OSDN Git Service

Subzero: Partial implementation of global initializers.
authorJim Stichnoth <stichnot@chromium.org>
Sun, 29 Jun 2014 15:13:48 +0000 (08:13 -0700)
committerJim Stichnoth <stichnot@chromium.org>
Sun, 29 Jun 2014 15:13:48 +0000 (08:13 -0700)
This is still missing a couple things:

1. It only supports flat arrays and zeroinitializers.  Arrays of structs are not yet supported.

2. Initializers can't yet contain relocatables, e.g. the address of another global.Mod

Some changes are made to work around an llvm-mc assembler bug.  When assembling using intel syntax, llvm-mc doesn't correctly parse symbolic constants or add relocation entries in some circumstances.  Call instructions work, and use in a memory operand works, e.g. mov eax, [ArrayBase+4*ecx].  To work around this, we adjust legalize() to not allow ConstantRelocatable by default, except for memory operands and when called from lowerCall(), so the relocatable ends up being the source operand of a mov instruction.  Then, the mov emit routine actually emits an lea instruction for such moves.

A few lit tests needed to be adjusted to make szdiff work properly with respect to global initializers.

In the new cross test, the driver calls test code that returns a pointer to an array with a global initializer, and the driver compares the arrays returned by llc and Subzero.

BUG= none
R=jvoung@chromium.org

Review URL: https://codereview.chromium.org/358013003

16 files changed:
crosstest/runtests.sh
crosstest/test_global.cpp [new file with mode: 0644]
crosstest/test_global.h [new file with mode: 0644]
crosstest/test_global_main.cpp [new file with mode: 0644]
src/IceInstX8632.cpp
src/IceTargetLowering.cpp
src/IceTargetLowering.h
src/IceTargetLoweringX8632.cpp
src/IceTargetLoweringX8632.h
src/llvm2ice.cpp
szdiff.py
tests_lit/llvm2ice_tests/convert.ll
tests_lit/llvm2ice_tests/global.ll
tests_lit/llvm2ice_tests/globalinit.pnacl.ll [new file with mode: 0644]
tests_lit/llvm2ice_tests/nacl-atomic-fence-all.ll
tests_lit/llvm2ice_tests/shift.ll

index d89e1b9..0bc4cf2 100755 (executable)
@@ -51,6 +51,13 @@ for optlevel in ${OPTLEVELS} ; do
     ./crosstest.py -O${optlevel} --prefix=Subzero_ --target=x8632 \
         --dir="${OUTDIR}" \
         --llvm-bin-path="${LLVM_BIN_PATH}" \
+        --test=test_global.cpp \
+        --driver=test_global_main.cpp \
+        --output=test_global_O${optlevel}
+
+    ./crosstest.py -O${optlevel} --prefix=Subzero_ --target=x8632 \
+        --dir="${OUTDIR}" \
+        --llvm-bin-path="${LLVM_BIN_PATH}" \
         --test=test_icmp.cpp \
         --driver=test_icmp_main.cpp \
         --output=test_icmp_O${optlevel}
@@ -63,5 +70,6 @@ for optlevel in ${OPTLEVELS} ; do
     "${OUTDIR}"/test_arith_O${optlevel}
     "${OUTDIR}"/test_cast_O${optlevel}
     "${OUTDIR}"/test_fcmp_O${optlevel}
+    "${OUTDIR}"/test_global_O${optlevel}
     "${OUTDIR}"/test_icmp_O${optlevel}
 done
diff --git a/crosstest/test_global.cpp b/crosstest/test_global.cpp
new file mode 100644 (file)
index 0000000..a5a2f61
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdint.h>
+#include <cstdlib>
+
+#include "test_global.h"
+
+// Partially initialized array
+int ArrayInitPartial[10] = { 60, 70, 80, 90, 100 };
+int ArrayInitFull[] = { 10, 20, 30, 40, 50 };
+const int ArrayConst[] = { -10, -20, -30 };
+static double ArrayDouble[10] = { 0.5, 1.5, 2.5, 3.5 };
+
+#if 0
+#define ARRAY(a)                                                               \
+  { (uint8_t *)(a), sizeof(a) }
+
+struct {
+  uint8_t *ArrayAddress;
+  size_t ArraySizeInBytes;
+} Arrays[] = {
+  ARRAY(ArrayInitPartial),
+  ARRAY(ArrayInitFull),
+  ARRAY(ArrayConst),
+  ARRAY(ArrayDouble),
+};
+size_t NumArraysElements = sizeof(Arrays) / sizeof(*Arrays);
+#endif // 0
+
+size_t getNumArrays() {
+  return 4;
+  // return NumArraysElements;
+}
+
+const uint8_t *getArray(size_t WhichArray, size_t &Len) {
+  // Using a switch statement instead of a table lookup because such a
+  // table is represented as a kind of initializer that Subzero
+  // doesn't yet support.  Specifically, the table becomes constant
+  // aggregate data, and it contains relocations.  TODO(stichnot):
+  // switch over to the cleaner table-based method when global
+  // initializers are fully implemented.
+  switch (WhichArray) {
+  default:
+    Len = -1;
+    return NULL;
+  case 0:
+    Len = sizeof(ArrayInitPartial);
+    return (uint8_t *)&ArrayInitPartial;
+  case 1:
+    Len = sizeof(ArrayInitFull);
+    return (uint8_t *)&ArrayInitFull;
+  case 2:
+    Len = sizeof(ArrayConst);
+    return (uint8_t *)&ArrayConst;
+  case 3:
+    Len = sizeof(ArrayDouble);
+    return (uint8_t *)&ArrayDouble;
+  }
+#if 0
+  if (WhichArray >= NumArraysElements) {
+    Len = -1;
+    return NULL;
+  }
+  Len = Arrays[WhichArray].ArraySizeInBytes;
+  return Arrays[WhichArray].ArrayAddress;
+#endif // 0
+}
diff --git a/crosstest/test_global.h b/crosstest/test_global.h
new file mode 100644 (file)
index 0000000..dc7ff75
--- /dev/null
@@ -0,0 +1,2 @@
+size_t getNumArrays();
+const uint8_t *getArray(size_t WhichArray, size_t &Len);
diff --git a/crosstest/test_global_main.cpp b/crosstest/test_global_main.cpp
new file mode 100644 (file)
index 0000000..e533f99
--- /dev/null
@@ -0,0 +1,50 @@
+/* crosstest.py --test=test_global.cpp \
+   --driver=test_global_main.cpp --prefix=Subzero_ --output=test_global */
+
+#include <stdint.h>
+#include <cstdlib>
+#include <iostream>
+
+#include "test_global.h"
+namespace Subzero_ {
+#include "test_global.h"
+}
+
+int main(int argc, char **argv) {
+  size_t TotalTests = 0;
+  size_t Passes = 0;
+  size_t Failures = 0;
+
+  const uint8_t *SzArray, *LlcArray;
+  size_t SzArrayLen, LlcArrayLen;
+
+  size_t NumArrays = getNumArrays();
+  for (size_t i = 0; i < NumArrays; ++i) {
+    LlcArrayLen = -1;
+    SzArrayLen = -2;
+    LlcArray = getArray(i, LlcArrayLen);
+    SzArray = Subzero_::getArray(i, SzArrayLen);
+    if (LlcArrayLen == SzArrayLen) {
+      ++Passes;
+    } else {
+      std::cout << i << ":LlcArrayLen=" << LlcArrayLen
+                << ", SzArrayLen=" << SzArrayLen << std::endl;
+      ++Failures;
+    }
+
+    for (size_t i = 0; i < LlcArrayLen; ++i) {
+      if (LlcArray[i] == SzArray[i]) {
+        ++Passes;
+      } else {
+        ++Failures;
+        std::cout << i << ":LlcArray[" << i << "] = " << (int)LlcArray[i]
+                  << ", SzArray[" << i << "] = " << (int)SzArray[i]
+                  << std::endl;
+      }
+    }
+  }
+
+  std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
+            << " Failures=" << Failures << "\n";
+  return Failures;
+}
index 376d454..b983c3e 100644 (file)
@@ -655,8 +655,21 @@ void InstX8632StoreQ::dump(const Cfg *Func) const {
 void InstX8632Mov::emit(const Cfg *Func) const {
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(getSrcSize() == 1);
-  Str << "\tmov" << TypeX8632Attributes[getDest()->getType()].SdSsString
-      << "\t";
+  Operand *Src = getSrc(0);
+  // The llvm-mc assembler using Intel syntax has a bug in which "mov
+  // reg, RelocatableConstant" does not generate the right instruction
+  // with a relocation.  To work around, we emit "lea reg,
+  // [RelocatableConstant]".  Also, the lowering and legalization is
+  // changed to allow relocatable constants only in Assign and Call
+  // instructions or in Mem operands.  TODO(stichnot): remove LEAHACK
+  // once a proper emitter is used.
+  bool UseLeaHack = llvm::isa<ConstantRelocatable>(Src);
+  Str << "\t";
+  if (UseLeaHack)
+    Str << "lea";
+  else
+    Str << "mov" << TypeX8632Attributes[getDest()->getType()].SdSsString;
+  Str << "\t";
   // For an integer truncation operation, src is wider than dest.
   // Ideally, we use a mov instruction whose data width matches the
   // narrower dest.  This is a problem if e.g. src is a register like
@@ -665,10 +678,10 @@ void InstX8632Mov::emit(const Cfg *Func) const {
   // for stack-allocated dest variables because typeWidthOnStack()
   // pads to a 4-byte boundary even if only a lower portion is used.
   assert(Func->getTarget()->typeWidthInBytesOnStack(getDest()->getType()) ==
-         Func->getTarget()->typeWidthInBytesOnStack(getSrc(0)->getType()));
-  getDest()->asType(getSrc(0)->getType()).emit(Func);
+         Func->getTarget()->typeWidthInBytesOnStack(Src->getType()));
+  getDest()->asType(Src->getType()).emit(Func);
   Str << ", ";
-  getSrc(0)->emit(Func);
+  Src->emit(Func);
   Str << "\n";
 }
 
index 877f717..d29506e 100644 (file)
@@ -174,4 +174,23 @@ void TargetLowering::regAlloc() {
   LinearScan.scan(RegMask);
 }
 
+TargetGlobalInitLowering *
+TargetGlobalInitLowering::createLowering(TargetArch Target,
+                                         GlobalContext *Ctx) {
+  // These statements can be #ifdef'd to specialize the code generator
+  // to a subset of the available targets.  TODO: use CRTP.
+  if (Target == Target_X8632)
+    return TargetGlobalInitX8632::create(Ctx);
+#if 0
+  if (Target == Target_X8664)
+    return IceTargetGlobalInitX8664::create(Ctx);
+  if (Target == Target_ARM32)
+    return IceTargetGlobalInitARM32::create(Ctx);
+  if (Target == Target_ARM64)
+    return IceTargetGlobalInitARM64::create(Ctx);
+#endif
+  llvm_unreachable("Unsupported target");
+  return NULL;
+}
+
 } // end of namespace Ice
index dbb9a42..ddb66fa 100644 (file)
@@ -199,6 +199,29 @@ private:
   TargetLowering &operator=(const TargetLowering &) LLVM_DELETED_FUNCTION;
 };
 
+// TargetGlobalInitLowering is used for "lowering" global
+// initializers.  It is separated out from TargetLowering because it
+// does not require a Cfg.
+class TargetGlobalInitLowering {
+public:
+  static TargetGlobalInitLowering *createLowering(TargetArch Target,
+                                                  GlobalContext *Ctx);
+  // TODO: Allow relocations to be represented as part of the Data.
+  virtual void lower(const IceString &Name, SizeT Align, bool IsInternal,
+                     bool IsConst, bool IsZeroInitializer, SizeT Size,
+                     const char *Data, bool DisableTranslation) = 0;
+
+protected:
+  TargetGlobalInitLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
+  GlobalContext *Ctx;
+
+private:
+  TargetGlobalInitLowering(const TargetGlobalInitLowering &)
+  LLVM_DELETED_FUNCTION;
+  TargetGlobalInitLowering &
+  operator=(const TargetGlobalInitLowering &) LLVM_DELETED_FUNCTION;
+};
+
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERING_H
index ef9bc22..fec2d62 100644 (file)
@@ -1319,7 +1319,9 @@ void TargetX8632::lowerCall(const InstCall *Instr) {
       break;
     }
   }
-  Operand *CallTarget = legalize(Instr->getCallTarget());
+  // TODO(stichnot): LEAHACK: remove Legal_All (and use default) once
+  // a proper emitter is used.
+  Operand *CallTarget = legalize(Instr->getCallTarget(), Legal_All);
   Inst *NewCall = InstX8632Call::create(Func, eax, CallTarget);
   Context.insert(NewCall);
   if (edx)
@@ -2445,11 +2447,19 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
       // need to go in uninitialized registers.
       From = Ctx->getConstantZero(From->getType());
     }
-    bool NeedsReg =
-        !(Allowed & Legal_Imm) ||
-        // ConstantFloat and ConstantDouble are actually memory operands.
-        (!(Allowed & Legal_Mem) &&
-         (From->getType() == IceType_f32 || From->getType() == IceType_f64));
+    bool NeedsReg = false;
+    if (!(Allowed & Legal_Imm))
+      // Immediate specifically not allowed
+      NeedsReg = true;
+    // TODO(stichnot): LEAHACK: remove Legal_Reloc once a proper
+    // emitter is used.
+    if (!(Allowed & Legal_Reloc) && llvm::isa<ConstantRelocatable>(From))
+      // Relocatable specifically not allowed
+      NeedsReg = true;
+    if (!(Allowed & Legal_Mem) &&
+        (From->getType() == IceType_f32 || From->getType() == IceType_f64))
+      // On x86, FP constants are lowered to mem operands.
+      NeedsReg = true;
     if (NeedsReg) {
       Variable *Reg = makeReg(From->getType(), RegNum);
       _mov(Reg, From);
@@ -2581,4 +2591,100 @@ template <> void ConstantDouble::emit(GlobalContext *Ctx) const {
   Str << "qword ptr [L$" << IceType_f64 << "$" << getPoolEntryID() << "]";
 }
 
+TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx)
+    : TargetGlobalInitLowering(Ctx) {}
+
+namespace {
+char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
+}
+
+void TargetGlobalInitX8632::lower(const IceString &Name, SizeT Align,
+                                  bool IsInternal, bool IsConst,
+                                  bool IsZeroInitializer, SizeT Size,
+                                  const char *Data, bool DisableTranslation) {
+  if (Ctx->isVerbose()) {
+    // TODO: Consider moving the dump output into the driver to be
+    // reused for all targets.
+    Ostream &Str = Ctx->getStrDump();
+    Str << "@" << Name << " = " << (IsInternal ? "internal" : "external");
+    Str << (IsConst ? " constant" : " global");
+    Str << " [" << Size << " x i8] ";
+    if (IsZeroInitializer) {
+      Str << "zeroinitializer";
+    } else {
+      Str << "c\"";
+      // Code taken from PrintEscapedString() in AsmWriter.cpp.  Keep
+      // the strings in the same format as the .ll file for practical
+      // diffing.
+      for (uint64_t i = 0; i < Size; ++i) {
+        unsigned char C = Data[i];
+        if (isprint(C) && C != '\\' && C != '"')
+          Str << C;
+        else
+          Str << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
+      }
+      Str << "\"";
+    }
+    Str << ", align " << Align << "\n";
+  }
+
+  if (DisableTranslation)
+    return;
+
+  Ostream &Str = Ctx->getStrEmit();
+  // constant:
+  //   .section .rodata,"a",@progbits
+  //   .align ALIGN
+  //   .byte ...
+  //   .size NAME, SIZE
+
+  // non-constant:
+  //   .data
+  //   .align ALIGN
+  //   .byte ...
+  //   .size NAME, SIZE
+
+  // zeroinitializer (constant):
+  //   (.section or .data as above)
+  //   .align ALIGN
+  //   .zero SIZE
+  //   .size NAME, SIZE
+
+  // zeroinitializer (non-constant):
+  //   (.section or .data as above)
+  //   .comm NAME, SIZE, ALIGN
+  //   .local NAME
+
+  IceString MangledName = Ctx->mangleName(Name);
+  // Start a new section.
+  if (IsConst) {
+    Str << "\t.section\t.rodata,\"a\",@progbits\n";
+  } else {
+    Str << "\t.type\t" << MangledName << ",@object\n";
+    Str << "\t.data\n";
+  }
+  if (IsZeroInitializer) {
+    if (IsConst) {
+      Str << "\t.align\t" << Align << "\n";
+      Str << MangledName << ":\n";
+      Str << "\t.zero\t" << Size << "\n";
+      Str << "\t.size\t" << MangledName << ", " << Size << "\n";
+    } else {
+      // TODO(stichnot): Put the appropriate non-constant
+      // zeroinitializers in a .bss section to reduce object size.
+      Str << "\t.comm\t" << MangledName << ", " << Size << ", " << Align
+          << "\n";
+    }
+  } else {
+    Str << "\t.align\t" << Align << "\n";
+    Str << MangledName << ":\n";
+    for (SizeT i = 0; i < Size; ++i) {
+      Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
+    }
+    Str << "\t.size\t" << MangledName << ", " << Size << "\n";
+  }
+  Str << "\t" << (IsInternal ? ".local" : ".global") << "\t" << MangledName
+      << "\n";
+}
+
 } // end of namespace Ice
index 972b29f..521c36e 100644 (file)
@@ -109,10 +109,13 @@ protected:
     Legal_Reg = 1 << 0, // physical register, not stack location
     Legal_Imm = 1 << 1,
     Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12]
+    // TODO(stichnot): LEAHACK: remove Legal_Reloc once a proper
+    // emitter is used.
+    Legal_Reloc = 1 << 3,
     Legal_All = ~Legal_None
   };
   typedef uint32_t LegalMask;
-  Operand *legalize(Operand *From, LegalMask Allowed = Legal_All,
+  Operand *legalize(Operand *From, LegalMask Allowed = Legal_All & ~Legal_Reloc,
                     bool AllowOverlap = false,
                     int32_t RegNum = Variable::NoRegister);
   Variable *legalizeToVar(Operand *From, bool AllowOverlap = false,
@@ -291,6 +294,25 @@ private:
   template <typename T> void emitConstantPool() const;
 };
 
+class TargetGlobalInitX8632 : public TargetGlobalInitLowering {
+public:
+  static TargetGlobalInitLowering *create(GlobalContext *Ctx) {
+    return new TargetGlobalInitX8632(Ctx);
+  }
+  virtual void lower(const IceString &Name, SizeT Align, bool IsInternal,
+                     bool IsConst, bool IsZeroInitializer, SizeT Size,
+                     const char *Data, bool DisableTranslation);
+
+protected:
+  TargetGlobalInitX8632(GlobalContext *Ctx);
+
+private:
+  TargetGlobalInitX8632(const TargetGlobalInitX8632 &) LLVM_DELETED_FUNCTION;
+  TargetGlobalInitX8632 &
+  operator=(const TargetGlobalInitX8632 &) LLVM_DELETED_FUNCTION;
+  virtual ~TargetGlobalInitX8632() {}
+};
+
 template <> void ConstantFloat::emit(GlobalContext *Ctx) const;
 template <> void ConstantDouble::emit(GlobalContext *Ctx) const;
 
index 01d4f9b..6d26cff 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+#include "IceCfg.h"
 #include "IceConverter.h"
 #include "IceDefs.h"
+#include "IceTargetLowering.h"
 #include "IceTypes.h"
 
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
 #include "llvm/IRReader/IRReader.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/raw_os_ostream.h"
@@ -94,9 +99,10 @@ static cl::opt<NaClFileFormat> InputFileFormat(
                clEnumValEnd),
     cl::init(LLVMFormat));
 
-static cl::opt<bool> BuildOnRead(
-    "build-on-read", cl::desc("Build ICE instructions when reading bitcode"),
-    cl::init(false));
+static cl::opt<bool>
+BuildOnRead("build-on-read",
+            cl::desc("Build ICE instructions when reading bitcode"),
+            cl::init(false));
 
 int main(int argc, char **argv) {
 
@@ -129,8 +135,8 @@ int main(int argc, char **argv) {
     // Parse the input LLVM IR file into a module.
     SMDiagnostic Err;
     Ice::Timer T;
-    Module *Mod = NaClParseIRFile(IRFilename, InputFileFormat, Err,
-                                  getGlobalContext());
+    Module *Mod =
+        NaClParseIRFile(IRFilename, InputFileFormat, Err, getGlobalContext());
 
     if (SubzeroTimingEnabled) {
       std::cerr << "[Subzero timing] IR Parsing: " << T.getElapsedSec()
@@ -142,6 +148,47 @@ int main(int argc, char **argv) {
       return 1;
     }
 
+    // TODO(stichnot): Move this into IceConverter.cpp.
+    OwningPtr<Ice::TargetGlobalInitLowering> GlobalLowering(
+        Ice::TargetGlobalInitLowering::createLowering(TargetArch, &Ctx));
+    for (Module::const_global_iterator I = Mod->global_begin(),
+                                       E = Mod->global_end();
+         I != E; ++I) {
+      if (!I->hasInitializer())
+        continue;
+      const Constant *Initializer = I->getInitializer();
+      Ice::IceString Name = I->getName();
+      unsigned Align = I->getAlignment();
+      uint64_t NumElements = 0;
+      const char *Data = NULL;
+      bool IsInternal = I->hasInternalLinkage();
+      bool IsConst = I->isConstant();
+      bool IsZeroInitializer = false;
+
+      if (const ConstantDataArray *CDA =
+              dyn_cast<ConstantDataArray>(Initializer)) {
+        NumElements = CDA->getNumElements();
+        assert(isa<IntegerType>(CDA->getElementType()) &&
+               cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8);
+        Data = CDA->getRawDataValues().data();
+      } else if (isa<ConstantAggregateZero>(Initializer)) {
+        if (const ArrayType *AT = dyn_cast<ArrayType>(Initializer->getType())) {
+          assert(isa<IntegerType>(AT->getElementType()) &&
+                 cast<IntegerType>(AT->getElementType())->getBitWidth() == 8);
+          NumElements = AT->getNumElements();
+          IsZeroInitializer = true;
+        } else {
+          llvm_unreachable("Unhandled constant aggregate zero type");
+        }
+      } else {
+        llvm_unreachable("Unhandled global initializer");
+      }
+
+      GlobalLowering->lower(Name, Align, IsInternal, IsConst, IsZeroInitializer,
+                            NumElements, Data, DisableTranslation);
+    }
+    GlobalLowering.reset();
+
     Ice::Converter Converter(&Ctx, DisableInternal, SubzeroTimingEnabled,
                              DisableTranslation);
     return Converter.convertToIce(Mod);
index 046982e..b25681f 100755 (executable)
--- a/szdiff.py
+++ b/szdiff.py
@@ -42,7 +42,12 @@ if __name__ == '__main__':
     llc_out = []
     tail_call = re.compile(' tail call ');
     trailing_comment = re.compile(';.*')
-    ignore_pattern = re.compile('^ *$|^declare|^@')
+    ignore_pattern = re.compile('|'.join([
+                '^ *$',     # all-whitespace lines
+                '^declare', # declarations without definitions
+                '^@.*\]$'   # PNaCl global declarations like:
+                            #   @v = external global [4 x i8]
+                ]))
     prev_line = None
     for line in bitcode:
         if prev_line:
index 144d38a..61426a3 100644 (file)
@@ -7,14 +7,14 @@
 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
 ; RUN:                           | FileCheck --check-prefix=DUMP %s
 
-@i8v = global [1 x i8] zeroinitializer, align 1
-@i16v = global [2 x i8] zeroinitializer, align 2
-@i32v = global [4 x i8] zeroinitializer, align 4
-@i64v = global [8 x i8] zeroinitializer, align 8
-@u8v = global [1 x i8] zeroinitializer, align 1
-@u16v = global [2 x i8] zeroinitializer, align 2
-@u32v = global [4 x i8] zeroinitializer, align 4
-@u64v = global [8 x i8] zeroinitializer, align 8
+@i8v = internal global [1 x i8] zeroinitializer, align 1
+@i16v = internal global [2 x i8] zeroinitializer, align 2
+@i32v = internal global [4 x i8] zeroinitializer, align 4
+@i64v = internal global [8 x i8] zeroinitializer, align 8
+@u8v = internal global [1 x i8] zeroinitializer, align 1
+@u16v = internal global [2 x i8] zeroinitializer, align 2
+@u32v = internal global [4 x i8] zeroinitializer, align 4
+@u64v = internal global [8 x i8] zeroinitializer, align 8
 
 define void @from_int8() {
 entry:
index ba5471e..0d791cc 100644 (file)
@@ -1,14 +1,11 @@
 ; Trivial test of the use of internal versus external global
-; functions.
+; variables.
 
 ; RUN: %llvm2ice --verbose inst %s | FileCheck %s
 ; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
 ; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
 
-; Note: We don't run this test using a PNaCl bitcode file, because
-; external globals are not in the PNaCl ABI.
-
-@intern_global = global [4 x i8] [i8 0, i8 0, i8 0, i8 12], align 4
+@intern_global = internal global [4 x i8] c"\00\00\00\0C", align 4
 @extern_global = external global [4 x i8]
 
 define i32 @test_intern_global() {
diff --git a/tests_lit/llvm2ice_tests/globalinit.pnacl.ll b/tests_lit/llvm2ice_tests/globalinit.pnacl.ll
new file mode 100644 (file)
index 0000000..593c5e4
--- /dev/null
@@ -0,0 +1,103 @@
+; Test of global initializers.
+
+; RUN: %llvm2ice --verbose inst %s | FileCheck %s
+; RUN: %llvm2ice --verbose none %s | FileCheck --check-prefix=ERRORS %s
+; RUN: %llvm2iceinsts %s | %szdiff %s | FileCheck --check-prefix=DUMP %s
+
+@PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
+; CHECK: .data
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: PrimitiveInit:
+; CHECK-NEXT: .byte
+; CHECK: .size PrimitiveInit, 4
+
+@PrimitiveInitConst = internal constant [4 x i8] c"\0D\00\00\00", align 4
+; CHECK: .section .rodata,"a",@progbits
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: PrimitiveInitConst:
+; CHECK-NEXT: .byte
+; CHECK: .size PrimitiveInitConst, 4
+
+@ArrayInit = internal global [20 x i8] c"\0A\00\00\00\14\00\00\00\1E\00\00\00(\00\00\002\00\00\00", align 4
+; CHECK: .data
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ArrayInit:
+; CHECK-NEXT: .byte
+; CHECK: .size ArrayInit, 20
+
+@ArrayInitPartial = internal global [40 x i8] c"<\00\00\00F\00\00\00P\00\00\00Z\00\00\00d\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", align 4
+; CHECK: .data
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ArrayInitPartial:
+; CHECK-NEXT: .byte
+; CHECK: .size ArrayInitPartial, 40
+
+@PrimitiveInitStatic = internal global [4 x i8] zeroinitializer, align 4
+; CHECK: .data
+; CHECK-NEXT: .comm PrimitiveInitStatic, 4, 4
+; CHECK-NEXT: .local PrimitiveInitStatic
+
+@PrimitiveUninit = internal global [4 x i8] zeroinitializer, align 4
+; CHECK: .data
+; CHECK-NEXT: .comm PrimitiveUninit, 4, 4
+; CHECK-NEXT: .local PrimitiveUninit
+
+@ArrayUninit = internal global [20 x i8] zeroinitializer, align 4
+; CHECK: .data
+; CHECK-NEXT: .comm ArrayUninit, 20, 4
+; CHECK-NEXT: .local ArrayUninit
+
+@ArrayUninitConstDouble = internal constant [200 x i8] zeroinitializer, align 8
+; CHECK: .section .rodata,"a",@progbits
+; CHECK-NEXT: .align 8
+; CHECK-NEXT: ArrayUninitConstDouble:
+; CHECK-NEXT: .zero 200
+; CHECK-NEXT: .size ArrayUninitConstDouble, 200
+
+@ArrayUninitConstInt = internal constant [20 x i8] zeroinitializer, align 4
+; CHECK: .section .rodata,"a",@progbits
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ArrayUninitConstInt:
+; CHECK-NEXT: .zero 20
+; CHECK-NEXT: .size ArrayUninitConstInt, 20
+
+@__init_array_start = internal constant [0 x i8] zeroinitializer, align 4
+@__fini_array_start = internal constant [0 x i8] zeroinitializer, align 4
+@__tls_template_start = internal constant [0 x i8] zeroinitializer, align 8
+@__tls_template_alignment = internal constant [4 x i8] c"\01\00\00\00", align 4
+
+define internal i32 @main(i32 %argc, i32 %argv) {
+entry:
+  %expanded1 = ptrtoint [4 x i8]* @PrimitiveInit to i32
+  call void @use(i32 %expanded1)
+  %expanded3 = ptrtoint [4 x i8]* @PrimitiveInitConst to i32
+  call void @use(i32 %expanded3)
+  %expanded5 = ptrtoint [4 x i8]* @PrimitiveInitStatic to i32
+  call void @use(i32 %expanded5)
+  %expanded7 = ptrtoint [4 x i8]* @PrimitiveUninit to i32
+  call void @use(i32 %expanded7)
+  %expanded9 = ptrtoint [20 x i8]* @ArrayInit to i32
+  call void @use(i32 %expanded9)
+  %expanded11 = ptrtoint [40 x i8]* @ArrayInitPartial to i32
+  call void @use(i32 %expanded11)
+  %expanded13 = ptrtoint [20 x i8]* @ArrayUninit to i32
+  call void @use(i32 %expanded13)
+  ret i32 0
+}
+; CHECK: entry:
+
+declare void @use(i32)
+
+define internal i32 @nacl_tp_tdb_offset(i32 %__0) {
+entry:
+  ret i32 0
+}
+
+define internal i32 @nacl_tp_tls_offset(i32 %size) {
+entry:
+  %result = sub i32 0, %size
+  ret i32 %result
+}
+
+; ERRORS-NOT: ICE translation error
+; DUMP-NOT: SZ
index 32c5e85..6293e1a 100644 (file)
@@ -43,15 +43,15 @@ entry:
 ; CHECK: mov {{.*}}, esp
 ; CHECK: mov dword ptr {{.*}}, 999
 ;    atomic store (w/ its own mfence)
-; CHECK: mov {{.*}}, g32_a
+; CHECK: lea {{.*}}, g32_a
 ; The load + add are optimized into one everywhere.
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mov dword ptr
 ; CHECK: mfence
-; CHECK: mov {{.*}}, g32_b
+; CHECK: lea {{.*}}, g32_b
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mov dword ptr
-; CHECK: mov {{.*}}, g32_c
+; CHECK: lea {{.*}}, g32_c
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mfence
 ; CHECK: mov dword ptr
@@ -86,14 +86,14 @@ entry:
 ; CHECK: mov {{.*}}, esp
 ; CHECK: mov dword ptr {{.*}}, 999
 ;    atomic store (w/ its own mfence)
-; CHECK: mov {{.*}}, g32_a
+; CHECK: lea {{.*}}, g32_a
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mov dword ptr
 ; CHECK: mfence
-; CHECK: mov {{.*}}, g32_b
+; CHECK: lea {{.*}}, g32_b
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mov dword ptr
-; CHECK: mov {{.*}}, g32_c
+; CHECK: lea {{.*}}, g32_c
 ; CHECK: mfence
 ; Load + add can still be optimized into one instruction
 ; because it is not separated by a fence.
@@ -130,11 +130,11 @@ entry:
 ; CHECK: mov {{.*}}, esp
 ; CHECK: mov dword ptr {{.*}}, 999
 ;    atomic store (w/ its own mfence)
-; CHECK: mov {{.*}}, g32_a
+; CHECK: lea {{.*}}, g32_a
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mov dword ptr
 ; CHECK: mfence
-; CHECK: mov {{.*}}, g32_b
+; CHECK: lea {{.*}}, g32_b
 ; This load + add are no longer optimized into one,
 ; though perhaps it should be legal as long as
 ; the load stays on the same side of the fence.
@@ -142,7 +142,7 @@ entry:
 ; CHECK: mfence
 ; CHECK: add {{.*}}, 1
 ; CHECK: mov dword ptr
-; CHECK: mov {{.*}}, g32_c
+; CHECK: lea {{.*}}, g32_c
 ; CHECK: add {{.*}}, dword ptr
 ; CHECK: mov dword ptr
 
@@ -182,7 +182,7 @@ entry:
   ret i32 %b1234
 }
 ; CHECK-LABEL: could_have_fused_loads
-; CHECK: mov {{.*}}, g32_d
+; CHECK: lea {{.*}}, g32_d
 ; CHECK: mov {{.*}}, byte ptr
 ; CHECK: mov {{.*}}, byte ptr
 ; CHECK: mov {{.*}}, byte ptr
@@ -206,7 +206,7 @@ branch2:
   ret i32 %z
 }
 ; CHECK-LABEL: could_have_hoisted_loads
-; CHECK: mov {{.*}}, g32_d
+; CHECK: lea {{.*}}, g32_d
 ; CHECK: je {{.*}}
 ; CHECK: jmp {{.*}}
 ; CHECK: mov {{.*}}, dword ptr
index 2ec187d..5ce07dd 100644 (file)
@@ -8,9 +8,9 @@
 ; RUN: %llvm2iceinsts --pnacl %s | %szdiff %s \
 ; RUN:                           | FileCheck --check-prefix=DUMP %s
 
-@i1 = global [4 x i8] zeroinitializer, align 4
-@i2 = global [4 x i8] zeroinitializer, align 4
-@u1 = global [4 x i8] zeroinitializer, align 4
+@i1 = internal global [4 x i8] zeroinitializer, align 4
+@i2 = internal global [4 x i8] zeroinitializer, align 4
+@u1 = internal global [4 x i8] zeroinitializer, align 4
 
 define void @conv1() {
 entry: