./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}
"${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
--- /dev/null
+#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
+}
--- /dev/null
+size_t getNumArrays();
+const uint8_t *getArray(size_t WhichArray, size_t &Len);
--- /dev/null
+/* 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;
+}
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
// 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";
}
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
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
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)
// 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);
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
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,
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;
//
//===----------------------------------------------------------------------===//
+#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"
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) {
// 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()
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);
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:
; 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:
; 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() {
--- /dev/null
+; 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
; 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
; 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.
; 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.
; 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
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
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
; 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: