diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index accc62eb6c0..7582017a0f0 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -214,6 +214,14 @@ public: /// block when its address is taken. This cannot be its normal LBB label /// because the block may be accessed outside its containing function. MCSymbol *getAddrLabelSymbol(const BasicBlock *BB); + + /// takeDeletedSymbolsForFunction - If the specified function has had any + /// references to address-taken blocks generated, but the block got deleted, + /// return the symbol now so we can emit it. This prevents emitting a + /// reference to a symbol that has no definition. + void takeDeletedSymbolsForFunction(const Function *F, + std::vector &Result); + //===- EH ---------------------------------------------------------------===// diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 63b05365d1c..fe78b23debd 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -307,6 +307,16 @@ void AsmPrinter::EmitFunctionHeader() { // do their wild and crazy things as required. EmitFunctionEntryLabel(); + // If the function had address-taken blocks that got deleted, then we have + // references to the dangling symbols. Emit them at the start of the function + // so that we don't get references to undefined symbols. + std::vector DeadBlockSyms; + MMI->takeDeletedSymbolsForFunction(F, DeadBlockSyms); + for (unsigned i = 0, e = DeadBlockSyms.size(); i != e; ++i) { + OutStreamer.AddComment("Address taken block that was later removed"); + OutStreamer.EmitLabel(DeadBlockSyms[i]); + } + // Add some workaround for linkonce linkage on Cygwin\MinGW. if (MAI->getLinkOnceDirective() != 0 && (F->hasLinkOnceLinkage() || F->hasWeakLinkage())) diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 72a9450dcb4..b18e34c0d8d 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -52,18 +52,35 @@ public: class MMIAddrLabelMap { MCContext &Context; struct AddrLabelSymEntry { - MCSymbol *Sym; - unsigned Index; + MCSymbol *Sym; // The symbol for the label. + Function *Fn; // The containing function of the BasicBlock. + unsigned Index; // The index in BBCallbacks for the BasicBlock. }; DenseMap, AddrLabelSymEntry> AddrLabelSymbols; + /// BBCallbacks - Callbacks for the BasicBlock's that we have entries for. We + /// use this so we get notified if a block is deleted or RAUWd. std::vector BBCallbacks; + + /// DeletedAddrLabelsNeedingEmission - This is a per-function list of symbols + /// whose corresponding BasicBlock got deleted. These symbols need to be + /// emitted at some point in the file, so AsmPrinter emits them after the + /// function body. + DenseMap, std::vector > + DeletedAddrLabelsNeedingEmission; public: MMIAddrLabelMap(MCContext &context) : Context(context) {} + ~MMIAddrLabelMap() { + assert(DeletedAddrLabelsNeedingEmission.empty() && + "Some labels for deleted blocks never got emitted"); + } MCSymbol *getAddrLabelSymbol(BasicBlock *BB); + void takeDeletedSymbolsForFunction(Function *F, + std::vector &Result); + void UpdateForDeletedBlock(BasicBlock *BB); void UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New); }; @@ -75,16 +92,36 @@ MCSymbol *MMIAddrLabelMap::getAddrLabelSymbol(BasicBlock *BB) { AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; // If we already had an entry for this block, just return it. - if (Entry.Sym) return Entry.Sym; + if (Entry.Sym) { + assert(BB->getParent() == Entry.Fn && "Parent changed"); + return Entry.Sym; + } // Otherwise, this is a new entry, create a new symbol for it and add an // entry to BBCallbacks so we can be notified if the BB is deleted or RAUWd. BBCallbacks.push_back(BB); BBCallbacks.back().setMap(this); Entry.Index = BBCallbacks.size()-1; + Entry.Fn = BB->getParent(); return Entry.Sym = Context.CreateTempSymbol(); } +/// takeDeletedSymbolsForFunction - If we have any deleted symbols for F, return +/// them. +void MMIAddrLabelMap:: +takeDeletedSymbolsForFunction(Function *F, std::vector &Result) { + DenseMap, std::vector >::iterator I = + DeletedAddrLabelsNeedingEmission.find(F); + + // If there are no entries for the function, just return. + if (I == DeletedAddrLabelsNeedingEmission.end()) return; + + // Otherwise, take the list. + std::swap(Result, I->second); + DeletedAddrLabelsNeedingEmission.erase(I); +} + + void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { // If the block got deleted, there is no need for the symbol. If the symbol // was already emitted, we can just forget about it, otherwise we need to @@ -98,9 +135,13 @@ void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { return; // If the block is not yet defined, we need to emit it at the end of the - // function. - assert(0 && "Case not handled yet!"); - abort(); + // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list for + // the containing Function. Since the block is being deleted, its parent may + // already be removed, we have to get the function from 'Entry'. + assert((BB->getParent() == 0 || BB->getParent() == Entry.Fn) && + "Block/parent mismatch"); + + DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Entry.Sym); } void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { @@ -219,6 +260,18 @@ MCSymbol *MachineModuleInfo::getAddrLabelSymbol(const BasicBlock *BB) { return AddrLabelSymbols->getAddrLabelSymbol(const_cast(BB)); } +/// takeDeletedSymbolsForFunction - If the specified function has had any +/// references to address-taken blocks generated, but the block got deleted, +/// return the symbol now so we can emit it. This prevents emitting a +/// reference to a symbol that has no definition. +void MachineModuleInfo:: +takeDeletedSymbolsForFunction(const Function *F, + std::vector &Result) { + // If no blocks have had their addresses taken, we're done. + if (AddrLabelSymbols == 0) return; + return AddrLabelSymbols-> + takeDeletedSymbolsForFunction(const_cast(F), Result); +} //===- EH -----------------------------------------------------------------===// diff --git a/test/CodeGen/Generic/addr-label.ll b/test/CodeGen/Generic/addr-label.ll new file mode 100644 index 00000000000..49f3cbfe7c7 --- /dev/null +++ b/test/CodeGen/Generic/addr-label.ll @@ -0,0 +1,39 @@ +; RUN: llc %s -o - + +;; Reference to a label that gets deleted. +define i8* @test1() nounwind { +entry: + ret i8* blockaddress(@test1b, %test_label) +} + +define i32 @test1b() nounwind { +entry: + ret i32 -1 +test_label: + br label %ret +ret: + ret i32 -1 +} + + +;; Issues with referring to a label that gets RAUW'd later. +define i32 @test2a() nounwind { +entry: + %target = bitcast i8* blockaddress(@test2b, %test_label) to i8* + + call i32 @test2b(i8* %target) + + ret i32 0 +} + +define i32 @test2b(i8* %target) nounwind { +entry: + indirectbr i8* %target, [label %test_label] + +test_label: +; assume some code here... + br label %ret + +ret: + ret i32 -1 +} diff --git a/test/CodeGen/X86/crash.ll b/test/CodeGen/X86/crash.ll index 8ce9e6c2489..4b7c8509938 100644 --- a/test/CodeGen/X86/crash.ll +++ b/test/CodeGen/X86/crash.ll @@ -92,26 +92,3 @@ foo: } -;; Issues with referring to a label that gets RAUW'd later. -define i32 @test6a() nounwind { -entry: - %target = bitcast i8* blockaddress(@test6b, %test_label) to i8* - - call i32 @test6b(i8* %target) - - ret i32 0 -} - -define i32 @test6b(i8* %target) nounwind { -entry: - indirectbr i8* %target, [label %test_label] - -test_label: -; assume some code here... - br label %ret - -ret: - ret i32 -1 -} - -