@@ -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+
11821192Value *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
12211272void 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