Skip to content

Commit 8cb8bf9

Browse files
committed
More complicated way of tracking stack frame liveness
1 parent febc042 commit 8cb8bf9

File tree

1 file changed

+82
-29
lines changed

1 file changed

+82
-29
lines changed

llvm/lib/Transforms/Tapir/OpenCilkABI.cpp

Lines changed: 82 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,48 +1179,101 @@ OpenCilkABI::getLoopOutlineProcessor(const TapirLoopInfo *TL) {
11791179
return nullptr;
11801180
}
11811181

1182+
// Return the stack frame for this function if it is definitely
1183+
// initialized. Otherwise return null.
1184+
// The lookup call must be dominated by a call to enter frame.
1185+
// The lookup call must not be reachable by any call to leave
1186+
// frame unless there is an intervening enter frame.
1187+
// This function will conservatively return null in some cases
1188+
// it does not understand. Most likely to matter, if a basic
1189+
// block contains a leave frame call followed by an enter frame
1190+
// call it will be treated as leaving the frame invalid.
1191+
11821192
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) {
1193+
BasicBlock *FrameBlock = FrameCall->getParent();
1194+
Function *F = FrameBlock->getParent();
1195+
Value *Frame = DetachCtxToStackFrame.lookup(F);
1196+
if (!Frame)
1197+
return nullptr;
1198+
1199+
// Blocks with enter frame calls.
1200+
SmallPtrSet<BasicBlock *, 8> EnterBlocks;
1201+
// The last enter or leave frame call before FrameCall
1202+
// in the same basic block.
1203+
CallBase *SameBlockCall = nullptr;
1204+
// True if the call is enter, false if leave or not yet set.
1205+
bool SameBlockEnter = false;
1206+
// Leave frame calls other than those before FrameCall
1207+
// in the same basic block.
1208+
SmallPtrSet<CallBase *, 8> Leaves;
1209+
1210+
// Use pointer identity to check call target. Enter and leave
1211+
// are always called with a known getCalledFunction().
1212+
// This function runs before inlining of runtime calls.
1213+
Value *Enter1 = CILKRTS_FUNC(enter_frame_helper).getCallee();
1214+
Value *Enter2 = CILKRTS_FUNC(enter_frame).getCallee();
1215+
Value *Leave1 = CILKRTS_FUNC(leave_frame_helper).getCallee();
1216+
Value *Leave2 = CILKRTS_FUNC(leave_frame).getCallee();
1217+
Value *Leave3 = CilkHelperEpilogue.getCallee();
1218+
Value *Leave4 = CilkParentEpilogue.getCallee();
1219+
1220+
// Collect all enter_frame and leave_frame calls.
1221+
bool Initialized = false;
1222+
for (User *U : Frame->users()) {
1223+
if (CallBase *C = dyn_cast<CallBase>(U)) {
1224+
Function *Fn = C->getCalledFunction();
1225+
BasicBlock *Block = C->getParent();
1226+
if (Fn == Enter1 || Fn == Enter2) {
1227+
if (FrameBlock == Block && C->comesBefore(FrameCall)) {
1228+
if (!SameBlockCall || SameBlockCall->comesBefore(C)) {
1229+
SameBlockCall = C;
1230+
SameBlockEnter = true;
1231+
}
1232+
Initialized = true;
1233+
} else {
1234+
EnterBlocks.insert(Block);
12031235
if (!Initialized && DT.dominates(C, FrameCall))
12041236
Initialized = true;
1205-
continue;
12061237
}
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;
1238+
} else if (Fn == Leave1 || Fn == Leave2 || Fn == Leave3 || Fn == Leave4) {
1239+
if (Block == FrameBlock && C->comesBefore(FrameCall)) {
1240+
if (!SameBlockCall || SameBlockCall->comesBefore(C)) {
1241+
SameBlockCall = C;
1242+
SameBlockEnter = false;
1243+
}
1244+
} else {
1245+
Leaves.insert(C);
12121246
}
12131247
}
12141248
}
1215-
if (Initialized)
1216-
return Frame;
12171249
}
1218-
return Constant::getNullValue(FrameCall->getType());
1250+
if (!Initialized)
1251+
return nullptr;
1252+
1253+
// Is the answer found in the same basic block?
1254+
if (SameBlockCall)
1255+
return SameBlockEnter ? Frame : nullptr;
1256+
1257+
// Ignore any enter frame call in a block that also contains
1258+
// a leave frame call.
1259+
for (CallBase *L : Leaves) {
1260+
EnterBlocks.erase(L->getParent());
1261+
}
1262+
1263+
// Look for leave frame calls that might reach the use without
1264+
// an intervening enter frame call.
1265+
for (CallBase *L : Leaves) {
1266+
if (isPotentiallyReachable(L, FrameCall, &EnterBlocks, &DT, nullptr))
1267+
return nullptr;
1268+
}
1269+
return Frame;
12191270
}
12201271

12211272
void OpenCilkABI::lowerFrameCall(CallBase *FrameCall, DominatorTree &DT) {
12221273
assert(FrameCall->data_operands_size() == 0);
12231274
Value *Frame = getValidFrame(FrameCall, DT);
1275+
if (Frame == nullptr)
1276+
Frame = Constant::getNullValue(FrameCall->getType());
12241277
FrameCall->replaceAllUsesWith(Frame);
12251278
FrameCall->eraseFromParent();
12261279
}

0 commit comments

Comments
 (0)