Commit de4ca71e by Jim Stichnoth

Subzero: Partial implementation of global initializers.

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
parent e1e013cf
......@@ -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
#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
}
size_t getNumArrays();
const uint8_t *getArray(size_t WhichArray, size_t &Len);
/* 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;
}
......@@ -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";
}
......
......@@ -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
......@@ -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
......@@ -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
......@@ -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;
......
......@@ -13,11 +13,16 @@
//
//===----------------------------------------------------------------------===//
#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);
......
......@@ -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:
......
......@@ -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:
......
; 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() {
......
; 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
......@@ -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
......
......@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment