From 36a2ada69fdb457b0e46d0ef452c150b360d8888 Mon Sep 17 00:00:00 2001 From: Mike Stump Date: Sat, 7 Feb 2009 12:52:26 +0000 Subject: [PATCH] Fixup goto codegen in and around VLAs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64014 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDecl.cpp | 2 +- lib/CodeGen/CGObjC.cpp | 3 +- lib/CodeGen/CGStmt.cpp | 84 +++++++++++++++++++++++++-------- lib/CodeGen/CodeGenFunction.cpp | 2 +- lib/CodeGen/CodeGenFunction.h | 37 +++++++++++++-- 5 files changed, 100 insertions(+), 28 deletions(-) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 73d3e2103c..3162c2f480 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -188,7 +188,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Builder.CreateStore(V, Stack); - StackSaveValues.back() = Stack; + StackSaveValues.back() = StackDepth = Stack; } // Get the element type. const llvm::Type *LElemTy = ConvertType(Ty); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 0cb5c7ab4d..d62cfdc306 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -515,8 +515,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S) llvm::BasicBlock *LoopEnd = createBasicBlock("loopend"); llvm::BasicBlock *AfterBody = createBasicBlock("afterbody"); - BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody, - ObjCEHStack.size())); + BreakContinuePush(LoopEnd, AfterBody); EmitStmt(S.getBody()); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 939ebec01e..42512d1847 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -164,6 +164,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, } if (llvm::Value *V = StackSaveValues.pop_back_val()) { + StackDepth = V; V = Builder.CreateLoad(V, "tmp"); llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore); @@ -186,6 +187,41 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { Builder.SetInsertPoint(BB); } +void CodeGenFunction::EmitStackUpdate(const LabelStmt &S) { + if (StackDepthMap.find(&S) == StackDepthMap.end()) { + // If we can't find it, just remember the depth now, + // so we can validate it later. + // FIXME: We need to save a place to insert the adjustment, + // if needed, here, sa that later in EmitLabel, we can + // backpatch the adjustment into that place, instead of + // saying unsupported. + StackDepthMap[&S] = StackDepth; + return; + } + + // Find applicable stack depth, if any... + llvm::Value *V = StackDepthMap[&S]; + // V can be 0 here, if it is, be sure to start searching from the + // top of the function, as we want the next save after that point. + for (unsigned int i = 0; i < StackSaveValues.size(); ++i) + if (StackSaveValues[i] == V) { + // The actual depth is actually in the next used slot, if any. + while (++i < StackSaveValues.size() + && (V = StackSaveValues[i]) == 0) ; + // If there were no other depth changes, we don't need any + // adjustments. + if (V) { + V = Builder.CreateLoad(V, "tmp"); + // and restore it. + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore); + Builder.CreateCall(F, V); + } + } else + // FIXME: Move to semq and assert here, codegen isn't the right + // time to be checking. + CGM.ErrorUnsupported(&S, "invalid goto to VLA scope that has finished"); +} + void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) { // Emit a branch from the current block to the target one if this // was a real block. If this was just a fall-through block after a @@ -205,6 +241,22 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) { void CodeGenFunction::EmitLabel(const LabelStmt &S) { llvm::BasicBlock *NextBB = getBasicBlockForLabel(&S); + if (StackDepthMap.find(&S) == StackDepthMap.end()) { + // We need to remember the stack depth so that we can readjust the + // stack back to the right depth for this label if we want to + // transfer here from a different depth. + StackDepthMap[&S] = StackDepth; + } else { + if (StackDepthMap[&S] != StackDepth) { + // FIXME: Sema needs to ckeck for jumps that cross decls with + // initializations for C++, and all VLAs, not just the first in + // a block that does a stacksave. + // FIXME: We need to save a place to insert the adjustment + // when we do a EmitStackUpdate on a forward jump, and then + // backpatch the adjustment into that place. + CGM.ErrorUnsupported(&S, "forward goto inside scope with VLA"); + } + } EmitBlock(NextBB); } @@ -221,18 +273,16 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { return; } - for (unsigned i = 0; i < StackSaveValues.size(); i++) { - if (StackSaveValues[i]) { - CGM.ErrorUnsupported(&S, "goto inside scope with VLA"); - return; - } - } - // If this code is reachable then emit a stop point (if generating // debug info). We have to do this ourselves because we are on the // "simple" statement path. if (HaveInsertPoint()) EmitStopPoint(&S); + + // We need to adjust the stack, if the destination was (will be) at + // a different depth. + EmitStackUpdate(*S.getLabel()); + EmitBranch(getBasicBlockForLabel(S.getLabel())); } @@ -330,14 +380,13 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); // Store the blocks to use for break and continue. - BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader, - ObjCEHStack.size())); + BreakContinuePush(ExitBlock, LoopHeader); // Emit the loop body. EmitBlock(LoopBody); EmitStmt(S.getBody()); - BreakContinueStack.pop_back(); + BreakContinuePop(); // Cycle to the condition. EmitBranch(LoopHeader); @@ -364,13 +413,12 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { llvm::BasicBlock *DoCond = createBasicBlock("do.cond"); // Store the blocks to use for break and continue. - BreakContinueStack.push_back(BreakContinue(AfterDo, DoCond, - ObjCEHStack.size())); + BreakContinuePush(AfterDo, DoCond); // Emit the body of the loop into the block. EmitStmt(S.getBody()); - BreakContinueStack.pop_back(); + BreakContinuePop(); EmitBlock(DoCond); @@ -443,13 +491,12 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { ContinueBlock = CondBlock; // Store the blocks to use for break and continue. - BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock, - ObjCEHStack.size())); + BreakContinuePush(AfterFor, ContinueBlock); // If the condition is true, execute the body of the for stmt. EmitStmt(S.getBody()); - BreakContinueStack.pop_back(); + BreakContinuePop(); // If there is an increment, emit it next. if (S.getInc()) { @@ -678,12 +725,11 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { llvm::BasicBlock *ContinueBlock = NULL; if (!BreakContinueStack.empty()) ContinueBlock = BreakContinueStack.back().ContinueBlock; - BreakContinueStack.push_back(BreakContinue(NextBlock, ContinueBlock, - ObjCEHStack.size())); + BreakContinuePush(NextBlock, ContinueBlock); // Emit switch body. EmitStmt(S.getBody()); - BreakContinueStack.pop_back(); + BreakContinuePop(); // Update the default block in case explicit case range tests have // been chained on top. diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 2b365c9cca..f5a802f0b7 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -24,7 +24,7 @@ using namespace CodeGen; CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : CGM(cgm), Target(CGM.getContext().Target), SwitchInsn(NULL), - CaseRangeBlock(NULL) { + CaseRangeBlock(NULL), StackDepth(0) { LLVMIntTy = ConvertType(getContext().IntTy); LLVMPointerWidth = Target.getPointerWidth(0); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index bf27d0acea..90b0bf45fe 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -144,21 +144,36 @@ private: /// until all AddrLabelExprs have been seen. std::vector IndirectSwitches; - /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C - /// decls. + /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local + /// C decls. llvm::DenseMap LocalDeclMap; /// LabelMap - This keeps track of the LLVM basic block for each C label. llvm::DenseMap LabelMap; + /// BreakContinuePush - Note a new break and continue level. + void BreakContinuePush(llvm::BasicBlock *bb, llvm::BasicBlock *cb) { + BreakContinueStack.push_back(BreakContinue(bb, cb, StackDepth, + ObjCEHStack.size())); + } + + /// BreakContinuePop - Note end of previous break and continue level. + void BreakContinuePop() { + BreakContinueStack.pop_back(); + } + // BreakContinueStack - This keeps track of where break and continue - // statements should jump to, as well as the size of the eh stack. + // statements should jump to, as well as the depth of the stack and the size + // of the eh stack. struct BreakContinue { - BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb, size_t ehss) - : BreakBlock(bb), ContinueBlock(cb), EHStackSize(ehss) {} + BreakContinue(llvm::BasicBlock *bb, llvm::BasicBlock *cb, + llvm::Value *sd, size_t ehss) + : BreakBlock(bb), ContinueBlock(cb), SaveStackDepth(sd), + EHStackSize(ehss) {} llvm::BasicBlock *BreakBlock; llvm::BasicBlock *ContinueBlock; + llvm::Value *SaveStackDepth; size_t EHStackSize; }; llvm::SmallVector BreakContinueStack; @@ -176,11 +191,23 @@ private: // we enter/leave scopes. llvm::DenseMap VLASizeMap; + /// StackDepth - This keeps track of the stack depth. It is used to + /// notice when control flow results in a change in stack depth and + /// to arrange for the appropriate stack depth to be restored. + llvm::Value *StackDepth; + /// StackSaveValues - A stack(!) of stack save values. When a new scope is /// entered, a null is pushed on this stack. If a VLA is emitted, then /// the return value of llvm.stacksave() is stored at the top of this stack. llvm::SmallVector StackSaveValues; + llvm::DenseMap StackDepthMap; + + /// EmitStackUpdate - Routine to adjust the stack to the depth the + /// stack should be at by the time we transfer control flow to the + /// label. + void EmitStackUpdate(const LabelStmt &S); + public: CodeGenFunction(CodeGenModule &cgm); -- 2.40.0