Skip to content

Commit

Permalink
New builtin and intrinsic to get pointer to OpenCilk stack frame
Browse files Browse the repository at this point in the history
  • Loading branch information
VoxSciurorum committed Nov 6, 2024
1 parent fd69c32 commit 191895d
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 21 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -1800,6 +1800,8 @@ LANGBUILTIN(__arithmetic_fence, "v.", "tE", ALL_LANGUAGES)
// and needs a builtin to carry the information to codegen.
BUILTIN(__hyper_lookup, "v*vC*z.", "nU")

BUILTIN(__tapir_frame, "v*", "n")

#undef BUILTIN
#undef LIBBUILTIN
#undef LANGBUILTIN
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5990,6 +5990,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Str.getPointer(), Zeros);
return RValue::get(Ptr);
}
case Builtin::BI__tapir_frame: {
Function *FF = CGM.getIntrinsic(Intrinsic::tapir_frame);
return RValue::get(Builder.CreateCall(FF, {}));
}
case Builtin::BI__hyper_lookup: {
llvm::Value *Size = EmitScalarExpr(E->getArg(1));
Function *F = CGM.getIntrinsic(Intrinsic::hyper_lookup, Size->getType());
Expand Down
29 changes: 29 additions & 0 deletions clang/test/Cilk/tapir-frame.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %clang_cc1 %s -x c -O1 -fopencilk -mllvm -use-opencilk-runtime-bc=false -mllvm -debug-abi-calls=true -verify -S -emit-llvm -o - | FileCheck %s
// expected-no-diagnostics

// CHECK-LABEL: zero
int zero()
{
return __tapir_frame() != 0;
// CHECK: ret i32 0
}

// CHECK-LABEL: one
int one()
{
extern void f(int);
_Cilk_spawn f(0);
_Cilk_spawn f(1);
// CHECK: ret i32 1
return __tapir_frame() != 0;
}

// CHECK-LABEL: function3
int function3()
{
extern void f(int);
extern int g(void *);
_Cilk_spawn f(0);
// CHECK: call i32 @g(ptr noundef nonnull %__cilkrts_sf)
return g(__tapir_frame());
}
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,10 @@ def int_tapir_loop_grainsize
: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>],
[IntrNoMem, IntrWillReturn, IntrSpeculatable]>;

// Return the stack_frame in an OpenCilk function, otherwise null.
def int_tapir_frame
: Intrinsic<[llvm_ptr_ty], [], [IntrWillReturn,IntrReadInaccessibleMemOnly]>;

// Intrinsic to get the frame address of a spawned task. Tapir
// lowering transforms this intrinsic into ordinary frameaddress
// intrinsics.
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Transforms/Tapir/LoweringUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ class TapirTarget {
/// Lower a Tapir sync instruction \p SI.
virtual void lowerSync(SyncInst &SI) = 0;

virtual void lowerFrameCall(CallBase *Call, DominatorTree &DT) {}

virtual void lowerReducerOperation(CallBase *Call) {}

/// Lower calls to the tapir.runtime.{start,end} intrinsics. Only
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Transforms/Tapir/OpenCilkABI.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ class OpenCilkABI final : public TapirTarget {

BasicBlock *GetDefaultSyncLandingpad(Function &F, Value *SF, DebugLoc Loc);

Value *getValidFrame(CallBase *FrameCall, DominatorTree &DT);

public:
OpenCilkABI(Module &M);
~OpenCilkABI() { DetachCtxToStackFrame.clear(); }
Expand All @@ -167,6 +169,7 @@ class OpenCilkABI final : public TapirTarget {
Value *lowerGrainsizeCall(CallInst *GrainsizeCall) override final;
void lowerSync(SyncInst &SI) override final;
void lowerReducerOperation(CallBase *CI) override;
void lowerFrameCall(CallBase *CI, DominatorTree &DT) override;

ArgStructMode getArgStructMode() const override final {
return ArgStructMode::None;
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/IntrinsicLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
report_fatal_error("Code generator does not support intrinsic function '"+
Callee->getName()+"'!");

case Intrinsic::tapir_frame:
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
break;

case Intrinsic::expect: {
// Just replace __builtin_expect(exp, c) with EXP.
Value *V = CI->getArgOperand(0);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Tapir/LoweringUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@ bool TapirTarget::shouldProcessFunction(const Function &F) const {
case Intrinsic::reducer_unregister:
case Intrinsic::tapir_loop_grainsize:
case Intrinsic::task_frameaddress:
case Intrinsic::tapir_frame:
case Intrinsic::tapir_runtime_start:
case Intrinsic::tapir_runtime_end:
return true;
Expand Down
48 changes: 48 additions & 0 deletions llvm/lib/Transforms/Tapir/OpenCilkABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/TapirTaskInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfo.h"
Expand Down Expand Up @@ -1178,6 +1179,53 @@ OpenCilkABI::getLoopOutlineProcessor(const TapirLoopInfo *TL) {
return nullptr;
}

Value *OpenCilkABI::getValidFrame(CallBase *FrameCall, DominatorTree &DT) {
Function *F = FrameCall->getFunction();
if (Value *Frame = DetachCtxToStackFrame.lookup(F)) {
// Make sure a call to enter_frame dominates this get_frame call
// and no call to leave_frame has potentially been executed.
// Otherwise return a null pointer value to mean unknown.
// This is correct in most functions and conservative in
// complicated functions.
bool Initialized = false;
Value *Enter1 = CILKRTS_FUNC(enter_frame_helper).getCallee();
Value *Enter2 = CILKRTS_FUNC(enter_frame).getCallee();
Value *Leave1 = CILKRTS_FUNC(leave_frame_helper).getCallee();
Value *Leave2 = CILKRTS_FUNC(leave_frame).getCallee();
Value *Leave3 = CilkHelperEpilogue.getCallee();
Value *Leave4 = CilkParentEpilogue.getCallee();
for (User *U : Frame->users()) {
if (CallBase *C = dyn_cast<CallBase>(U)) {
Function *Fn = C->getCalledFunction();
if (Fn == nullptr) // indirect function call
continue;
if (Fn == Enter1 || Fn == Enter2) {
if (!Initialized && DT.dominates(C, FrameCall))
Initialized = true;
continue;
}
if (Fn == Leave1 || Fn == Leave2 | Fn == Leave3 | Fn == Leave4) {
// TODO: ...unless an enter_frame call definitely intervenes.
if (isPotentiallyReachable(C, FrameCall, nullptr, &DT, nullptr))
return Constant::getNullValue(FrameCall->getType());
continue;
}
}
}
if (Initialized)
return Frame;
}
return Constant::getNullValue(FrameCall->getType());
}

void OpenCilkABI::lowerFrameCall(CallBase *FrameCall, DominatorTree &DT) {
assert(FrameCall->data_operands_size() == 0);
Value *Frame = getValidFrame(FrameCall, DT);
FrameCall->replaceAllUsesWith(Frame);
FrameCall->eraseFromParent();
}


void OpenCilkABI::lowerReducerOperation(CallBase *CI) {
FunctionCallee Fn = nullptr;
const Function *Called = CI->getCalledFunction();
Expand Down
59 changes: 38 additions & 21 deletions llvm/lib/Transforms/Tapir/TapirToTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,42 +180,59 @@ bool TapirToTargetImpl::processSimpleABI(Function &F, BasicBlock *TFEntry) {
SmallVector<CallInst *, 8> TaskFrameAddrCalls;
SmallVector<CallInst *, 8> TapirRTCalls;
SmallVector<CallBase *, 8> ReducerOperations;
SmallVector<CallInst *, 8> TapirFrameCalls;

for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
// Record calls to get Tapir-loop grainsizes.
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
if (Intrinsic::tapir_loop_grainsize == II->getIntrinsicID())

// Record sync instructions in this function.
if (SyncInst *SI = dyn_cast<SyncInst>(&I)) {
Syncs.push_back(SI);
continue;
}

if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I)) {
switch (II->getIntrinsicID()) {
case Intrinsic::tapir_loop_grainsize:
GrainsizeCalls.push_back(II);
break;

// Record calls to task_frameaddr intrinsics.
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
if (Intrinsic::task_frameaddress == II->getIntrinsicID())
case Intrinsic::task_frameaddress:
TaskFrameAddrCalls.push_back(II);
break;

// Record calls to tapir_runtime_start intrinsics. We rely on analyzing
// uses of these intrinsic calls to find calls to tapir_runtime_end.
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
if (Intrinsic::tapir_runtime_start == II->getIntrinsicID())
// Record calls to tapir_runtime_start intrinsics.
// We rely on analyzing uses of these intrinsic calls
// to find calls to tapir_runtime_end.
case Intrinsic::tapir_runtime_start:
TapirRTCalls.push_back(II);

// Record sync instructions in this function.
if (SyncInst *SI = dyn_cast<SyncInst>(&I))
Syncs.push_back(SI);

if (!dyn_cast<CallBase>(&I))
break;

case Intrinsic::tapir_frame:
TapirFrameCalls.push_back(II);
break;

case Intrinsic::hyper_lookup:
case Intrinsic::reducer_register:
case Intrinsic::reducer_unregister:
ReducerOperations.push_back(cast<CallInst>(&I));
break;
}
continue;

if (isTapirIntrinsic(Intrinsic::hyper_lookup, &I, nullptr) ||
isTapirIntrinsic(Intrinsic::reducer_register, &I, nullptr) ||
isTapirIntrinsic(Intrinsic::reducer_unregister, &I, nullptr))
ReducerOperations.push_back(cast<CallInst>(&I));
}
}
}

// Lower simple Tapir instructions in this function. Collect the set of
// helper functions generated by this process.
bool Changed = false;

while (!TapirFrameCalls.empty()) {
CallInst *CI = TapirFrameCalls.pop_back_val();
Target->lowerFrameCall(CI, GetDT(F));
Changed = true;
}

// Lower calls to get Tapir-loop grainsizes.
while (!GrainsizeCalls.empty()) {
CallInst *GrainsizeCall = GrainsizeCalls.pop_back_val();
Expand Down

0 comments on commit 191895d

Please sign in to comment.