Teach DAGCombine to fold constant offsets into GlobalAddress nodes,
authorDan Gohman <gohman@apple.com>
Sat, 18 Oct 2008 02:06:02 +0000 (02:06 +0000)
committerDan Gohman <gohman@apple.com>
Sat, 18 Oct 2008 02:06:02 +0000 (02:06 +0000)
and add a TargetLowering hook for it to use to determine when this
is legal (i.e. not in PIC mode, etc.)

This allows instruction selection to emit folded constant offsets
in more cases, such as the included testcase, eliminating the need
for explicit arithmetic instructions.

This eliminates the need for the C++ code in X86ISelDAGToDAG.cpp
that attempted to achieve the same effect, but wasn't as effective.

Also, fix handling of offsets in GlobalAddressSDNodes in several
places, including changing GlobalAddressSDNode's offset from
int to int64_t.

The Mips, Alpha, Sparc, and CellSPU targets appear to be
unaware of GlobalAddress offsets currently, so set the hook to
false on those targets.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57748 91177308-0d34-0410-b5e6-96231b3b80d8

21 files changed:
include/llvm/CodeGen/MachineInstrBuilder.h
include/llvm/CodeGen/MachineOperand.h
include/llvm/CodeGen/SelectionDAG.h
include/llvm/CodeGen/SelectionDAGNodes.h
include/llvm/Target/TargetLowering.h
lib/CodeGen/SelectionDAG/DAGCombiner.cpp
lib/CodeGen/SelectionDAG/SelectionDAG.cpp
lib/CodeGen/SelectionDAG/TargetLowering.cpp
lib/Target/Alpha/AlphaISelLowering.cpp
lib/Target/Alpha/AlphaISelLowering.h
lib/Target/CellSPU/SPUISelLowering.cpp
lib/Target/CellSPU/SPUISelLowering.h
lib/Target/Mips/MipsISelLowering.cpp
lib/Target/Mips/MipsISelLowering.h
lib/Target/Sparc/SparcISelLowering.cpp
lib/Target/Sparc/SparcISelLowering.h
lib/Target/X86/X86ISelDAGToDAG.cpp
lib/Target/X86/X86ISelLowering.cpp
lib/Target/X86/X86ISelLowering.h
lib/Target/X86/X86TargetMachine.cpp
test/CodeGen/X86/ga-offset.ll [new file with mode: 0644]

index c63487d19dce02f807f3ba1ae76092ec352e78dd..f57168b27669d56ff5eb0c161ac51fa30168152b 100644 (file)
@@ -79,13 +79,14 @@ public:
   }
 
   const MachineInstrBuilder &addGlobalAddress(GlobalValue *GV,
-                                              int Offset = 0) const {
+                                              int64_t Offset = 0) const {
     MI->addOperand(MachineOperand::CreateGA(GV, Offset));
     return *this;
   }
 
-  const MachineInstrBuilder &addExternalSymbol(const char *FnName) const{
-    MI->addOperand(MachineOperand::CreateES(FnName, 0));
+  const MachineInstrBuilder &addExternalSymbol(const char *FnName,
+                                               int64_t Offset = 0) const {
+    MI->addOperand(MachineOperand::CreateES(FnName, Offset));
     return *this;
   }
 };
index f9d80c7fcce0ee9e0d19493e0629c568739313cc..e3cc814011722d1547cfaed10d0b96267fe5b2a6 100644 (file)
@@ -101,7 +101,7 @@ private:
         const char *SymbolName;   // For MO_ExternalSymbol.
         GlobalValue *GV;          // For MO_GlobalAddress.
       } Val;
-      int Offset;   // An offset from the object.
+      int64_t Offset;   // An offset from the object.
     } OffsetedInfo;
   } Contents;
   
@@ -273,7 +273,7 @@ public:
     return Contents.OffsetedInfo.Val.GV;
   }
   
-  int getOffset() const {
+  int64_t getOffset() const {
     assert((isGlobal() || isSymbol() || isCPI()) &&
            "Wrong MachineOperand accessor");
     return Contents.OffsetedInfo.Offset;
@@ -293,7 +293,7 @@ public:
     Contents.ImmVal = immVal;
   }
 
-  void setOffset(int Offset) {
+  void setOffset(int64_t Offset) {
     assert((isGlobal() || isSymbol() || isCPI()) &&
         "Wrong MachineOperand accessor");
     Contents.OffsetedInfo.Offset = Offset;
@@ -382,13 +382,13 @@ public:
     Op.setIndex(Idx);
     return Op;
   }
-  static MachineOperand CreateGA(GlobalValue *GV, int Offset) {
+  static MachineOperand CreateGA(GlobalValue *GV, int64_t Offset) {
     MachineOperand Op(MachineOperand::MO_GlobalAddress);
     Op.Contents.OffsetedInfo.Val.GV = GV;
     Op.setOffset(Offset);
     return Op;
   }
-  static MachineOperand CreateES(const char *SymName, int Offset = 0) {
+  static MachineOperand CreateES(const char *SymName, int64_t Offset = 0) {
     MachineOperand Op(MachineOperand::MO_ExternalSymbol);
     Op.Contents.OffsetedInfo.Val.SymbolName = SymName;
     Op.setOffset(Offset);
index d6a40a68a2b273bd18bdcb9001e311c59a7a4de0..a6f9c1beed95ade16d70b6407e5730751bfbaa9e 100644 (file)
@@ -255,9 +255,9 @@ public:
     return getConstantFP(Val, VT, true);
   }
   SDValue getGlobalAddress(const GlobalValue *GV, MVT VT,
-                             int offset = 0, bool isTargetGA = false);
+                           int64_t offset = 0, bool isTargetGA = false);
   SDValue getTargetGlobalAddress(const GlobalValue *GV, MVT VT,
-                                   int offset = 0) {
+                                 int64_t offset = 0) {
     return getGlobalAddress(GV, VT, offset, true);
   }
   SDValue getFrameIndex(int FI, MVT VT, bool isTarget = false);
index 94c8dadd966d8e12c665f53e00a03ff0ce95dddf..494783229ad3274fef17ff8b7cf9156b1666ff8c 100644 (file)
@@ -1819,15 +1819,16 @@ public:
 
 class GlobalAddressSDNode : public SDNode {
   GlobalValue *TheGlobal;
-  int Offset;
+  int64_t Offset;
   virtual void ANCHOR();  // Out-of-line virtual method to give class a home.
 protected:
   friend class SelectionDAG;
-  GlobalAddressSDNode(bool isTarget, const GlobalValue *GA, MVT VT, int o = 0);
+  GlobalAddressSDNode(bool isTarget, const GlobalValue *GA, MVT VT,
+                      int64_t o = 0);
 public:
 
   GlobalValue *getGlobal() const { return TheGlobal; }
-  int getOffset() const { return Offset; }
+  int64_t getOffset() const { return Offset; }
 
   static bool classof(const GlobalAddressSDNode *) { return true; }
   static bool classof(const SDNode *N) {
index 5e5bdbe5116af04777dea209a192239421568782..85e90af5adf20ebaf42af0483b3171172bbd3a26 100644 (file)
@@ -653,6 +653,11 @@ public:
   virtual SDValue getPICJumpTableRelocBase(SDValue Table,
                                              SelectionDAG &DAG) const;
 
+  /// isOffsetFoldingLegal - Return true if folding a constant offset
+  /// with the given GlobalAddress is legal.  It is frequently not legal in
+  /// PIC relocation models.
+  virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
+
   //===--------------------------------------------------------------------===//
   // TargetLowering Optimization Methods
   //
index 4b1945efe4de8e7436172264888151ec2bf6e716..81058152eb0065ddb3059323a6350d23e4c4aaae 100644 (file)
@@ -967,6 +967,13 @@ SDValue DAGCombiner::visitADD(SDNode *N) {
   // fold (add x, 0) -> x
   if (N1C && N1C->isNullValue())
     return N0;
+  // fold (add Sym, c) -> Sym+c
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N0))
+    if (!AfterLegalize && TLI.isOffsetFoldingLegal(GA) && N1C &&
+        GA->getOpcode() == ISD::GlobalAddress)
+      return DAG.getGlobalAddress(GA->getGlobal(), VT,
+                                  GA->getOffset() +
+                                    (uint64_t)N1C->getSExtValue());
   // fold ((c1-A)+c2) -> (c1+c2)-A
   if (N1C && N0.getOpcode() == ISD::SUB)
     if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0.getOperand(0)))
@@ -1133,6 +1140,21 @@ SDValue DAGCombiner::visitSUB(SDNode *N) {
   if (N1.getOpcode() == ISD::UNDEF)
     return N1;
 
+  // If the relocation model supports it, consider symbol offsets.
+  if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N0))
+    if (!AfterLegalize && TLI.isOffsetFoldingLegal(GA)) {
+      // fold (sub Sym, c) -> Sym-c
+      if (N1C && GA->getOpcode() == ISD::GlobalAddress)
+        return DAG.getGlobalAddress(GA->getGlobal(), VT,
+                                    GA->getOffset() -
+                                      (uint64_t)N1C->getSExtValue());
+      // fold (sub Sym+c1, Sym+c2) -> c1-c2
+      if (GlobalAddressSDNode *GB = dyn_cast<GlobalAddressSDNode>(N1))
+        if (GA->getGlobal() == GB->getGlobal())
+          return DAG.getConstant((uint64_t)GA->getOffset() - GB->getOffset(),
+                                 VT);
+    }
+
   return SDValue();
 }
 
index 9cfb1a1a22d8218b19bd66f85c8e3e35fbd7517f..07819404e14407ee131f75f862e4527cf5f5c8f5 100644 (file)
@@ -959,10 +959,15 @@ SDValue SelectionDAG::getConstantFP(double Val, MVT VT, bool isTarget) {
 }
 
 SDValue SelectionDAG::getGlobalAddress(const GlobalValue *GV,
-                                       MVT VT, int Offset,
+                                       MVT VT, int64_t Offset,
                                        bool isTargetGA) {
   unsigned Opc;
 
+  // Truncate (with sign-extension) the offset value to the pointer size.
+  unsigned BitWidth = VT.getSizeInBits();
+  if (BitWidth < 64)
+    Offset = (Offset << (64 - BitWidth) >> (64 - BitWidth));
+
   const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
   if (!GVar) {
     // If GV is an alias then use the aliasee for determining thread-localness.
@@ -2017,6 +2022,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, unsigned Depth) const{
 bool SelectionDAG::isVerifiedDebugInfoDesc(SDValue Op) const {
   GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op);
   if (!GA) return false;
+  if (GA->getOffset() != 0) return false;
   GlobalVariable *GV = dyn_cast<GlobalVariable>(GA->getGlobal());
   if (!GV) return false;
   MachineModuleInfo *MMI = getMachineModuleInfo();
@@ -4726,7 +4732,7 @@ HandleSDNode::~HandleSDNode() {
 }
 
 GlobalAddressSDNode::GlobalAddressSDNode(bool isTarget, const GlobalValue *GA,
-                                         MVT VT, int o)
+                                         MVT VT, int64_t o)
   : SDNode(isa<GlobalVariable>(GA) &&
            cast<GlobalVariable>(GA)->isThreadLocal() ?
            // Thread Local
index 479e1380c5b21e38c031379f560dfaf300110c52..1e7e847b8adba831b856087144f6a0fb927bf946 100644 (file)
@@ -656,6 +656,23 @@ SDValue TargetLowering::getPICJumpTableRelocBase(SDValue Table,
   return Table;
 }
 
+bool
+TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+  // Assume that everything is safe in static mode.
+  if (getTargetMachine().getRelocationModel() == Reloc::Static)
+    return true;
+
+  // In dynamic-no-pic mode, assume that known defined values are safe.
+  if (getTargetMachine().getRelocationModel() == Reloc::DynamicNoPIC &&
+      GA &&
+      !GA->getGlobal()->isDeclaration() &&
+      !GA->getGlobal()->mayBeOverridden())
+    return true;
+
+  // Otherwise assume nothing is safe.
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 //  Optimization Methods
 //===----------------------------------------------------------------------===//
index 33445f0fa4cfa0c164f973c88507d7dca757c6aa..787883073553441d09c55c90538b74b965af5fd8 100644 (file)
@@ -764,3 +764,9 @@ AlphaTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
 
   return sinkMBB;
 }
+
+bool
+AlphaTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+  // The Alpha target isn't yet aware of offsets.
+  return false;
+}
index 0a78997b195799a9fd7dd442b5b3c3f14056c15a..3e870aff8823c18c5cfd7cb1116fc152b88ce013 100644 (file)
@@ -95,6 +95,8 @@ namespace llvm {
     MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI,
                                                    MachineBasicBlock *BB);
 
+    virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
+
   private:
     // Helpers for custom lowering.
     void LowerVAARG(SDNode *N, SDValue &Chain, SDValue &DataPtr,
index 086a25f1d8961342b27f7f1a8b6eb2a1af8dc181..659ba7530d079e2f73f432f05e9090d14957121e 100644 (file)
@@ -3058,3 +3058,9 @@ bool SPUTargetLowering::isLegalAddressImmediate(int64_t V,
 bool SPUTargetLowering::isLegalAddressImmediate(llvm::GlobalValue* GV) const {
   return false;
 }
+
+bool
+SPUTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+  // The SPU target isn't yet aware of offsets.
+  return false;
+}
index e79b1363f21ab8a1fff52befd3790fef033dea43..54aac66571da35f20952af518ea6200658f2ede8 100644 (file)
@@ -139,6 +139,8 @@ namespace llvm {
     /// as the offset of the target addressing mode.
     virtual bool isLegalAddressImmediate(int64_t V, const Type *Ty) const;
     virtual bool isLegalAddressImmediate(GlobalValue *) const;
+
+    virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
   };
 }
 
index 3224d73d5f6041aea767fc114def38d8ade16d70..8fdc4b799b8d7938ee995e52712ca85c117e0b65 100644 (file)
@@ -1094,3 +1094,9 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint,
   }
   return std::vector<unsigned>();
 }
+
+bool
+MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+  // The Mips target isn't yet aware of offsets.
+  return false;
+}
index b19ce58d2b37bbbed7af7399df91a196c6233ca6..5704b7ef8e284c86e223b54cf32a8dcc45262f0d 100644 (file)
@@ -118,6 +118,8 @@ namespace llvm {
     std::vector<unsigned>
     getRegClassForInlineAsmConstraint(const std::string &Constraint,
               MVT VT) const;
+
+    virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
   };
 }
 
index e81688e4e8ec924aac87f5ac20ad34474acfc319..59e19d54666f791bed2c694bf3fcec3a4accd980 100644 (file)
@@ -996,3 +996,9 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint,
 
   return std::vector<unsigned>();
 }
+
+bool
+SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+  // The Sparc target isn't yet aware of offsets.
+  return false;
+}
index ea3171d0276e831b64a633585ad1a1b6900ef5b6..a0e3c653441ff98482d15d11a96af42d0c1e49a8 100644 (file)
@@ -70,6 +70,8 @@ namespace llvm {
     std::vector<unsigned>
     getRegClassForInlineAsmConstraint(const std::string &Constraint,
                                       MVT VT) const;
+
+    virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const;
   };
 } // end namespace llvm
 
index cf83e681922c15ac7acc535de12c789ddb693481..6735f1d80b783e8e6857c74d5c1db06d11263e32 100644 (file)
@@ -759,6 +759,7 @@ void X86DAGToDAGISel::EmitFunctionEntryCode(Function &Fn, MachineFunction &MF) {
 /// addressing mode.
 bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM,
                                    bool isRoot, unsigned Depth) {
+  bool is64Bit = Subtarget->is64Bit();
   DOUT << "MatchAddress: "; DEBUG(AM.dump());
   // Limit recursion.
   if (Depth > 5)
@@ -768,7 +769,7 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM,
   if (AM.isRIPRel) {
     if (!AM.ES && AM.JT != -1 && N.getOpcode() == ISD::Constant) {
       int64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
-      if (isInt32(AM.Disp + Val)) {
+      if (!is64Bit || isInt32(AM.Disp + Val)) {
         AM.Disp += Val;
         return false;
       }
@@ -783,7 +784,7 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM,
   default: break;
   case ISD::Constant: {
     int64_t Val = cast<ConstantSDNode>(N)->getSExtValue();
-    if (isInt32(AM.Disp + Val)) {
+    if (!is64Bit || isInt32(AM.Disp + Val)) {
       AM.Disp += Val;
       return false;
     }
@@ -791,10 +792,9 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM,
   }
 
   case X86ISD::Wrapper: {
-DOUT << "Wrapper: 64bit " << Subtarget->is64Bit();
-DOUT << " AM "; DEBUG(AM.dump()); DOUT << "\n";
-DOUT << "AlreadySelected " << AlreadySelected << "\n";
-    bool is64Bit = Subtarget->is64Bit();
+    DOUT << "Wrapper: 64bit " << is64Bit;
+    DOUT << " AM "; DEBUG(AM.dump()); DOUT << "\n";
+    DOUT << "AlreadySelected " << AlreadySelected << "\n";
     // Under X86-64 non-small code model, GV (and friends) are 64-bits.
     // Also, base and index reg must be 0 in order to use rip as base.
     if (is64Bit && (TM.getCodeModel() != CodeModel::Small ||
@@ -808,17 +808,21 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n";
     if (!AlreadySelected || (AM.Base.Reg.getNode() && AM.IndexReg.getNode())) {
       SDValue N0 = N.getOperand(0);
       if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) {
-        GlobalValue *GV = G->getGlobal();
-        AM.GV = GV;
-        AM.Disp += G->getOffset();
-        AM.isRIPRel = TM.symbolicAddressesAreRIPRel();
-        return false;
+        if (!is64Bit || isInt32(AM.Disp + G->getOffset())) {
+          GlobalValue *GV = G->getGlobal();
+          AM.GV = GV;
+          AM.Disp += G->getOffset();
+          AM.isRIPRel = TM.symbolicAddressesAreRIPRel();
+          return false;
+        }
       } else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N0)) {
-        AM.CP = CP->getConstVal();
-        AM.Align = CP->getAlignment();
-        AM.Disp += CP->getOffset();
-        AM.isRIPRel = TM.symbolicAddressesAreRIPRel();
-        return false;
+        if (!is64Bit || isInt32(AM.Disp + CP->getOffset())) {
+          AM.CP = CP->getConstVal();
+          AM.Align = CP->getAlignment();
+          AM.Disp += CP->getOffset();
+          AM.isRIPRel = TM.symbolicAddressesAreRIPRel();
+          return false;
+        }
       } else if (ExternalSymbolSDNode *S =dyn_cast<ExternalSymbolSDNode>(N0)) {
         AM.ES = S->getSymbol();
         AM.isRIPRel = TM.symbolicAddressesAreRIPRel();
@@ -862,7 +866,7 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n";
           ConstantSDNode *AddVal =
             cast<ConstantSDNode>(ShVal.getNode()->getOperand(1));
           uint64_t Disp = AM.Disp + (AddVal->getZExtValue() << Val);
-          if (isInt32(Disp))
+          if (!is64Bit || isInt32(Disp))
             AM.Disp = Disp;
           else
             AM.IndexReg = ShVal;
@@ -905,7 +909,7 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n";
               cast<ConstantSDNode>(MulVal.getNode()->getOperand(1));
             uint64_t Disp = AM.Disp + AddVal->getZExtValue() *
                                       CN->getZExtValue();
-            if (isInt32(Disp))
+            if (!is64Bit || isInt32(Disp))
               AM.Disp = Disp;
             else
               Reg = N.getNode()->getOperand(0);
@@ -944,7 +948,7 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n";
           // Address could not have picked a GV address for the displacement.
           AM.GV == NULL &&
           // On x86-64, the resultant disp must fit in 32-bits.
-          isInt32(AM.Disp + CN->getSExtValue()) &&
+          (!is64Bit || isInt32(AM.Disp + CN->getSExtValue())) &&
           // Check to see if the LHS & C is zero.
           CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) {
         AM.Disp += CN->getZExtValue();
@@ -1248,49 +1252,6 @@ SDNode *X86DAGToDAGISel::Select(SDValue N) {
     case X86ISD::GlobalBaseReg: 
       return getGlobalBaseReg();
 
-    case ISD::ADD: {
-      // Turn ADD X, c to MOV32ri X+c. This cannot be done with tblgen'd
-      // code and is matched first so to prevent it from being turned into
-      // LEA32r X+c.
-      // In 64-bit small code size mode, use LEA to take advantage of
-      // RIP-relative addressing.
-      if (TM.getCodeModel() != CodeModel::Small)
-        break;
-      MVT PtrVT = TLI.getPointerTy();
-      SDValue N0 = N.getOperand(0);
-      SDValue N1 = N.getOperand(1);
-      if (N.getNode()->getValueType(0) == PtrVT &&
-          N0.getOpcode() == X86ISD::Wrapper &&
-          N1.getOpcode() == ISD::Constant) {
-        unsigned Offset = (unsigned)cast<ConstantSDNode>(N1)->getZExtValue();
-        SDValue C(0, 0);
-        // TODO: handle ExternalSymbolSDNode.
-        if (GlobalAddressSDNode *G =
-            dyn_cast<GlobalAddressSDNode>(N0.getOperand(0))) {
-          C = CurDAG->getTargetGlobalAddress(G->getGlobal(), PtrVT,
-                                             G->getOffset() + Offset);
-        } else if (ConstantPoolSDNode *CP =
-                   dyn_cast<ConstantPoolSDNode>(N0.getOperand(0))) {
-          C = CurDAG->getTargetConstantPool(CP->getConstVal(), PtrVT,
-                                            CP->getAlignment(),
-                                            CP->getOffset()+Offset);
-        }
-
-        if (C.getNode()) {
-          if (Subtarget->is64Bit()) {
-            SDValue Ops[] = { CurDAG->getRegister(0, PtrVT), getI8Imm(1),
-                                CurDAG->getRegister(0, PtrVT), C };
-            return CurDAG->SelectNodeTo(N.getNode(), X86::LEA64r,
-                                        MVT::i64, Ops, 4);
-          } else
-            return CurDAG->SelectNodeTo(N.getNode(), X86::MOV32ri, PtrVT, C);
-        }
-      }
-
-      // Other cases are handled by auto-generated code.
-      break;
-    }
-
     case X86ISD::ATOMOR64_DAG:
       return SelectAtomic64(Node, X86::ATOMOR6432);
     case X86ISD::ATOMXOR64_DAG:
index fa467693bcf28616437893aff2e21e8fed67b83c..c977dbe92b0f3cbcf54cef591168500552321f5d 100644 (file)
@@ -1705,7 +1705,8 @@ SDValue X86TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) {
     // non-JIT mode.
     if (!Subtarget->GVRequiresExtraLoad(G->getGlobal(),
                                         getTargetMachine(), true))
-      Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
+      Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy(),
+                                          G->getOffset());
   } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
     Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
   } else if (IsTailCall) {
@@ -4390,12 +4391,24 @@ X86TargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) {
 
 SDValue
 X86TargetLowering::LowerGlobalAddress(const GlobalValue *GV,
+                                      int64_t Offset,
                                       SelectionDAG &DAG) const {
-  SDValue Result = DAG.getTargetGlobalAddress(GV, getPointerTy());
+  bool IsPic = getTargetMachine().getRelocationModel() == Reloc::PIC_;
+  bool ExtraLoadRequired =
+    Subtarget->GVRequiresExtraLoad(GV, getTargetMachine(), false);
+
+  // Create the TargetGlobalAddress node, folding in the constant
+  // offset if it is legal.
+  SDValue Result;
+  if (!IsPic && !ExtraLoadRequired) {
+    Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), Offset);
+    Offset = 0;
+  } else
+    Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), 0);
   Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(), Result);
+
   // With PIC, the address is actually $g + Offset.
-  if (getTargetMachine().getRelocationModel() == Reloc::PIC_ &&
-      !Subtarget->isPICStyleRIPRel()) {
+  if (IsPic && !Subtarget->isPICStyleRIPRel()) {
     Result = DAG.getNode(ISD::ADD, getPointerTy(),
                          DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()),
                          Result);
@@ -4406,17 +4419,24 @@ X86TargetLowering::LowerGlobalAddress(const GlobalValue *GV,
   // the GlobalAddress must be in the base or index register of the address, not
   // the GV offset field. Platform check is inside GVRequiresExtraLoad() call
   // The same applies for external symbols during PIC codegen
-  if (Subtarget->GVRequiresExtraLoad(GV, getTargetMachine(), false))
+  if (ExtraLoadRequired)
     Result = DAG.getLoad(getPointerTy(), DAG.getEntryNode(), Result,
                          PseudoSourceValue::getGOT(), 0);
 
+  // If there was a non-zero offset that we didn't fold, create an explicit
+  // addition for it.
+  if (Offset != 0)
+    Result = DAG.getNode(ISD::ADD, getPointerTy(), Result,
+                         DAG.getConstant(Offset, getPointerTy()));
+
   return Result;
 }
 
 SDValue
 X86TargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) {
   const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
-  return LowerGlobalAddress(GV, DAG);
+  int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
+  return LowerGlobalAddress(GV, Offset, DAG);
 }
 
 // Lower ISD::GlobalTLSAddress using the "general dynamic" model, 32 bit
@@ -7006,6 +7026,7 @@ bool X86TargetLowering::isGAPlusOffset(SDNode *N,
   if (N->getOpcode() == X86ISD::Wrapper) {
     if (isa<GlobalAddressSDNode>(N->getOperand(0))) {
       GA = cast<GlobalAddressSDNode>(N->getOperand(0))->getGlobal();
+      Offset = cast<GlobalAddressSDNode>(N->getOperand(0))->getOffset();
       return true;
     }
   }
@@ -7448,7 +7469,7 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
     
     if (GA) {
       if (hasMemory) 
-        Op = LowerGlobalAddress(GA->getGlobal(), DAG);
+        Op = LowerGlobalAddress(GA->getGlobal(), Offset, DAG);
       else
         Op = DAG.getTargetGlobalAddress(GA->getGlobal(), GA->getValueType(0),
                                         Offset);
index b3d165432ff1dcbca3f5c7a20b2de503f70274b2..b76ba845e51aa657520f023e858838277ce5d42a 100644 (file)
@@ -551,7 +551,8 @@ namespace llvm {
     SDValue LowerINSERT_VECTOR_ELT_SSE4(SDValue Op, SelectionDAG &DAG);
     SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG);
     SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG);
-    SDValue LowerGlobalAddress(const GlobalValue *GV, SelectionDAG &DAG) const;
+    SDValue LowerGlobalAddress(const GlobalValue *GV, int64_t Offset,
+                               SelectionDAG &DAG) const;
     SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG);
     SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG);
     SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG);
index 923823b98cd51db44f23676a99709e5fd38b106a..ef4f897f5d12f101f07c0afa12899a79340aa3fd 100644 (file)
@@ -143,6 +143,15 @@ X86TargetMachine::X86TargetMachine(const Module &M, const std::string &FS,
     else
       setRelocationModel(Reloc::Static);
   }
+
+  // ELF doesn't have a distinct dynamic-no-PIC model. Dynamic-no-PIC
+  // is defined as a model for code which may be used in static or
+  // dynamic executables but not necessarily a shared library. On ELF
+  // implement this by using the Static model.
+  if (Subtarget.isTargetELF() &&
+      getRelocationModel() == Reloc::DynamicNoPIC)
+    setRelocationModel(Reloc::Static);
+
   if (Subtarget.is64Bit()) {
     // No DynamicNoPIC support under X86-64.
     if (getRelocationModel() == Reloc::DynamicNoPIC)
diff --git a/test/CodeGen/X86/ga-offset.ll b/test/CodeGen/X86/ga-offset.ll
new file mode 100644 (file)
index 0000000..cc93b4c
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: llvm-as < %s | llc -march=x86 > %t
+; RUN: not grep lea %t
+; RUN: not grep add %t
+; RUN: grep mov %t | count 1
+; RUN: llvm-as < %s | llc -march=x86-64 -relocation-model=static > %t
+; RUN: not grep lea %t
+; RUN: not grep add %t
+; RUN: grep mov %t | count 1
+
+; This store should fold to a single mov instruction.
+
+@ptr = global i32* null
+@dst = global [131072 x i32] zeroinitializer
+
+define void @foo() nounwind {
+  store i32* getelementptr ([131072 x i32]* @dst, i32 0, i32 16), i32** @ptr
+  ret void
+}