[LLVMdev] [PATCH 2/2] Allow full constants in symbol_offsets

Ben Gamari bgamari.foss at gmail.com
Sun May 25 17:41:11 PDT 2014


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




More information about the llvm-dev mailing list