Skip to content

Commit 191895d

Browse files
committed
New builtin and intrinsic to get pointer to OpenCilk stack frame
1 parent fd69c32 commit 191895d

File tree

10 files changed

+135
-21
lines changed

10 files changed

+135
-21
lines changed

clang/include/clang/Basic/Builtins.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,8 @@ LANGBUILTIN(__arithmetic_fence, "v.", "tE", ALL_LANGUAGES)
18001800
// and needs a builtin to carry the information to codegen.
18011801
BUILTIN(__hyper_lookup, "v*vC*z.", "nU")
18021802

1803+
BUILTIN(__tapir_frame, "v*", "n")
1804+
18031805
#undef BUILTIN
18041806
#undef LIBBUILTIN
18051807
#undef LANGBUILTIN

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5990,6 +5990,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
59905990
Str.getPointer(), Zeros);
59915991
return RValue::get(Ptr);
59925992
}
5993+
case Builtin::BI__tapir_frame: {
5994+
Function *FF = CGM.getIntrinsic(Intrinsic::tapir_frame);
5995+
return RValue::get(Builder.CreateCall(FF, {}));
5996+
}
59935997
case Builtin::BI__hyper_lookup: {
59945998
llvm::Value *Size = EmitScalarExpr(E->getArg(1));
59955999
Function *F = CGM.getIntrinsic(Intrinsic::hyper_lookup, Size->getType());

clang/test/Cilk/tapir-frame.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// 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
2+
// expected-no-diagnostics
3+
4+
// CHECK-LABEL: zero
5+
int zero()
6+
{
7+
return __tapir_frame() != 0;
8+
// CHECK: ret i32 0
9+
}
10+
11+
// CHECK-LABEL: one
12+
int one()
13+
{
14+
extern void f(int);
15+
_Cilk_spawn f(0);
16+
_Cilk_spawn f(1);
17+
// CHECK: ret i32 1
18+
return __tapir_frame() != 0;
19+
}
20+
21+
// CHECK-LABEL: function3
22+
int function3()
23+
{
24+
extern void f(int);
25+
extern int g(void *);
26+
_Cilk_spawn f(0);
27+
// CHECK: call i32 @g(ptr noundef nonnull %__cilkrts_sf)
28+
return g(__tapir_frame());
29+
}

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,10 @@ def int_tapir_loop_grainsize
17671767
: Intrinsic<[llvm_anyint_ty], [LLVMMatchType<0>],
17681768
[IntrNoMem, IntrWillReturn, IntrSpeculatable]>;
17691769

1770+
// Return the stack_frame in an OpenCilk function, otherwise null.
1771+
def int_tapir_frame
1772+
: Intrinsic<[llvm_ptr_ty], [], [IntrWillReturn,IntrReadInaccessibleMemOnly]>;
1773+
17701774
// Intrinsic to get the frame address of a spawned task. Tapir
17711775
// lowering transforms this intrinsic into ordinary frameaddress
17721776
// intrinsics.

llvm/include/llvm/Transforms/Tapir/LoweringUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ class TapirTarget {
244244
/// Lower a Tapir sync instruction \p SI.
245245
virtual void lowerSync(SyncInst &SI) = 0;
246246

247+
virtual void lowerFrameCall(CallBase *Call, DominatorTree &DT) {}
248+
247249
virtual void lowerReducerOperation(CallBase *Call) {}
248250

249251
/// Lower calls to the tapir.runtime.{start,end} intrinsics. Only

llvm/include/llvm/Transforms/Tapir/OpenCilkABI.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ class OpenCilkABI final : public TapirTarget {
157157

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

160+
Value *getValidFrame(CallBase *FrameCall, DominatorTree &DT);
161+
160162
public:
161163
OpenCilkABI(Module &M);
162164
~OpenCilkABI() { DetachCtxToStackFrame.clear(); }
@@ -167,6 +169,7 @@ class OpenCilkABI final : public TapirTarget {
167169
Value *lowerGrainsizeCall(CallInst *GrainsizeCall) override final;
168170
void lowerSync(SyncInst &SI) override final;
169171
void lowerReducerOperation(CallBase *CI) override;
172+
void lowerFrameCall(CallBase *CI, DominatorTree &DT) override;
170173

171174
ArgStructMode getArgStructMode() const override final {
172175
return ArgStructMode::None;

llvm/lib/CodeGen/IntrinsicLowering.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
236236
report_fatal_error("Code generator does not support intrinsic function '"+
237237
Callee->getName()+"'!");
238238

239+
case Intrinsic::tapir_frame:
240+
CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));
241+
break;
242+
239243
case Intrinsic::expect: {
240244
// Just replace __builtin_expect(exp, c) with EXP.
241245
Value *V = CI->getArgOperand(0);

llvm/lib/Transforms/Tapir/LoweringUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,7 @@ bool TapirTarget::shouldProcessFunction(const Function &F) const {
12481248
case Intrinsic::reducer_unregister:
12491249
case Intrinsic::tapir_loop_grainsize:
12501250
case Intrinsic::task_frameaddress:
1251+
case Intrinsic::tapir_frame:
12511252
case Intrinsic::tapir_runtime_start:
12521253
case Intrinsic::tapir_runtime_end:
12531254
return true;

llvm/lib/Transforms/Tapir/OpenCilkABI.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/ADT/Statistic.h"
1717
#include "llvm/ADT/StringSet.h"
1818
#include "llvm/Analysis/AssumptionCache.h"
19+
#include "llvm/Analysis/CFG.h"
1920
#include "llvm/Analysis/TapirTaskInfo.h"
2021
#include "llvm/IR/Constants.h"
2122
#include "llvm/IR/DebugInfo.h"
@@ -1178,6 +1179,53 @@ OpenCilkABI::getLoopOutlineProcessor(const TapirLoopInfo *TL) {
11781179
return nullptr;
11791180
}
11801181

1182+
Value *OpenCilkABI::getValidFrame(CallBase *FrameCall, DominatorTree &DT) {
1183+
Function *F = FrameCall->getFunction();
1184+
if (Value *Frame = DetachCtxToStackFrame.lookup(F)) {
1185+
// Make sure a call to enter_frame dominates this get_frame call
1186+
// and no call to leave_frame has potentially been executed.
1187+
// Otherwise return a null pointer value to mean unknown.
1188+
// This is correct in most functions and conservative in
1189+
// complicated functions.
1190+
bool Initialized = false;
1191+
Value *Enter1 = CILKRTS_FUNC(enter_frame_helper).getCallee();
1192+
Value *Enter2 = CILKRTS_FUNC(enter_frame).getCallee();
1193+
Value *Leave1 = CILKRTS_FUNC(leave_frame_helper).getCallee();
1194+
Value *Leave2 = CILKRTS_FUNC(leave_frame).getCallee();
1195+
Value *Leave3 = CilkHelperEpilogue.getCallee();
1196+
Value *Leave4 = CilkParentEpilogue.getCallee();
1197+
for (User *U : Frame->users()) {
1198+
if (CallBase *C = dyn_cast<CallBase>(U)) {
1199+
Function *Fn = C->getCalledFunction();
1200+
if (Fn == nullptr) // indirect function call
1201+
continue;
1202+
if (Fn == Enter1 || Fn == Enter2) {
1203+
if (!Initialized && DT.dominates(C, FrameCall))
1204+
Initialized = true;
1205+
continue;
1206+
}
1207+
if (Fn == Leave1 || Fn == Leave2 | Fn == Leave3 | Fn == Leave4) {
1208+
// TODO: ...unless an enter_frame call definitely intervenes.
1209+
if (isPotentiallyReachable(C, FrameCall, nullptr, &DT, nullptr))
1210+
return Constant::getNullValue(FrameCall->getType());
1211+
continue;
1212+
}
1213+
}
1214+
}
1215+
if (Initialized)
1216+
return Frame;
1217+
}
1218+
return Constant::getNullValue(FrameCall->getType());
1219+
}
1220+
1221+
void OpenCilkABI::lowerFrameCall(CallBase *FrameCall, DominatorTree &DT) {
1222+
assert(FrameCall->data_operands_size() == 0);
1223+
Value *Frame = getValidFrame(FrameCall, DT);
1224+
FrameCall->replaceAllUsesWith(Frame);
1225+
FrameCall->eraseFromParent();
1226+
}
1227+
1228+
11811229
void OpenCilkABI::lowerReducerOperation(CallBase *CI) {
11821230
FunctionCallee Fn = nullptr;
11831231
const Function *Called = CI->getCalledFunction();

llvm/lib/Transforms/Tapir/TapirToTarget.cpp

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -180,42 +180,59 @@ bool TapirToTargetImpl::processSimpleABI(Function &F, BasicBlock *TFEntry) {
180180
SmallVector<CallInst *, 8> TaskFrameAddrCalls;
181181
SmallVector<CallInst *, 8> TapirRTCalls;
182182
SmallVector<CallBase *, 8> ReducerOperations;
183+
SmallVector<CallInst *, 8> TapirFrameCalls;
184+
183185
for (BasicBlock &BB : F) {
184186
for (Instruction &I : BB) {
185-
// Record calls to get Tapir-loop grainsizes.
186-
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
187-
if (Intrinsic::tapir_loop_grainsize == II->getIntrinsicID())
187+
188+
// Record sync instructions in this function.
189+
if (SyncInst *SI = dyn_cast<SyncInst>(&I)) {
190+
Syncs.push_back(SI);
191+
continue;
192+
}
193+
194+
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I)) {
195+
switch (II->getIntrinsicID()) {
196+
case Intrinsic::tapir_loop_grainsize:
188197
GrainsizeCalls.push_back(II);
198+
break;
189199

190-
// Record calls to task_frameaddr intrinsics.
191-
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
192-
if (Intrinsic::task_frameaddress == II->getIntrinsicID())
200+
case Intrinsic::task_frameaddress:
193201
TaskFrameAddrCalls.push_back(II);
202+
break;
194203

195-
// Record calls to tapir_runtime_start intrinsics. We rely on analyzing
196-
// uses of these intrinsic calls to find calls to tapir_runtime_end.
197-
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I))
198-
if (Intrinsic::tapir_runtime_start == II->getIntrinsicID())
204+
// Record calls to tapir_runtime_start intrinsics.
205+
// We rely on analyzing uses of these intrinsic calls
206+
// to find calls to tapir_runtime_end.
207+
case Intrinsic::tapir_runtime_start:
199208
TapirRTCalls.push_back(II);
200-
201-
// Record sync instructions in this function.
202-
if (SyncInst *SI = dyn_cast<SyncInst>(&I))
203-
Syncs.push_back(SI);
204-
205-
if (!dyn_cast<CallBase>(&I))
209+
break;
210+
211+
case Intrinsic::tapir_frame:
212+
TapirFrameCalls.push_back(II);
213+
break;
214+
215+
case Intrinsic::hyper_lookup:
216+
case Intrinsic::reducer_register:
217+
case Intrinsic::reducer_unregister:
218+
ReducerOperations.push_back(cast<CallInst>(&I));
219+
break;
220+
}
206221
continue;
207-
208-
if (isTapirIntrinsic(Intrinsic::hyper_lookup, &I, nullptr) ||
209-
isTapirIntrinsic(Intrinsic::reducer_register, &I, nullptr) ||
210-
isTapirIntrinsic(Intrinsic::reducer_unregister, &I, nullptr))
211-
ReducerOperations.push_back(cast<CallInst>(&I));
222+
}
212223
}
213224
}
214225

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

230+
while (!TapirFrameCalls.empty()) {
231+
CallInst *CI = TapirFrameCalls.pop_back_val();
232+
Target->lowerFrameCall(CI, GetDT(F));
233+
Changed = true;
234+
}
235+
219236
// Lower calls to get Tapir-loop grainsizes.
220237
while (!GrainsizeCalls.empty()) {
221238
CallInst *GrainsizeCall = GrainsizeCalls.pop_back_val();

0 commit comments

Comments
 (0)