Ben Gamari
2014-May-26 00:41 UTC
[LLVMdev] [PATCH 2/2] Allow full constants in symbol_offsets
From: Ben Gamari <ben at ben-server> This generalized symbol offset support for allow constant offsets (Option 1 of the original proposal[1]). [1] http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/061511.html --- include/llvm/IR/Function.h | 32 +++++++++++++++---------- lib/AsmParser/LLParser.cpp | 4 ++-- lib/Bitcode/Reader/BitcodeReader.cpp | 19 +++++++++++++-- lib/Bitcode/Reader/BitcodeReader.h | 1 + lib/Bitcode/Writer/BitcodeWriter.cpp | 3 ++- lib/Bitcode/Writer/ValueEnumerator.cpp | 5 ++++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 10 ++++---- lib/IR/AsmWriter.cpp | 7 ++++-- lib/IR/Function.cpp | 43 +++++++++++++++++++++++++++------- lib/IR/LLVMContextImpl.h | 6 +++++ lib/IR/TypeFinder.cpp | 3 +++ lib/Transforms/IPO/GlobalDCE.cpp | 3 +++ test/Feature/symbol_offset.ll | 4 ++-- 13 files changed, 106 insertions(+), 34 deletions(-) diff --git a/include/llvm/IR/Function.h b/include/llvm/IR/Function.h index 0332e74..ab85c0d 100644 --- a/include/llvm/IR/Function.h +++ b/include/llvm/IR/Function.h @@ -86,13 +86,15 @@ private: mutable ArgumentListType ArgumentList; ///< The formal arguments ValueSymbolTable *SymTab; ///< Symbol table of args/instructions AttributeSet AttributeSets; ///< Parameter attributes - signed SymbolOffset; ///< Symbol offset - // HasLazyArguments is stored in Value::SubclassData. - /*bool HasLazyArguments;*/ - - // The Calling Convention is stored in Value::SubclassData. - /*CallingConv::ID CallingConvention;*/ + /* + * Value::SubclassData + * + * bit 0 : HasLazyArguments + * bit 1 : HasPrefixData + * bit 2 : HasSymbolOffset + * bit 3-6: CallingConvention + */ friend class SymbolTableListTraits<Function, Module>; @@ -103,7 +105,7 @@ private: /// needs it. The hasLazyArguments predicate returns true if the arg list /// hasn't been set up yet. bool hasLazyArguments() const { - return getSubclassDataFromValue() & 1; + return getSubclassDataFromValue() & (1<<0); } void CheckLazyArguments() const { if (hasLazyArguments()) @@ -160,11 +162,11 @@ public: /// calling convention of this function. The enum values for the known /// calling conventions are defined in CallingConv.h. CallingConv::ID getCallingConv() const { - return static_cast<CallingConv::ID>(getSubclassDataFromValue() >> 2); + return static_cast<CallingConv::ID>(getSubclassDataFromValue() >> 3); } void setCallingConv(CallingConv::ID CC) { - setValueSubclassData((getSubclassDataFromValue() & 3) | - (static_cast<unsigned>(CC) << 2)); + setValueSubclassData((getSubclassDataFromValue() & 7) | + (static_cast<unsigned>(CC) << 3)); } /// @brief Return the attribute list for this Function. @@ -440,14 +442,18 @@ public: bool arg_empty() const; bool hasPrefixData() const { - return getSubclassDataFromValue() & 2; + return getSubclassDataFromValue() & (1<<1); } Constant *getPrefixData() const; void setPrefixData(Constant *PrefixData); - signed getSymbolOffset() const; - void setSymbolOffset(signed Offset); + bool hasSymbolOffset() const { + return getSubclassDataFromValue() & (1<<2); + } + + Constant *getSymbolOffset() const; + void setSymbolOffset(Constant *Offset); /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 8988ffd..2b5c818 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -3110,7 +3110,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { bool UnnamedAddr; LocTy UnnamedAddrLoc; Constant *Prefix = nullptr; - signed Offset = 0; + Constant *Offset = nullptr; if (ParseArgumentList(ArgList, isVarArg) || ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr, @@ -3125,7 +3125,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { (EatIfPresent(lltok::kw_prefix) && ParseGlobalTypeAndValue(Prefix)) || (EatIfPresent(lltok::kw_symbol_offset) && - ParseInt32(Offset))) + ParseGlobalTypeAndValue(Offset))) return true; if (FuncAttrs.contains(Attribute::Builtin)) diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 904468d..a4cb051 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1122,10 +1122,12 @@ error_code BitcodeReader::ResolveGlobalAndAliasInits() { std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist; std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist; std::vector<std::pair<Function*, unsigned> > FunctionPrefixWorklist; + std::vector<std::pair<Function*, unsigned> > FunctionOffsetWorklist; GlobalInitWorklist.swap(GlobalInits); AliasInitWorklist.swap(AliasInits); FunctionPrefixWorklist.swap(FunctionPrefixes); + FunctionOffsetWorklist.swap(FunctionOffsets); while (!GlobalInitWorklist.empty()) { unsigned ValID = GlobalInitWorklist.back().second; @@ -1178,6 +1180,19 @@ error_code BitcodeReader::ResolveGlobalAndAliasInits() { FunctionPrefixWorklist.pop_back(); } + while (!FunctionOffsetWorklist.empty()) { + unsigned ValID = FunctionOffsetWorklist.back().second; + if (ValID >= ValueList.size()) { + FunctionOffsets.push_back(FunctionOffsetWorklist.back()); + } else { + if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID])) + FunctionOffsetWorklist.back().first->setSymbolOffset(C); + else + return Error(ExpectedConstant); + } + FunctionOffsetWorklist.pop_back(); + } + return error_code::success(); } @@ -1977,8 +1992,8 @@ error_code BitcodeReader::ParseModule(bool Resume) { Func->setUnnamedAddr(UnnamedAddr); if (Record.size() > 10 && Record[10] != 0) FunctionPrefixes.push_back(std::make_pair(Func, Record[10]-1)); - if (Record.size() > 11) - Func->setSymbolOffset(Record[11]); + if (Record.size() > 11 && Record[11] != 0) + FunctionOffsets.push_back(std::make_pair(Func, Record[11]-1)); if (Record.size() > 12) Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[12])); diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 593d8f9..d70f573 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -142,6 +142,7 @@ class BitcodeReader : public GVMaterializer { std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits; std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits; std::vector<std::pair<Function*, unsigned> > FunctionPrefixes; + std::vector<std::pair<Function*, unsigned> > FunctionOffsets; SmallVector<Instruction*, 64> InstsWithTBAATag; diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 151a4fa..e1d8838 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -655,7 +655,8 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, Vals.push_back(F->hasUnnamedAddr()); Vals.push_back(F->hasPrefixData() ? (VE.getValueID(F->getPrefixData()) + 1) : 0); - Vals.push_back(F->getSymbolOffset()); + Vals.push_back(F->hasSymbolOffset() ? (VE.getValueID(F->getSymbolOffset()) + 1) + : 0); Vals.push_back(getEncodedDLLStorageClass(F)); unsigned AbbrevToUse = 0; diff --git a/lib/Bitcode/Writer/ValueEnumerator.cpp b/lib/Bitcode/Writer/ValueEnumerator.cpp index 8531e76..c851e9c 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -65,6 +65,11 @@ ValueEnumerator::ValueEnumerator(const Module *M) { if (I->hasPrefixData()) EnumerateValue(I->getPrefixData()); + // Enumerate the symbol offset constants. + for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) + if (I->hasSymbolOffset()) + EnumerateValue(I->getSymbolOffset()); + // Insert constants and metadata that are named at module level into the slot // pool so that the module symbol table can refer to them... EnumerateValueSymbolTable(M->getValueSymbolTable()); diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index eed1b3b..99df7a0 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -63,6 +63,8 @@ STATISTIC(EmittedInsts, "Number of machine instrs printed"); char AsmPrinter::ID = 0; +static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP); + typedef DenseMap<GCStrategy*, std::unique_ptr<GCMetadataPrinter>> gcp_map_type; static gcp_map_type &getGCMap(void *&P) { if (!P) @@ -561,14 +563,14 @@ void AsmPrinter::EmitFunctionEntryLabel() { // The function label could have already been emitted if two symbols end up // conflicting due to asm renaming. Detect this and emit an error. if (CurrentFnSym->isUndefined()) { - if (F->getSymbolOffset() != 0) { + if (F->hasSymbolOffset()) { MCSymbol *dummySym = OutContext.CreateTempSymbol(); OutStreamer.EmitLabel(dummySym); const MCExpr *symRefExpr = MCSymbolRefExpr::Create(dummySym, OutContext); - const MCExpr *constExpr = MCConstantExpr::Create(F->getSymbolOffset(), OutContext); - const MCExpr *addExpr = MCBinaryExpr::CreateAdd(symRefExpr, constExpr, OutContext); - OutStreamer.EmitAssignment(CurrentFnSym, addExpr); + const MCExpr *offsetExpr = lowerConstant(F->getSymbolOffset(), *this); + const MCExpr *sumExpr = MCBinaryExpr::CreateAdd(symRefExpr, offsetExpr, OutContext); + OutStreamer.EmitAssignment(CurrentFnSym, sumExpr); return; } else { return OutStreamer.EmitLabel(CurrentFnSym); diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index 9d39e4c..bd1631f 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -1657,8 +1657,11 @@ void AssemblyWriter::printFunction(const Function *F) { Out << " prefix "; writeOperand(F->getPrefixData(), true); } - if (F->getSymbolOffset() != 0) - Out << " symbol_offset " << F->getSymbolOffset(); + if (F->hasSymbolOffset()) { + Out << " symbol_offset "; + writeOperand(F->getSymbolOffset(), true); + } + if (F->isDeclaration()) { Out << '\n'; } else { diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp index d158f9c..9195890 100644 --- a/lib/IR/Function.cpp +++ b/lib/IR/Function.cpp @@ -265,7 +265,7 @@ void Function::BuildLazyArguments() const { // Clear the lazy arguments bit. unsigned SDC = getSubclassDataFromValue(); - const_cast<Function*>(this)->setValueSubclassData(SDC &= ~1); + const_cast<Function*>(this)->setValueSubclassData(SDC &= ~(1<<0)); } size_t Function::arg_size() const { @@ -302,6 +302,9 @@ void Function::dropAllReferences() { // Prefix data is stored in a side table. setPrefixData(nullptr); + + // Symbol offset is stored in a side table. + setSymbolOffset(nullptr); } void Function::addAttribute(unsigned i, Attribute::AttrKind attr) { @@ -381,7 +384,10 @@ void Function::copyAttributesFrom(const GlobalValue *Src) { setPrefixData(SrcF->getPrefixData()); else setPrefixData(nullptr); - setSymbolOffset(SrcF->getSymbolOffset()); + if (SrcF->hasSymbolOffset()) + setSymbolOffset(SrcF->getSymbolOffset()); + else + setSymbolOffset(nullptr); } /// getIntrinsicID - This method returns the ID number of the specified @@ -799,19 +805,40 @@ void Function::setPrefixData(Constant *PrefixData) { PDHolder->setOperand(0, PrefixData); else PDHolder = ReturnInst::Create(getContext(), PrefixData); - SCData |= 2; + SCData |= (1<<1); } else { delete PDHolder; PDMap.erase(this); - SCData &= ~2; + SCData &= ~(1<<1); } setValueSubclassData(SCData); } -signed Function::getSymbolOffset() const { - return this->SymbolOffset; +Constant *Function::getSymbolOffset() const { + assert(hasSymbolOffset()); + const LLVMContextImpl::SymbolOffsetMapTy &SOMap + getContext().pImpl->SymbolOffsetMap; + assert(SOMap.find(this) != SOMap.end()); + return cast<Constant>(SOMap.find(this)->second->getReturnValue()); } -void Function::setSymbolOffset(signed Offset) { - this->SymbolOffset = Offset; +void Function::setSymbolOffset(Constant *Offset) { + if (!Offset && !hasSymbolOffset()) + return; + + unsigned SCData = getSubclassDataFromValue(); + LLVMContextImpl::SymbolOffsetMapTy &SOMap = getContext().pImpl->SymbolOffsetMap; + ReturnInst *&SOHolder = SOMap[this]; + if (Offset) { + if (SOHolder) + SOHolder->setOperand(0, Offset); + else + SOHolder = ReturnInst::Create(getContext(), Offset); + SCData |= (1<<2); + } else { + delete SOHolder; + SOMap.erase(this); + SCData &= ~(1<<2); + } + setValueSubclassData(SCData); } diff --git a/lib/IR/LLVMContextImpl.h b/lib/IR/LLVMContextImpl.h index 808c239..ddb1f7d 100644 --- a/lib/IR/LLVMContextImpl.h +++ b/lib/IR/LLVMContextImpl.h @@ -374,6 +374,12 @@ public: typedef DenseMap<const Function *, ReturnInst *> PrefixDataMapTy; PrefixDataMapTy PrefixDataMap; + /// \brief Mapping from a function to its symbol offset, which is stored as + /// the operand of an unparented ReturnInst so that the prefix data has a + /// Use. + typedef DenseMap<const Function *, ReturnInst *> SymbolOffsetMapTy; + SymbolOffsetMapTy SymbolOffsetMap; + int getOrAddScopeRecordIdxEntry(MDNode *N, int ExistingIdx); int getOrAddScopeInlinedAtIdxEntry(MDNode *Scope, MDNode *IA,int ExistingIdx); diff --git a/lib/IR/TypeFinder.cpp b/lib/IR/TypeFinder.cpp index 689b903..5e63972 100644 --- a/lib/IR/TypeFinder.cpp +++ b/lib/IR/TypeFinder.cpp @@ -47,6 +47,9 @@ void TypeFinder::run(const Module &M, bool onlyNamed) { if (FI->hasPrefixData()) incorporateValue(FI->getPrefixData()); + if (FI->hasSymbolOffset()) + incorporateValue(FI->getSymbolOffset()); + // First incorporate the arguments. for (Function::const_arg_iterator AI = FI->arg_begin(), AE = FI->arg_end(); AI != AE; ++AI) diff --git a/lib/Transforms/IPO/GlobalDCE.cpp b/lib/Transforms/IPO/GlobalDCE.cpp index 9decddc..b1d65be 100644 --- a/lib/Transforms/IPO/GlobalDCE.cpp +++ b/lib/Transforms/IPO/GlobalDCE.cpp @@ -197,6 +197,9 @@ void GlobalDCE::GlobalIsNeeded(GlobalValue *G) { if (F->hasPrefixData()) MarkUsedGlobalsAsNeeded(F->getPrefixData()); + if (F->hasSymbolOffset()) + MarkUsedGlobalsAsNeeded(F->getSymbolOffset()); + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) for (User::op_iterator U = I->op_begin(), E = I->op_end(); U != E; ++U) diff --git a/test/Feature/symbol_offset.ll b/test/Feature/symbol_offset.ll index a9784f6..3bebc85 100644 --- a/test/Feature/symbol_offset.ll +++ b/test/Feature/symbol_offset.ll @@ -4,7 +4,7 @@ ; RUN: diff %t1.ll %t2.ll ; RUN: opt -O3 -S < %t1.ll | FileCheck %s -; CHECK: f(){{.*}}symbol_offset 1 -define void @f() symbol_offset 1 { +; CHECK: f(){{.*}}symbol_offset i32 1 +define void @f() symbol_offset i32 1 { ret void } -- 1.9.2