CodeGen: Stick constant pool entries in COMDAT sections for WinCOFF
authorDavid Majnemer <david.majnemer@gmail.com>
Mon, 14 Jul 2014 22:57:27 +0000 (22:57 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Mon, 14 Jul 2014 22:57:27 +0000 (22:57 +0000)
COFF lacks a feature that other object file formats support: mergeable
sections.

To work around this, MSVC sticks constant pool entries in special COMDAT
sections so that each constant is in it's own section.  This permits
unused constants to be dropped and it also allows duplicate constants in
different translation units to get merged together.

This fixes PR20262.

Differential Revision: http://reviews.llvm.org/D4482

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

16 files changed:
include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
include/llvm/MC/MCSectionCOFF.h
include/llvm/Target/TargetLoweringObjectFile.h
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/CodeGen/TargetLoweringObjectFileImpl.cpp
lib/MC/MCContext.cpp
lib/Target/NVPTX/NVPTXTargetObjectFile.h
lib/Target/TargetLoweringObjectFile.cpp
lib/Target/X86/X86AsmPrinter.cpp
lib/Target/X86/X86AsmPrinter.h
lib/Target/X86/X86TargetObjectFile.cpp
lib/Target/X86/X86TargetObjectFile.h
lib/Target/XCore/XCoreTargetObjectFile.cpp
lib/Target/XCore/XCoreTargetObjectFile.h
test/CodeGen/X86/constant-pool-sharing.ll
test/CodeGen/X86/win_cst_pool.ll [new file with mode: 0644]

index 230d1ed51a9488aab8c338c9576bbe0d976670ed..87f140190a75b0d4b31f659de51c056da0a3153f 100644 (file)
@@ -43,7 +43,8 @@ public:
 
   /// Given a constant with the SectionKind, return a section that it should be
   /// placed in.
-  const MCSection *getSectionForConstant(SectionKind Kind) const override;
+  const MCSection *getSectionForConstant(SectionKind Kind,
+                                         const Constant *C) const override;
 
   const MCSection *getExplicitSectionGlobal(const GlobalValue *GV,
                                         SectionKind Kind, Mangler &Mang,
@@ -100,7 +101,8 @@ public:
                              SectionKind Kind, Mangler &Mang,
                              const TargetMachine &TM) const override;
 
-  const MCSection *getSectionForConstant(SectionKind Kind) const override;
+  const MCSection *getSectionForConstant(SectionKind Kind,
+                                         const Constant *C) const override;
 
   /// The mach-o version of this method defaults to returning a stub reference.
   const MCExpr *
index d205e2aebfb0b33f7735134ee3eca39875071f69..0bbf3696686ebe5374ced88e8b2b5899c9ad01a3 100644 (file)
@@ -36,7 +36,7 @@ class MCSymbol;
     /// The COMDAT symbol of this section. Only valid if this is a COMDAT
     /// section. Two COMDAT sections are merged if they have the same
     /// COMDAT symbol.
-    const MCSymbol *COMDATSymbol;
+    MCSymbol *COMDATSymbol;
 
     /// Selection - This is the Selection field for the section symbol, if
     /// it is a COMDAT section (Characteristics & IMAGE_SCN_LNK_COMDAT) != 0
@@ -45,7 +45,7 @@ class MCSymbol;
   private:
     friend class MCContext;
     MCSectionCOFF(StringRef Section, unsigned Characteristics,
-                  const MCSymbol *COMDATSymbol, int Selection, SectionKind K)
+                  MCSymbol *COMDATSymbol, int Selection, SectionKind K)
         : MCSection(SV_COFF, K), SectionName(Section),
           Characteristics(Characteristics), COMDATSymbol(COMDATSymbol),
           Selection(Selection) {
@@ -67,7 +67,7 @@ class MCSymbol;
       return SectionName.str() + "_end";
     }
     unsigned getCharacteristics() const { return Characteristics; }
-    const MCSymbol *getCOMDATSymbol() const { return COMDATSymbol; }
+    MCSymbol *getCOMDATSymbol() const { return COMDATSymbol; }
     int getSelection() const { return Selection; }
 
     void setSelection(int Selection) const;
index 419eced0a0be8ea768854af2791cac80dc8cafe3..7c32a5e3d0ca8c807fe4be99575505766d5a7560 100644 (file)
@@ -70,7 +70,8 @@ public:
 
   /// Given a constant with the SectionKind, return a section that it should be
   /// placed in.
-  virtual const MCSection *getSectionForConstant(SectionKind Kind) const;
+  virtual const MCSection *getSectionForConstant(SectionKind Kind,
+                                                 const Constant *C) const;
 
   /// Classify the specified global variable into a set of target independent
   /// categories embodied in SectionKind.
index 4c3e6aa4732ab3820ed4c2914eaa2dd105c22946..424e759caa8c6613195808718d8fed5b0bd89701 100644 (file)
@@ -1064,7 +1064,11 @@ void AsmPrinter::EmitConstantPool() {
 
     SectionKind Kind = CPE.getSectionKind(TM.getDataLayout());
 
-    const MCSection *S = getObjFileLowering().getSectionForConstant(Kind);
+    const Constant *C = nullptr;
+    if (!CPE.isMachineConstantPoolEntry())
+      C = CPE.Val.ConstVal;
+
+    const MCSection *S = getObjFileLowering().getSectionForConstant(Kind, C);
 
     // The number of sections are small, just do a linear search from the
     // last section to the first.
@@ -1087,13 +1091,22 @@ void AsmPrinter::EmitConstantPool() {
   }
 
   // Now print stuff into the calculated sections.
+  const MCSection *CurSection = nullptr;
+  unsigned Offset = 0;
   for (unsigned i = 0, e = CPSections.size(); i != e; ++i) {
-    OutStreamer.SwitchSection(CPSections[i].S);
-    EmitAlignment(Log2_32(CPSections[i].Alignment));
-
-    unsigned Offset = 0;
     for (unsigned j = 0, ee = CPSections[i].CPEs.size(); j != ee; ++j) {
       unsigned CPI = CPSections[i].CPEs[j];
+      MCSymbol *Sym = GetCPISymbol(CPI);
+      if (!Sym->isUndefined())
+        continue;
+
+      if (CurSection != CPSections[i].S) {
+        OutStreamer.SwitchSection(CPSections[i].S);
+        EmitAlignment(Log2_32(CPSections[i].Alignment));
+        CurSection = CPSections[i].S;
+        Offset = 0;
+      }
+
       MachineConstantPoolEntry CPE = CP[CPI];
 
       // Emit inter-object padding for alignment.
@@ -1103,8 +1116,8 @@ void AsmPrinter::EmitConstantPool() {
 
       Type *Ty = CPE.getType();
       Offset = NewOffset + TM.getDataLayout()->getTypeAllocSize(Ty);
-      OutStreamer.EmitLabel(GetCPISymbol(CPI));
 
+      OutStreamer.EmitLabel(Sym);
       if (CPE.isMachineConstantPoolEntry())
         EmitMachineConstantPoolValue(CPE.Val.MachineCPVal);
       else
@@ -1142,7 +1155,8 @@ void AsmPrinter::EmitJumpTableInfo() {
   } else {
     // Otherwise, drop it in the readonly section.
     const MCSection *ReadOnlySection =
-      getObjFileLowering().getSectionForConstant(SectionKind::getReadOnly());
+        getObjFileLowering().getSectionForConstant(SectionKind::getReadOnly(),
+                                                   /*C=*/nullptr);
     OutStreamer.SwitchSection(ReadOnlySection);
     JTInDiffSection = true;
   }
index 03f4a51e8b63f342248edbaf76368e86fa478e29..f59efa35031c434a6cd224dec99d820380940621 100644 (file)
@@ -338,8 +338,9 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
 /// getSectionForConstant - Given a mergeable constant with the
 /// specified size and relocation information, return a section that it
 /// should be placed in.
-const MCSection *TargetLoweringObjectFileELF::
-getSectionForConstant(SectionKind Kind) const {
+const MCSection *
+TargetLoweringObjectFileELF::getSectionForConstant(SectionKind Kind,
+                                                   const Constant *C) const {
   if (Kind.isMergeableConst4() && MergeableConst4Section)
     return MergeableConst4Section;
   if (Kind.isMergeableConst8() && MergeableConst8Section)
@@ -654,7 +655,8 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
 }
 
 const MCSection *
-TargetLoweringObjectFileMachO::getSectionForConstant(SectionKind Kind) const {
+TargetLoweringObjectFileMachO::getSectionForConstant(SectionKind Kind,
+                                                     const Constant *C) const {
   // If this constant requires a relocation, we have to put it in the data
   // segment, not in the text segment.
   if (Kind.isDataRel() || Kind.isReadOnlyWithRel())
index 960a0716e93e2a148861aa28563e89d5a7c0ea5e..7702da3540ca56b1a28a895c6ae657a4dc3eee42 100644 (file)
@@ -291,7 +291,7 @@ const MCSectionCOFF *MCContext::getCOFFSection(StringRef Section,
   if (!IterBool.second)
     return Iter->second;
 
-  const MCSymbol *COMDATSymbol = nullptr;
+  MCSymbol *COMDATSymbol = nullptr;
   if (!COMDATSymName.empty())
     COMDATSymbol = GetOrCreateSymbol(COMDATSymName);
 
index 0b438c521a2096608a908af97b891d537361f39d..ba8086d78880f246cb16691522901de2f8925274 100644 (file)
@@ -87,7 +87,8 @@ public:
         new NVPTXSection(MCSection::SV_ELF, SectionKind::getMetadata());
   }
 
-  const MCSection *getSectionForConstant(SectionKind Kind) const override {
+  const MCSection *getSectionForConstant(SectionKind Kind,
+                                         const Constant *C) const override {
     return ReadOnlySection;
   }
 
index 39e045919ab0d47206474586823a399b0cf498a0..2569e922641d9eeaf254e5c5675150d7b6a70a12 100644 (file)
@@ -297,7 +297,8 @@ TargetLoweringObjectFile::SelectSectionForGlobal(const GlobalValue *GV,
 /// specified size and relocation information, return a section that it
 /// should be placed in.
 const MCSection *
-TargetLoweringObjectFile::getSectionForConstant(SectionKind Kind) const {
+TargetLoweringObjectFile::getSectionForConstant(SectionKind Kind,
+                                                const Constant *C) const {
   if (Kind.isReadOnly() && ReadOnlySection != nullptr)
     return ReadOnlySection;
 
index 1dca5689adee0dfeadf28d26aa82f08333a82aad..57c7a62bd5c121545161a143c46eaaf4f67bee50 100644 (file)
@@ -18,6 +18,7 @@
 #include "X86InstrInfo.h"
 #include "X86MachineFunctionInfo.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/CodeGen/MachineValueType.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
@@ -29,6 +30,7 @@
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCSectionMachO.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
@@ -549,6 +551,26 @@ emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel,
         4 /*size*/);
 }
 
+MCSymbol *X86AsmPrinter::GetCPISymbol(unsigned CPID) const {
+  if (Subtarget->isTargetKnownWindowsMSVC()) {
+    const MachineConstantPoolEntry &CPE =
+        MF->getConstantPool()->getConstants()[CPID];
+    if (!CPE.isMachineConstantPoolEntry()) {
+      SectionKind Kind = CPE.getSectionKind(TM.getDataLayout());
+      const Constant *C = CPE.Val.ConstVal;
+      const MCSectionCOFF *S = cast<MCSectionCOFF>(
+          getObjFileLowering().getSectionForConstant(Kind, C));
+      if (MCSymbol *Sym = S->getCOMDATSymbol()) {
+        if (Sym->isUndefined())
+          OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global);
+        return Sym;
+      }
+    }
+  }
+
+  return AsmPrinter::GetCPISymbol(CPID);
+}
+
 void X86AsmPrinter::GenerateExportDirective(const MCSymbol *Sym, bool IsData) {
   SmallString<128> Directive;
   raw_svector_ostream OS(Directive);
index e4eef5dbd79642208558c7313187f8965aeb8aa4..b1bbe8e41cc021bfa99ad92149ceaec6a073611b 100644 (file)
@@ -50,6 +50,9 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
                              unsigned AsmVariant, const char *ExtraCode,
                              raw_ostream &OS) override;
 
+  /// \brief Return the symbol for the specified constant pool entry.
+  MCSymbol *GetCPISymbol(unsigned CPID) const override;
+
   bool runOnMachineFunction(MachineFunction &F) override;
 };
 
index 8157085feaecd960b1237766dcc90f91a28bd167..c7802320b060cd40b111516dadd1a8fc6ec356a7 100644 (file)
@@ -8,10 +8,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "X86TargetObjectFile.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Operator.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/Support/Dwarf.h"
 #include "llvm/Target/TargetLowering.h"
@@ -106,3 +108,62 @@ const MCExpr *X86WindowsTargetObjectFile::getExecutableRelativeSymbol(
                                  MCSymbolRefExpr::VK_COFF_IMGREL32,
                                  getContext());
 }
+
+static std::string APIntToHexString(const APInt &AI, unsigned Width) {
+  std::string HexString = utohexstr(AI.getLimitedValue(), /*LowerCase=*/true);
+  unsigned Size = HexString.size();
+  assert(Width >= Size && "hex string is too large!");
+  HexString.insert(HexString.begin(), Width - Size, '0');
+
+  return HexString;
+}
+
+
+static std::string scalarConstantToHexString(const Constant *C) {
+  Type *Ty = C->getType();
+  if (Ty->isFloatTy()) {
+    const auto *CFP = cast<ConstantFP>(C);
+    return APIntToHexString(CFP->getValueAPF().bitcastToAPInt(), /*Width=*/8);
+  } else if (Ty->isDoubleTy()) {
+    const auto *CFP = cast<ConstantFP>(C);
+    return APIntToHexString(CFP->getValueAPF().bitcastToAPInt(), /*Width=*/16);
+  } else if (const auto *ITy = dyn_cast<IntegerType>(Ty)) {
+    const auto *CI = cast<ConstantInt>(C);
+    return APIntToHexString(CI->getValue(), (ITy->getBitWidth() / 8) * 2);
+  }
+  llvm_unreachable("unexpected constant pool element type!");
+}
+
+const MCSection *
+X86WindowsTargetObjectFile::getSectionForConstant(SectionKind Kind,
+                                                  const Constant *C) const {
+  if (Kind.isReadOnly()) {
+    if (C) {
+      Type *Ty = C->getType();
+      SmallString<32> COMDATSymName;
+      if (Ty->isFloatTy() || Ty->isDoubleTy()) {
+        COMDATSymName = "__real@";
+        COMDATSymName += scalarConstantToHexString(C);
+      } else if (const auto *VTy = dyn_cast<VectorType>(Ty)) {
+        uint64_t NumBits = VTy->getBitWidth();
+        if (NumBits == 128 || NumBits == 256) {
+          const auto *CDV = cast<ConstantDataVector>(C);
+          COMDATSymName = NumBits == 128 ? "__xmm@" : "__ymm@";
+          for (int I = CDV->getNumElements() - 1, E = -1; I != E; --I)
+            COMDATSymName +=
+                scalarConstantToHexString(CDV->getElementAsConstant(I));
+        }
+      }
+      if (!COMDATSymName.empty()) {
+        unsigned Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+                                   COFF::IMAGE_SCN_MEM_READ |
+                                   COFF::IMAGE_SCN_LNK_COMDAT;
+        return getContext().getCOFFSection(".rdata", Characteristics, Kind,
+                                           COMDATSymName,
+                                           COFF::IMAGE_COMDAT_SELECT_ANY);
+      }
+    }
+  }
+
+  return TargetLoweringObjectFile::getSectionForConstant(Kind, C);
+}
index a08ed09ffb9c9f542710bae5f1791e29dce80a57..4a10b7ea6b42bd7f4bfeebf25451ad26f459aeef 100644 (file)
@@ -46,6 +46,11 @@ namespace llvm {
     const MCExpr *
     getExecutableRelativeSymbol(const ConstantExpr *CE, Mangler &Mang,
                                 const TargetMachine &TM) const override;
+
+    /// \brief Given a mergeable constant with the specified size and relocation
+    /// information, return a section that it should be placed in.
+    const MCSection *getSectionForConstant(SectionKind Kind,
+                                           const Constant *C) const override;
   };
 
 } // end namespace llvm
index ab0f7ad47dcc087ccdf71915c6e0861a942fe926..cfd3302481e7335fd6de831399b456d52e1f2fbf 100644 (file)
@@ -165,8 +165,9 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler &Mang,
   report_fatal_error("Target does not support TLS or Common sections");
 }
 
-const MCSection *XCoreTargetObjectFile::
-getSectionForConstant(SectionKind Kind) const {
+const MCSection *
+XCoreTargetObjectFile::getSectionForConstant(SectionKind Kind,
+                                             const Constant *C) const {
   if (Kind.isMergeableConst4())           return MergeableConst4Section;
   if (Kind.isMergeableConst8())           return MergeableConst8Section;
   if (Kind.isMergeableConst16())          return MergeableConst16Section;
index 34d756edc3f70b8cb929d8d97b90136fe6a4112b..d389e55ae39906bcc105a37aabac6a7b4f84e57a 100644 (file)
@@ -34,7 +34,8 @@ static const unsigned CodeModelLargeSize = 256;
                              Mangler &Mang,
                              const TargetMachine &TM) const override;
 
-    const MCSection *getSectionForConstant(SectionKind Kind) const override;
+    const MCSection *getSectionForConstant(SectionKind Kind,
+                                           const Constant *C) const override;
   };
 } // end namespace llvm
 
index 26318dd6c55857c5d4d722f19a4a0e8f5158f98d..3682165e3a25e4fffcc8f0b2ea2a573d140d3daf 100644 (file)
@@ -1,12 +1,13 @@
-; RUN: llc < %s -mtriple=x86_64-linux -mcpu=corei7 | FileCheck %s
-; RUN: llc < %s -mtriple=x86_64-win32 -mcpu=corei7 | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-linux -mcpu=corei7 | FileCheck %s --check-prefix=COMMON --check-prefix=LINUX
+; RUN: llc < %s -mtriple=x86_64-win32 -mcpu=corei7 | FileCheck %s --check-prefix=COMMON --check-prefix=MSVC
 
 ; llc should share constant pool entries between this integer vector
 ; and this floating-point vector since they have the same encoding.
 
-; CHECK:  LCPI0_0(%rip), %xmm0
-; CHECK:  movaps        %xmm0, ({{%rdi|%rcx}})
-; CHECK:  movaps        %xmm0, ({{%rsi|%rdx}})
+; LINUX:   LCPI0_0(%rip), %xmm0
+; MSVC:    __xmm@40000000400000004000000040000000(%rip), %xmm0
+; COMMON:  movaps        %xmm0, ({{%rdi|%rcx}})
+; COMMON:  movaps        %xmm0, ({{%rsi|%rdx}})
 
 define void @foo(<4 x i32>* %p, <4 x float>* %q, i1 %t) nounwind {
 entry:
diff --git a/test/CodeGen/X86/win_cst_pool.ll b/test/CodeGen/X86/win_cst_pool.ll
new file mode 100644 (file)
index 0000000..7bc046d
--- /dev/null
@@ -0,0 +1,49 @@
+; RUN: llc < %s -mtriple=x86_64-win32 -mcpu=corei7 | FileCheck %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define double @double() {
+  ret double 0x0000000000800000
+}
+; CHECK:              .globl  __real@0000000000800000
+; CHECK-NEXT:         .section        .rdata,"rd",discard,__real@0000000000800000
+; CHECK-NEXT:         .align  8
+; CHECK-NEXT: __real@0000000000800000:
+; CHECK-NEXT:         .quad   8388608
+; CHECK:      double:
+; CHECK:               movsd   __real@0000000000800000(%rip), %xmm0
+; CHECK-NEXT:          ret
+
+define <4 x i32> @vec1() {
+  ret <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+}
+; CHECK:              .globl  __xmm@00000000000000010000000200000003
+; CHECK-NEXT:         .section        .rdata,"rd",discard,__xmm@00000000000000010000000200000003
+; CHECK-NEXT:         .align  16
+; CHECK-NEXT: __xmm@00000000000000010000000200000003:
+; CHECK-NEXT:         .long   3
+; CHECK-NEXT:         .long   2
+; CHECK-NEXT:         .long   1
+; CHECK-NEXT:         .long   0
+; CHECK:      vec1:
+; CHECK:               movaps  __xmm@00000000000000010000000200000003(%rip), %xmm0
+; CHECK-NEXT:          ret
+
+define <8 x i16> @vec2() {
+  ret <8 x i16> <i16 7, i16 6, i16 5, i16 4, i16 3, i16 2, i16 1, i16 0>
+}
+; CHECK:             .globl  __xmm@00000001000200030004000500060007
+; CHECK-NEXT:        .section        .rdata,"rd",discard,__xmm@00000001000200030004000500060007
+; CHECK-NEXT:        .align  16
+; CHECK-NEXT: __xmm@00000001000200030004000500060007:
+; CHECK-NEXT:        .short  7
+; CHECK-NEXT:        .short  6
+; CHECK-NEXT:        .short  5
+; CHECK-NEXT:        .short  4
+; CHECK-NEXT:        .short  3
+; CHECK-NEXT:        .short  2
+; CHECK-NEXT:        .short  1
+; CHECK-NEXT:        .short  0
+; CHECK:      vec2:
+; CHECK:               movaps  __xmm@00000001000200030004000500060007(%rip), %xmm0
+; CHECK-NEXT:          ret