Commit e3f64d09 by Karl Schimpf

Introduce model of global initializers in Subzero.

Modifies both LLVM to ICE converter, and Subzero's bitcode reader, to build Subzero's global initializers. Modifies target lowering routines for global initializers to use this new model. Also modifies both to now handle relocations in global variable initializers. BUG=None R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/624663002
parent 8363a066
...@@ -80,6 +80,7 @@ SRCS= \ ...@@ -80,6 +80,7 @@ SRCS= \
IceCfgNode.cpp \ IceCfgNode.cpp \
IceConverter.cpp \ IceConverter.cpp \
IceGlobalContext.cpp \ IceGlobalContext.cpp \
IceGlobalInits.cpp \
IceInst.cpp \ IceInst.cpp \
IceInstX8632.cpp \ IceInstX8632.cpp \
IceIntrinsics.cpp \ IceIntrinsics.cpp \
......
...@@ -16,63 +16,75 @@ ...@@ -16,63 +16,75 @@
#include "test_global.h" #include "test_global.h"
// Note: The following take advantage of the fact that external global
// names are not mangled with the --prefix CL argument. Hence, they
// should have the same relocation value for both llc and Subzero.
extern uint8_t *ExternName1;
extern uint8_t *ExternName2;
extern uint8_t *ExternName3;
extern uint8_t *ExternName4;
extern uint8_t *ExternName5;
// Partially initialized array // Partially initialized array
int ArrayInitPartial[10] = { 60, 70, 80, 90, 100 }; int ArrayInitPartial[10] = {60, 70, 80, 90, 100};
int ArrayInitFull[] = { 10, 20, 30, 40, 50 }; int ArrayInitFull[] = {10, 20, 30, 40, 50};
const int ArrayConst[] = { -10, -20, -30 }; const int ArrayConst[] = {-10, -20, -30};
static double ArrayDouble[10] = { 0.5, 1.5, 2.5, 3.5 }; static double ArrayDouble[10] = { 0.5, 1.5, 2.5, 3.5 };
#if 0 #if 0
// TODO(kschimpf) Add this example once we know how to not mangle
// uninitialized, external globals (so that we can compare that
// the same, unmangled relocations are used). See comment in
// TargetGlobalInitX8632::lower in IceTargetLoweringX8632.cpp for
// details.
static struct {
int Array1[5];
uint8_t *Pointer1;
double Array2[3];
uint8_t *Pointer2;
struct {
uint8_t *Pointer3;
int Array1[3];
uint8_t *Pointer4;
} NestedStuff;
uint8_t *Pointer5;
} StructEx = {
{ 10, 20, 30, 40, 50 },
ExternName1,
{ 0.5, 1.5, 2.5 },
ExternName4,
{ ExternName3, {1000, 1010, 1020}, ExternName2 },
ExternName5,
};
#endif
#define ARRAY(a) \ #define ARRAY(a) \
{ (uint8_t *)(a), sizeof(a) } { (uint8_t *)(a), sizeof(a) }
// Note: By embedding the array addresses in this table, we are indirectly
// testing relocations (i.e. getArray would return the wrong address if
// relocations are broken).
struct { struct {
uint8_t *ArrayAddress; uint8_t *ArrayAddress;
size_t ArraySizeInBytes; size_t ArraySizeInBytes;
} Arrays[] = { } Arrays[] = {
ARRAY(ArrayInitPartial), ARRAY(ArrayInitPartial),
ARRAY(ArrayInitFull), ARRAY(ArrayInitFull),
ARRAY(ArrayConst), ARRAY(ArrayConst),
ARRAY(ArrayDouble), ARRAY(ArrayDouble),
{(uint8_t *)(ArrayInitPartial + 2),
sizeof(ArrayInitPartial) - 2 * sizeof(int)},
// { (uint8_t*)(&StructEx), sizeof(StructEx) },
}; };
size_t NumArraysElements = sizeof(Arrays) / sizeof(*Arrays); size_t NumArraysElements = sizeof(Arrays) / sizeof(*Arrays);
#endif // 0
size_t getNumArrays() { size_t getNumArrays() { return NumArraysElements; }
return 4;
// return NumArraysElements;
}
const uint8_t *getArray(size_t WhichArray, size_t &Len) { 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) { if (WhichArray >= NumArraysElements) {
Len = -1; Len = -1;
return NULL; return NULL;
} }
Len = Arrays[WhichArray].ArraySizeInBytes; Len = Arrays[WhichArray].ArraySizeInBytes;
return Arrays[WhichArray].ArrayAddress; return Arrays[WhichArray].ArrayAddress;
#endif // 0
} }
...@@ -104,6 +104,7 @@ if __name__ == '__main__': ...@@ -104,6 +104,7 @@ if __name__ == '__main__':
'-mattr=' + args.attr, '-mattr=' + args.attr,
'--target=' + args.target, '--target=' + args.target,
'--prefix=' + args.prefix, '--prefix=' + args.prefix,
'-allow-uninitialized-globals',
'-o=' + asm_sz, '-o=' + asm_sz,
bitcode]) bitcode])
shellcmd(['llvm-mc', shellcmd(['llvm-mc',
......
...@@ -24,18 +24,21 @@ public: ...@@ -24,18 +24,21 @@ public:
ClFlags() ClFlags()
: DisableInternal(false), SubzeroTimingEnabled(false), : DisableInternal(false), SubzeroTimingEnabled(false),
DisableTranslation(false), DisableGlobals(false), DisableTranslation(false), DisableGlobals(false),
FunctionSections(false), UseIntegratedAssembler(false), FunctionSections(false), DataSections(false),
UseSandboxing(false), DumpStats(false), TimeEachFunction(false), UseIntegratedAssembler(false), UseSandboxing(false), DumpStats(false),
DefaultGlobalPrefix(""), DefaultFunctionPrefix(""), TimingFocusOn(""), AllowUninitializedGlobals(false), TimeEachFunction(false),
DefaultGlobalPrefix(""), DefaultFunctionPrefix(""),TimingFocusOn(""),
VerboseFocusOn("") {} VerboseFocusOn("") {}
bool DisableInternal; bool DisableInternal;
bool SubzeroTimingEnabled; bool SubzeroTimingEnabled;
bool DisableTranslation; bool DisableTranslation;
bool DisableGlobals; bool DisableGlobals;
bool FunctionSections; bool FunctionSections;
bool DataSections;
bool UseIntegratedAssembler; bool UseIntegratedAssembler;
bool UseSandboxing; bool UseSandboxing;
bool DumpStats; bool DumpStats;
bool AllowUninitializedGlobals;
bool TimeEachFunction; bool TimeEachFunction;
IceString DefaultGlobalPrefix; IceString DefaultGlobalPrefix;
IceString DefaultFunctionPrefix; IceString DefaultFunctionPrefix;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "IceConverter.h" #include "IceConverter.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceGlobalContext.h" #include "IceGlobalContext.h"
#include "IceGlobalInits.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceTargetLowering.h" #include "IceTargetLowering.h"
...@@ -45,17 +46,34 @@ template <typename T> static std::string LLVMObjectAsString(const T *O) { ...@@ -45,17 +46,34 @@ template <typename T> static std::string LLVMObjectAsString(const T *O) {
return Stream.str(); return Stream.str();
} }
// Converter from LLVM to ICE. The entry point is the convertFunction method. // Base class for converting LLVM to ICE.
//
// Note: this currently assumes that the given IR was verified to be valid PNaCl
// bitcode:
// https://developers.google.com/native-client/dev/reference/pnacl-bitcode-abi
// If not, all kinds of assertions may fire.
//
class LLVM2ICEConverter { class LLVM2ICEConverter {
LLVM2ICEConverter(const LLVM2ICEConverter &) = delete;
LLVM2ICEConverter &operator=(const LLVM2ICEConverter &) = delete;
public: public:
LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext) LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: Ctx(Ctx), Func(NULL), TypeConverter(LLVMContext) {} : Ctx(Ctx), TypeConverter(LLVMContext) {}
protected:
// Data
Ice::GlobalContext *Ctx;
const Ice::TypeConverter TypeConverter;
};
// Converter from LLVM functions to ICE. The entry point is the
// convertFunction method.
//
// Note: this currently assumes that the given IR was verified to be
// valid PNaCl bitcode. Otherwise, the behavior is undefined.
class LLVM2ICEFunctionConverter : LLVM2ICEConverter {
LLVM2ICEFunctionConverter(const LLVM2ICEFunctionConverter &) = delete;
LLVM2ICEFunctionConverter &
operator=(const LLVM2ICEFunctionConverter &) = delete;
public:
LLVM2ICEFunctionConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: LLVM2ICEConverter(Ctx, LLVMContext), Func(NULL) {}
// Caller is expected to delete the returned Ice::Cfg object. // Caller is expected to delete the returned Ice::Cfg object.
Ice::Cfg *convertFunction(const Function *F) { Ice::Cfg *convertFunction(const Function *F) {
...@@ -91,17 +109,17 @@ public: ...@@ -91,17 +109,17 @@ public:
// Ice::Cfg pointer. As such, it's suitable for e.g. constructing // Ice::Cfg pointer. As such, it's suitable for e.g. constructing
// global initializers. // global initializers.
Ice::Constant *convertConstant(const Constant *Const) { Ice::Constant *convertConstant(const Constant *Const) {
if (const GlobalValue *GV = dyn_cast<GlobalValue>(Const)) { if (const auto GV = dyn_cast<GlobalValue>(Const)) {
return Ctx->getConstantSym(convertToIceType(GV->getType()), 0, return Ctx->getConstantSym(convertToIceType(GV->getType()), 0,
GV->getName()); GV->getName());
} else if (const ConstantInt *CI = dyn_cast<ConstantInt>(Const)) { } else if (const auto CI = dyn_cast<ConstantInt>(Const)) {
Ice::Type Ty = convertToIceType(CI->getType()); Ice::Type Ty = convertToIceType(CI->getType());
if (Ty == Ice::IceType_i64) { if (Ty == Ice::IceType_i64) {
return Ctx->getConstantInt64(Ty, CI->getSExtValue()); return Ctx->getConstantInt64(Ty, CI->getSExtValue());
} else { } else {
return Ctx->getConstantInt32(Ty, CI->getSExtValue()); return Ctx->getConstantInt32(Ty, CI->getSExtValue());
} }
} else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(Const)) { } else if (const auto CFP = dyn_cast<ConstantFP>(Const)) {
Ice::Type Type = convertToIceType(CFP->getType()); Ice::Type Type = convertToIceType(CFP->getType());
if (Type == Ice::IceType_f32) if (Type == Ice::IceType_f32)
return Ctx->getConstantFloat(CFP->getValueAPF().convertToFloat()); return Ctx->getConstantFloat(CFP->getValueAPF().convertToFloat());
...@@ -109,7 +127,7 @@ public: ...@@ -109,7 +127,7 @@ public:
return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble()); return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble());
llvm_unreachable("Unexpected floating point type"); llvm_unreachable("Unexpected floating point type");
return NULL; return NULL;
} else if (const UndefValue *CU = dyn_cast<UndefValue>(Const)) { } else if (const auto CU = dyn_cast<UndefValue>(Const)) {
return Ctx->getConstantUndef(convertToIceType(CU->getType())); return Ctx->getConstantUndef(convertToIceType(CU->getType()));
} else { } else {
llvm_unreachable("Unhandled constant type"); llvm_unreachable("Unhandled constant type");
...@@ -144,8 +162,8 @@ private: ...@@ -144,8 +162,8 @@ private:
Ice::Type convertToIceType(Type *LLVMTy) const { Ice::Type convertToIceType(Type *LLVMTy) const {
Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy); Ice::Type IceTy = TypeConverter.convertToIceType(LLVMTy);
if (IceTy == Ice::IceType_NUM) if (IceTy == Ice::IceType_NUM)
llvm::report_fatal_error(std::string("Invalid PNaCl type ") + report_fatal_error(std::string("Invalid PNaCl type ") +
LLVMObjectAsString(LLVMTy)); LLVMObjectAsString(LLVMTy));
return IceTy; return IceTy;
} }
...@@ -161,7 +179,7 @@ private: ...@@ -161,7 +179,7 @@ private:
} }
Ice::Operand *convertValue(const Value *Op) { Ice::Operand *convertValue(const Value *Op) {
if (const Constant *Const = dyn_cast<Constant>(Op)) { if (const auto Const = dyn_cast<Constant>(Op)) {
return convertConstant(Const); return convertConstant(Const);
} else { } else {
return mapValueToIceVar(Op); return mapValueToIceVar(Op);
...@@ -291,7 +309,7 @@ private: ...@@ -291,7 +309,7 @@ private:
Ice::Inst *convertArithInstruction(const Instruction *Inst, Ice::Inst *convertArithInstruction(const Instruction *Inst,
Ice::InstArithmetic::OpKind Opcode) { Ice::InstArithmetic::OpKind Opcode) {
const BinaryOperator *BinOp = cast<BinaryOperator>(Inst); const auto BinOp = cast<BinaryOperator>(Inst);
Ice::Operand *Src0 = convertOperand(Inst, 0); Ice::Operand *Src0 = convertOperand(Inst, 0);
Ice::Operand *Src1 = convertOperand(Inst, 1); Ice::Operand *Src1 = convertOperand(Inst, 1);
Ice::Variable *Dest = mapValueToIceVar(BinOp); Ice::Variable *Dest = mapValueToIceVar(BinOp);
...@@ -509,8 +527,7 @@ private: ...@@ -509,8 +527,7 @@ private:
Ice::InstCall *NewInst = NULL; Ice::InstCall *NewInst = NULL;
const Ice::Intrinsics::FullIntrinsicInfo *Info = NULL; const Ice::Intrinsics::FullIntrinsicInfo *Info = NULL;
if (Ice::ConstantRelocatable *Target = if (const auto Target = dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
llvm::dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
// Check if this direct call is to an Intrinsic (starts with "llvm.") // Check if this direct call is to an Intrinsic (starts with "llvm.")
static const char LLVMPrefix[] = "llvm."; static const char LLVMPrefix[] = "llvm.";
const size_t LLVMPrefixLen = strlen(LLVMPrefix); const size_t LLVMPrefixLen = strlen(LLVMPrefix);
...@@ -603,13 +620,179 @@ private: ...@@ -603,13 +620,179 @@ private:
private: private:
// Data // Data
Ice::GlobalContext *Ctx;
Ice::Cfg *Func; Ice::Cfg *Func;
std::map<const Value *, Ice::Variable *> VarMap; std::map<const Value *, Ice::Variable *> VarMap;
std::map<const BasicBlock *, Ice::CfgNode *> NodeMap; std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
Ice::TypeConverter TypeConverter;
}; };
// Converter from LLVM global variables to ICE. The entry point is the
// convertGlobalsToIce method.
//
// Note: this currently assumes that the given IR was verified to be
// valid PNaCl bitcode. Othewise, the behavior is undefined.
class LLVM2ICEGlobalsConverter : public LLVM2ICEConverter {
LLVM2ICEGlobalsConverter(const LLVM2ICEGlobalsConverter &) = delete;
LLVM2ICEGlobalsConverter &
operator-(const LLVM2ICEGlobalsConverter &) = delete;
public:
LLVM2ICEGlobalsConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: LLVM2ICEConverter(Ctx, LLVMContext) {}
~LLVM2ICEGlobalsConverter() { DeleteContainerSeconds(GlobalVarAddressMap); }
/// Converts global variables, and their initializers into ICE global
/// addresses, for module Mod. Puts corresponding converted global
/// addresses into GlobalAddresses.
void convertGlobalsToIce(Module *Mod,
Ice::Translator::GlobalAddressList &GlobalAddresses);
private:
typedef std::map<const GlobalVariable *, Ice::GlobalAddress *>
GlobalVarAddressMapType;
// Map from global variables to their corresponding global address.
GlobalVarAddressMapType GlobalVarAddressMap;
// Adds the Initializer to the list of initializers for Global address.
void addGlobalInitializer(Ice::GlobalAddress &Global,
const Constant *Initializer) {
const bool HasOffset = false;
const Ice::GlobalAddress::RelocOffsetType Offset = 0;
addGlobalInitializer(Global, Initializer, HasOffset, Offset);
}
// Adds Initializer to the list of initializers for Global
// address. HasOffset is true only if Initializer is a relocation
// initializer and Offset should be added to the relocation.
void addGlobalInitializer(Ice::GlobalAddress &Global,
const Constant *Initializer, bool HasOffset,
Ice::GlobalAddress::RelocOffsetType Offset);
// Returns the global address associated with global variable GV.
Ice::GlobalAddress *getGlobalVarAddress(const GlobalVariable *GV) {
if (GlobalVarAddressMap.find(GV) == GlobalVarAddressMap.end())
GlobalVarAddressMap[GV] = new Ice::GlobalAddress();
return GlobalVarAddressMap[GV];
}
// Converts the given constant C to the corresponding integer
// literal it contains.
Ice::GlobalAddress::RelocOffsetType
getIntegerLiteralConstant(const Value *C) {
const auto CI = dyn_cast<ConstantInt>(C);
if (CI && CI->getType()->isIntegerTy(32))
return CI->getSExtValue();
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Constant not i32 literal: " << *C;
report_fatal_error(StrBuf.str());
return 0;
}
};
void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
Module *Mod, Ice::Translator::GlobalAddressList &GlobalAddresses) {
for (Module::const_global_iterator I = Mod->global_begin(),
E = Mod->global_end();
I != E; ++I) {
if (!I->hasInitializer() && Ctx->getFlags().AllowUninitializedGlobals)
continue;
const auto GV = dyn_cast<GlobalVariable>(I);
assert(GV);
Ice::IceString Name = GV->getName();
if (!GV->hasInternalLinkage()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't define external global address: " << Name;
report_fatal_error(StrBuf.str());
}
Ice::GlobalAddress *Addr = getGlobalVarAddress(GV);
GlobalAddresses.push_back(Addr);
Addr->setAlignment(GV->getAlignment());
Addr->setIsConstant(GV->isConstant());
// Note: We allow external for cross tests.
Addr->setIsInternal(!GV->isExternallyInitialized());
Addr->setName(Name);
const Constant *Initializer = GV->getInitializer();
if (const auto CompoundInit = dyn_cast<ConstantStruct>(Initializer)) {
for (ConstantStruct::const_op_iterator I = CompoundInit->op_begin(),
E = CompoundInit->op_end();
I != E; ++I) {
if (const auto Init = dyn_cast<Constant>(I)) {
addGlobalInitializer(*Addr, Init);
}
}
} else {
addGlobalInitializer(*Addr, Initializer);
}
}
}
void LLVM2ICEGlobalsConverter::addGlobalInitializer(
Ice::GlobalAddress &Global, const Constant *Initializer, bool HasOffset,
Ice::GlobalAddress::RelocOffsetType Offset) {
assert(HasOffset || Offset == 0);
if (const auto CDA = dyn_cast<ConstantDataArray>(Initializer)) {
assert(!HasOffset && isa<IntegerType>(CDA->getElementType()) &&
(cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8));
Global.addInitializer(new Ice::GlobalAddress::DataInitializer(
CDA->getRawDataValues().data(), CDA->getNumElements()));
return;
}
if (isa<ConstantAggregateZero>(Initializer)) {
if (const auto AT = dyn_cast<ArrayType>(Initializer->getType())) {
assert(!HasOffset && isa<IntegerType>(AT->getElementType()) &&
(cast<IntegerType>(AT->getElementType())->getBitWidth() == 8));
Global.addInitializer(
new Ice::GlobalAddress::ZeroInitializer(AT->getNumElements()));
} else {
llvm_unreachable("Unhandled constant aggregate zero type");
}
return;
}
if (const auto Exp = dyn_cast<ConstantExpr>(Initializer)) {
switch (Exp->getOpcode()) {
case Instruction::Add:
assert(!HasOffset);
addGlobalInitializer(Global, Exp->getOperand(0), true,
getIntegerLiteralConstant(Exp->getOperand(1)));
return;
case Instruction::PtrToInt: {
assert(TypeConverter.convertToIceType(Exp->getType()) ==
TypeConverter.getIcePointerType());
const auto GV = dyn_cast<GlobalValue>(Exp->getOperand(0));
assert(GV);
if (const auto Fcn = dyn_cast<Function>(GV)) {
Ice::GlobalAddress::RelocationAddress Addr(Fcn);
Global.addInitializer(
new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
return;
} else if (const auto Var = dyn_cast<GlobalVariable>(GV)) {
Ice::GlobalAddress::RelocationAddress Addr(getGlobalVarAddress(Var));
Global.addInitializer(
new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
return;
}
break;
}
default:
break;
}
}
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Unhandled global initializer: " << Initializer;
report_fatal_error(StrBuf.str());
}
} // end of anonymous namespace } // end of anonymous namespace
namespace Ice { namespace Ice {
...@@ -617,22 +800,31 @@ namespace Ice { ...@@ -617,22 +800,31 @@ namespace Ice {
void Converter::convertToIce() { void Converter::convertToIce() {
TimerMarker T(TimerStack::TT_convertToIce, Ctx); TimerMarker T(TimerStack::TT_convertToIce, Ctx);
nameUnnamedGlobalAddresses(Mod); nameUnnamedGlobalAddresses(Mod);
nameUnnamedFunctions(Mod);
if (!Ctx->getFlags().DisableGlobals) if (!Ctx->getFlags().DisableGlobals)
convertGlobals(Mod); convertGlobals(Mod);
convertFunctions(); convertFunctions();
} }
void Converter::convertGlobals(Module *Mod) {
LLVM2ICEGlobalsConverter GlobalsConverter(Ctx, Mod->getContext());
Translator::GlobalAddressList GlobalAddresses;
GlobalsConverter.convertGlobalsToIce(Mod, GlobalAddresses);
lowerGlobals(GlobalAddresses);
}
void Converter::convertFunctions() { void Converter::convertFunctions() {
TimerStackIdT StackID = GlobalContext::TSK_Funcs; TimerStackIdT StackID = GlobalContext::TSK_Funcs;
for (const Function &I : *Mod) { for (const Function &I : *Mod) {
if (I.empty()) if (I.empty())
continue; continue;
TimerIdT TimerID = 0; TimerIdT TimerID = 0;
if (Ctx->getFlags().TimeEachFunction) { if (Ctx->getFlags().TimeEachFunction) {
TimerID = Ctx->getTimerID(StackID, I.getName()); TimerID = Ctx->getTimerID(StackID, I.getName());
Ctx->pushTimer(TimerID, StackID); Ctx->pushTimer(TimerID, StackID);
} }
LLVM2ICEConverter FunctionConverter(Ctx, Mod->getContext()); LLVM2ICEFunctionConverter FunctionConverter(Ctx, Mod->getContext());
Cfg *Fcn = FunctionConverter.convertFunction(&I); Cfg *Fcn = FunctionConverter.convertFunction(&I);
translateFcn(Fcn); translateFcn(Fcn);
......
...@@ -26,6 +26,7 @@ class Converter : public Translator { ...@@ -26,6 +26,7 @@ class Converter : public Translator {
public: public:
Converter(llvm::Module *Mod, GlobalContext *Ctx, const Ice::ClFlags &Flags) Converter(llvm::Module *Mod, GlobalContext *Ctx, const Ice::ClFlags &Flags)
: Translator(Ctx, Flags), Mod(Mod) {} : Translator(Ctx, Flags), Mod(Mod) {}
/// Converts the LLVM Module to ICE. Sets exit status to false if successful, /// Converts the LLVM Module to ICE. Sets exit status to false if successful,
/// true otherwise. /// true otherwise.
void convertToIce(); void convertToIce();
...@@ -34,9 +35,14 @@ private: ...@@ -34,9 +35,14 @@ private:
llvm::Module *Mod; llvm::Module *Mod;
// Converts functions to ICE, and then machine code. // Converts functions to ICE, and then machine code.
void convertFunctions(); void convertFunctions();
// Converts globals to ICE, and then machine code.
void convertGlobals(llvm::Module *Mod);
Converter(const Converter &) = delete; Converter(const Converter &) = delete;
Converter &operator=(const Converter &) = delete; Converter &operator=(const Converter &) = delete;
}; };
}
} // end of namespace ICE.
#endif // SUBZERO_SRC_ICECONVERTER_H #endif // SUBZERO_SRC_ICECONVERTER_H
//===- subzero/src/IceGlobalInits.cpp - Global initializers ---------------===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the notion of global addresses and
// initializers in Subzero.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Value.h"
#include "IceDefs.h"
#include "IceGlobalInits.h"
#include "IceTypes.h"
namespace {
char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
}
namespace Ice {
GlobalAddress::~GlobalAddress() { llvm::DeleteContainerPointers(Initializers); }
void GlobalAddress::dumpType(Ostream &Stream) const {
if (Initializers.size() == 1) {
Initializers.front()->dumpType(Stream);
} else {
Stream << "<{ ";
bool IsFirst = true;
for (Initializer *Init : Initializers) {
if (IsFirst) {
IsFirst = false;
} else {
Stream << ", ";
}
Init->dumpType(Stream);
}
Stream << " }>";
}
}
void GlobalAddress::dump(Ostream &Stream) const {
Stream << "@" << getName() << " = internal "
<< (IsConstant ? "constant" : "global") << " ";
// Add initializer.
if (Initializers.size() == 1) {
Initializers.front()->dump(Stream);
} else {
dumpType(Stream);
Stream << " <{ ";
bool IsFirst = true;
for (Initializer *Init : Initializers) {
if (IsFirst) {
IsFirst = false;
} else {
Stream << ", ";
}
Init->dump(Stream);
}
Stream << " }>";
}
// Add alignment.
if (Alignment > 0)
Stream << ", align " << Alignment;
Stream << "\n";
}
void GlobalAddress::Initializer::dumpType(Ostream &Stream) const {
Stream << "[" << getNumBytes() << " x " << Ice::IceType_i8 << "]";
}
void GlobalAddress::DataInitializer::dump(Ostream &Stream) const {
dumpType(Stream);
Stream << " c\"";
// Code taken from PrintEscapedString() in AsmWriter.cpp. Keep
// the strings in the same format as the .ll file for practical
// diffing.
for (uint8_t C : Contents) {
if (isprint(C) && C != '\\' && C != '"')
Stream << C;
else
Stream << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
}
Stream << "\"";
}
void GlobalAddress::ZeroInitializer::dump(Ostream &Stream) const {
dumpType(Stream);
Stream << " zeroinitializer";
}
IceString GlobalAddress::RelocInitializer::getName() const {
switch (Address.getKind()) {
case FunctionRelocation:
return Address.getFunction()->getName();
case GlobalAddressRelocation:
return Address.getGlobalAddr()->getName();
default:
llvm::report_fatal_error("Malformed relocation address!");
}
}
void GlobalAddress::RelocInitializer::dumpType(Ostream &Stream) const {
Stream << Ice::IceType_i32;
}
void GlobalAddress::RelocInitializer::dump(Ostream &Stream) const {
if (Offset != 0) {
dumpType(Stream);
Stream << " add (";
}
dumpType(Stream);
Stream << " ptrtoint (";
if (Address.getKind() == FunctionRelocation) {
Stream << *Address.getFunction()->getType() << " @"
<< Address.getFunction()->getName();
} else {
Address.getGlobalAddr()->dumpType(Stream);
Stream << "* @" << Address.getGlobalAddr()->getName();
}
Stream << " to ";
dumpType(Stream);
Stream << ")";
if (Offset != 0) {
Stream << ", ";
dumpType(Stream);
Stream << " " << Offset << ")";
}
}
}
//===- subzero/src/IceGlobalInits.h - Global initializers -------*- C++ -*-===//
//
// The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the representation of global addresses and
// initializers in Subzero. Global initializers are represented as a
// sequence of simple initializers.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEGLOBALINITS_H
#define SUBZERO_SRC_ICEGLOBALINITS_H
#include "IceDefs.h"
namespace llvm {
// TODO(kschimpf): Remove this dependency on LLVM IR.
class Value;
}
namespace Ice {
/// Models a global address, and its initializers.
class GlobalAddress {
GlobalAddress(const GlobalAddress &) = delete;
GlobalAddress &operator=(const GlobalAddress &) = delete;
public:
/// Base class for a global variable initializer.
class Initializer {
Initializer(const Initializer &) = delete;
Initializer &operator=(const Initializer &) = delete;
public:
/// Discriminator for LLVM-style RTTI.
enum InitializerKind {
DataInitializerKind,
ZeroInitializerKind,
RelocInitializerKind
};
InitializerKind getKind() const { return Kind; }
virtual ~Initializer() {}
virtual SizeT getNumBytes() const = 0;
virtual void dump(Ostream &Stream) const = 0;
virtual void dumpType(Ostream &Stream) const;
protected:
explicit Initializer(InitializerKind Kind) : Kind(Kind) {}
private:
const InitializerKind Kind;
};
// Models the data in a data initializer.
typedef std::vector<uint8_t> DataVecType;
/// Defines a sequence of byte values as a data initializer.
class DataInitializer : public Initializer {
DataInitializer(const DataInitializer &) = delete;
DataInitializer &operator=(const DataInitializer &) = delete;
public:
template <class IntContainer>
DataInitializer(const IntContainer &Values)
: Initializer(DataInitializerKind), Contents(Values.size()) {
size_t i = 0;
for (auto &V : Values) {
Contents[i] = static_cast<uint8_t>(V);
++i;
}
}
DataInitializer(const char *Str, size_t StrLen)
: Initializer(DataInitializerKind), Contents(StrLen) {
for (size_t i = 0; i < StrLen; ++i)
Contents[i] = static_cast<uint8_t>(Str[i]);
}
~DataInitializer() override {}
const DataVecType &getContents() const { return Contents; }
SizeT getNumBytes() const override { return Contents.size(); }
void dump(Ostream &Stream) const override;
static bool classof(const Initializer *D) {
return D->getKind() == DataInitializerKind;
}
private:
// The byte contents of the data initializer.
DataVecType Contents;
};
/// Defines a sequence of bytes initialized to zero.
class ZeroInitializer : public Initializer {
ZeroInitializer(const ZeroInitializer &) = delete;
ZeroInitializer &operator=(const ZeroInitializer &) = delete;
public:
explicit ZeroInitializer(SizeT Size)
: Initializer(ZeroInitializerKind), Size(Size) {}
~ZeroInitializer() override {}
SizeT getNumBytes() const override { return Size; }
void dump(Ostream &Stream) const override;
static bool classof(const Initializer *Z) {
return Z->getKind() == ZeroInitializerKind;
}
private:
// The number of bytes to be zero initialized.
SizeT Size;
};
/// Defines the kind of relocation addresses allowed.
enum RelocationKind { FunctionRelocation, GlobalAddressRelocation };
/// Defines a relocation address (i.e. reference to a function
/// or global variable address).
class RelocationAddress {
RelocationAddress &operator=(const RelocationAddress &) = delete;
public:
explicit RelocationAddress(const RelocationAddress &Addr)
: Kind(Addr.Kind) {
switch (Kind) {
case FunctionRelocation:
Address.Function = Addr.Address.Function;
break;
case GlobalAddressRelocation:
Address.GlobalAddr = Addr.Address.GlobalAddr;
}
}
explicit RelocationAddress(llvm::Value *Function)
: Kind(FunctionRelocation) {
Address.Function = Function;
}
explicit RelocationAddress(GlobalAddress *GlobalAddr)
: Kind(GlobalAddressRelocation) {
Address.GlobalAddr = GlobalAddr;
}
RelocationKind getKind() const { return Kind; }
llvm::Value *getFunction() const {
assert(Kind == FunctionRelocation);
return Address.Function;
}
GlobalAddress *getGlobalAddr() const {
assert(Kind == GlobalAddressRelocation);
return Address.GlobalAddr;
}
private:
const RelocationKind Kind;
union {
// TODO(kschimpf) Integrate Functions into ICE model.
llvm::Value *Function;
GlobalAddress *GlobalAddr;
} Address;
};
// Relocation address offsets must be 32 bit values.
typedef int32_t RelocOffsetType;
static const SizeT RelocAddrSize = 4;
/// Defines the relocation value of another address.
class RelocInitializer : public Initializer {
RelocInitializer(const RelocInitializer &) = delete;
RelocInitializer &operator=(const RelocInitializer &) = delete;
public:
RelocInitializer(const RelocationAddress &Address, RelocOffsetType Offset)
: Initializer(RelocInitializerKind), Address(Address), Offset(Offset) {}
~RelocInitializer() override {}
RelocOffsetType getOffset() const { return Offset; }
IceString getName() const;
SizeT getNumBytes() const override { return RelocAddrSize; }
void dump(Ostream &Stream) const override;
virtual void dumpType(Ostream &Stream) const;
static bool classof(const Initializer *R) {
return R->getKind() == RelocInitializerKind;
}
private:
// The global address used in the relocation.
const RelocationAddress Address;
// The offset to add to the relocation.
const RelocOffsetType Offset;
};
/// Models the list of initializers.
typedef std::vector<Initializer *> InitializerListType;
GlobalAddress() : Alignment(0), IsConstant(false), IsInternal(true) {}
~GlobalAddress();
const InitializerListType &getInitializers() const { return Initializers; }
bool hasName() const { return !Name.empty(); }
const IceString &getName() const { return Name; }
void setName(const IceString &NewName) { Name = NewName; }
bool getIsConstant() const { return IsConstant; }
void setIsConstant(bool NewValue) { IsConstant = NewValue; }
uint32_t getAlignment() const { return Alignment; }
void setAlignment(uint32_t NewAlignment) { Alignment = NewAlignment; }
bool getIsInternal() const { return IsInternal; }
void setIsInternal(bool NewValue) { IsInternal = NewValue; }
/// Returns the number of bytes for the initializer of the global
/// address.
SizeT getNumBytes() const {
SizeT Count = 0;
for (Initializer *Init : Initializers) {
Count += Init->getNumBytes();
}
return Count;
}
/// Adds Initializer to the list of initializers. Takes ownership of
/// the initializer.
void addInitializer(Initializer *Initializer) {
Initializers.push_back(Initializer);
}
/// Prints out type for initializer associated with the global address
/// to Stream.
void dumpType(Ostream &Stream) const;
/// Prints out the definition of the global address (including
/// initialization).
void dump(Ostream &Stream) const;
private:
// list of initializers associated with the global address.
InitializerListType Initializers;
// The name for the global.
IceString Name;
// The alignment of the initializer.
uint32_t Alignment;
// True if a constant initializer.
bool IsConstant;
// True if the address is internal.
bool IsInternal;
};
template <class StreamType>
inline StreamType &operator<<(StreamType &Stream,
const GlobalAddress::Initializer &Init) {
Init.dump(Stream);
return Stream;
}
template <class StreamType>
inline StreamType &operator<<(StreamType &Stream, const GlobalAddress &Addr) {
Addr.dump(Stream);
return Stream;
}
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEGLOBALINITS_H
...@@ -27,6 +27,7 @@ namespace Ice { ...@@ -27,6 +27,7 @@ namespace Ice {
typedef uint8_t AsmCodeByte; typedef uint8_t AsmCodeByte;
class Assembler; class Assembler;
class GlobalAddress;
// LoweringContext makes it easy to iterate through non-deleted // LoweringContext makes it easy to iterate through non-deleted
// instructions in a node, and insert new (lowered) instructions at // instructions in a node, and insert new (lowered) instructions at
...@@ -248,10 +249,7 @@ public: ...@@ -248,10 +249,7 @@ public:
GlobalContext *Ctx); GlobalContext *Ctx);
virtual ~TargetGlobalInitLowering(); virtual ~TargetGlobalInitLowering();
// TODO: Allow relocations to be represented as part of the Data. virtual void lower(const GlobalAddress &Addr, bool DisableTranslation) = 0;
virtual void lower(const IceString &Name, SizeT Align, bool IsInternal,
bool IsConst, bool IsZeroInitializer, SizeT Size,
const char *Data, bool DisableTranslation) = 0;
protected: protected:
TargetGlobalInitLowering(GlobalContext *Ctx) : Ctx(Ctx) {} TargetGlobalInitLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "IceCfgNode.h" #include "IceCfgNode.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceGlobalInits.h"
#include "IceInstX8632.h" #include "IceInstX8632.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceRegistersX8632.h" #include "IceRegistersX8632.h"
...@@ -4428,38 +4429,10 @@ void ConstantUndef::emit(GlobalContext *) const { ...@@ -4428,38 +4429,10 @@ void ConstantUndef::emit(GlobalContext *) const {
TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx) TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx)
: TargetGlobalInitLowering(Ctx) {} : TargetGlobalInitLowering(Ctx) {}
namespace { void TargetGlobalInitX8632::lower(const GlobalAddress &Global,
char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; } bool DisableTranslation) {
}
void TargetGlobalInitX8632::lower(const IceString &Name, SizeT Align,
bool IsInternal, bool IsConst,
bool IsZeroInitializer, SizeT Size,
const char *Data, bool DisableTranslation) {
if (Ctx->isVerbose()) { if (Ctx->isVerbose()) {
// TODO: Consider moving the dump output into the driver to be Global.dump(Ctx->getStrDump());
// 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) if (DisableTranslation)
...@@ -4489,35 +4462,86 @@ void TargetGlobalInitX8632::lower(const IceString &Name, SizeT Align, ...@@ -4489,35 +4462,86 @@ void TargetGlobalInitX8632::lower(const IceString &Name, SizeT Align,
// .local NAME // .local NAME
// .comm NAME, SIZE, ALIGN // .comm NAME, SIZE, ALIGN
IceString MangledName = Ctx->mangleName(Name); // TODO(kschimpf): Don't mangle name if external and uninitialized. This
// will allow us to cross test relocations for references to external
// global variables.
IceString MangledName = Ctx->mangleName(Global.getName());
// Start a new section. // Start a new section.
if (IsConst) { if (Ctx->getFlags().DataSections) {
Str << "\t.section\t.rodata." << MangledName << ",\"a\",@progbits\n";
} else if (Global.getIsConstant()) {
Str << "\t.section\t.rodata,\"a\",@progbits\n"; Str << "\t.section\t.rodata,\"a\",@progbits\n";
} else { } else {
Str << "\t.type\t" << MangledName << ",@object\n"; Str << "\t.type\t" << MangledName << ",@object\n";
Str << "\t.data\n"; Str << "\t.data\n";
} }
Str << "\t" << (IsInternal ? ".local" : ".global") << "\t" << MangledName
<< "\n"; Str << "\t" << (Global.getIsInternal() ? ".local" : ".global") << "\t"
if (IsZeroInitializer) { << MangledName << "\n";
if (IsConst) {
Str << "\t.align\t" << Align << "\n"; const GlobalAddress::InitializerListType &Initializers =
Str << MangledName << ":\n"; Global.getInitializers();
Str << "\t.zero\t" << Size << "\n";
Str << "\t.size\t" << MangledName << ", " << Size << "\n"; // Note: Handle zero initializations specially when lowering, since
} else { // we may be able to reduce object size.
// TODO(stichnot): Put the appropriate non-constant GlobalAddress::ZeroInitializer *SimpleZeroInit = nullptr;
// zeroinitializers in a .bss section to reduce object size. if (Initializers.size() == 1) {
Str << "\t.comm\t" << MangledName << ", " << Size << ", " << Align GlobalAddress::Initializer *Init = Initializers[0];
<< "\n"; if (const auto ZeroInit =
llvm::dyn_cast<GlobalAddress::ZeroInitializer>(Init)) {
SimpleZeroInit = ZeroInit;
} }
}
if (SimpleZeroInit && !Global.getIsConstant()) {
// TODO(stichnot): Put the appropriate non-constant
// zeroinitializers in a .bss section to reduce object size.
Str << "\t.comm\t" << MangledName << ", " << Global.getNumBytes() << ", "
<< Global.getAlignment() << "\n";
// }
} else { } else {
Str << "\t.align\t" << Align << "\n"; Str << "\t.align\t" << Global.getAlignment() << "\n";
Str << MangledName << ":\n"; Str << MangledName << ":\n";
for (SizeT i = 0; i < Size; ++i) { for (GlobalAddress::Initializer *Init : Initializers) {
Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n"; switch (Init->getKind()) {
case GlobalAddress::Initializer::DataInitializerKind: {
const auto Data =
llvm::cast<GlobalAddress::DataInitializer>(Init)->getContents();
for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
}
break;
}
case GlobalAddress::Initializer::ZeroInitializerKind:
Str << "\t.zero\t" << Init->getNumBytes() << "\n";
break;
case GlobalAddress::Initializer::RelocInitializerKind: {
const auto Reloc = llvm::cast<GlobalAddress::RelocInitializer>(Init);
Str << "\t.long\t";
// TODO(kschimpf): Once the representation of a relocation has
// been modified to reference the corresponding global
// address, modify to not mangle the name if the global is
// external and uninitialized. This will allow us to better
// test cross test relocations.
Str << Ctx->mangleName(Reloc->getName());
if (GlobalAddress::RelocOffsetType Offset = Reloc->getOffset()) {
Str << " + " << Offset;
}
Str << "\n";
break;
}
default: {
std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer);
StrBuf << "Unable to lower initializer: ";
Init->dump(StrBuf);
llvm::report_fatal_error(StrBuf.str());
break;
}
}
} }
Str << "\t.size\t" << MangledName << ", " << Size << "\n"; Str << "\t.size\t" << MangledName << ", " << Global.getNumBytes() << "\n";
} }
} }
......
...@@ -486,9 +486,9 @@ public: ...@@ -486,9 +486,9 @@ public:
static TargetGlobalInitLowering *create(GlobalContext *Ctx) { static TargetGlobalInitLowering *create(GlobalContext *Ctx) {
return new TargetGlobalInitX8632(Ctx); return new TargetGlobalInitX8632(Ctx);
} }
void lower(const IceString &Name, SizeT Align, bool IsInternal, bool IsConst,
bool IsZeroInitializer, SizeT Size, const char *Data, virtual void lower(const GlobalAddress &Addr,
bool DisableTranslation) override; bool DisableTranslation) override;
protected: protected:
TargetGlobalInitX8632(GlobalContext *Ctx); TargetGlobalInitX8632(GlobalContext *Ctx);
......
...@@ -29,44 +29,61 @@ using namespace Ice; ...@@ -29,44 +29,61 @@ using namespace Ice;
Translator::~Translator() {} Translator::~Translator() {}
namespace { IceString Translator::createUnnamedName(const IceString &Prefix, SizeT Index) {
void setValueName(llvm::Value *V, const char *Kind, const IceString &Prefix, if (Index == 0)
uint32_t &NameIndex, Ostream &errs) { return Prefix;
if (V->hasName()) {
const std::string &Name(V->getName());
if (Name.find(Prefix) == 0) {
errs << "Warning: Default " << Kind << " prefix '" << Prefix
<< "' conflicts with name '" << Name << "'.\n";
}
return;
}
if (NameIndex == 0) {
V->setName(Prefix);
++NameIndex;
return;
}
std::string Buffer; std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer); llvm::raw_string_ostream StrBuf(Buffer);
StrBuf << Prefix << NameIndex; StrBuf << Prefix << Index;
V->setName(StrBuf.str()); return StrBuf.str();
++NameIndex; }
bool Translator::checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
const IceString &Prefix,
Ostream &Stream) {
if (Name.find(Prefix) == 0) {
for (size_t i = Prefix.size(); i < Name.size(); ++i) {
if (!isdigit(Name[i])) {
return false;
}
}
Stream << "Warning : Default " << Kind << " prefix '" << Prefix
<< "' potentially conflicts with name '" << Name << "'.\n";
return true;
}
return false;
} }
} // end of anonymous namespace
void Translator::nameUnnamedGlobalAddresses(llvm::Module *Mod) { void Translator::nameUnnamedGlobalAddresses(llvm::Module *Mod) {
const IceString &GlobalPrefix = Flags.DefaultGlobalPrefix; const IceString &GlobalPrefix = Flags.DefaultGlobalPrefix;
if (GlobalPrefix.empty())
return;
uint32_t NameIndex = 0;
Ostream &errs = Ctx->getStrDump(); Ostream &errs = Ctx->getStrDump();
if (!GlobalPrefix.empty()) { for (auto V = Mod->global_begin(), E = Mod->global_end(); V != E; ++V) {
uint32_t NameIndex = 0; if (!V->hasName()) {
for (auto I = Mod->global_begin(), E = Mod->global_end(); I != E; ++I) V->setName(createUnnamedName(GlobalPrefix, NameIndex));
setValueName(I, "global", GlobalPrefix, NameIndex, errs); ++NameIndex;
} else {
checkIfUnnamedNameSafe(V->getName(), "global", GlobalPrefix, errs);
}
} }
}
void Translator::nameUnnamedFunctions(llvm::Module *Mod) {
const IceString &FunctionPrefix = Flags.DefaultFunctionPrefix; const IceString &FunctionPrefix = Flags.DefaultFunctionPrefix;
if (FunctionPrefix.empty()) if (FunctionPrefix.empty())
return; return;
uint32_t NameIndex = 0; uint32_t NameIndex = 0;
for (llvm::Function &I : *Mod) Ostream &errs = Ctx->getStrDump();
setValueName(&I, "function", FunctionPrefix, NameIndex, errs); for (llvm::Function &F : *Mod) {
if (!F.hasName()) {
F.setName(createUnnamedName(FunctionPrefix, NameIndex));
++NameIndex;
} else {
checkIfUnnamedNameSafe(F.getName(), "function", FunctionPrefix, errs);
}
}
} }
void Translator::translateFcn(Cfg *Fcn) { void Translator::translateFcn(Cfg *Fcn) {
...@@ -93,46 +110,12 @@ void Translator::emitConstants() { ...@@ -93,46 +110,12 @@ void Translator::emitConstants() {
Func->getTarget()->emitConstants(); Func->getTarget()->emitConstants();
} }
void Translator::convertGlobals(llvm::Module *Mod) { void Translator::lowerGlobals(const GlobalAddressList &GlobalAddresses) {
std::unique_ptr<TargetGlobalInitLowering> GlobalLowering( llvm::OwningPtr<Ice::TargetGlobalInitLowering> GlobalLowering(
TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx)); Ice::TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
for (auto I = Mod->global_begin(), E = Mod->global_end(); I != E; ++I) { bool DisableTranslation = Ctx->getFlags().DisableTranslation;
if (!I->hasInitializer()) for (const Ice::GlobalAddress *Addr : GlobalAddresses) {
continue; GlobalLowering->lower(*Addr, DisableTranslation);
const llvm::Constant *Initializer = I->getInitializer();
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 llvm::ConstantDataArray *CDA =
llvm::dyn_cast<llvm::ConstantDataArray>(Initializer)) {
NumElements = CDA->getNumElements();
assert(llvm::isa<llvm::IntegerType>(CDA->getElementType()) &&
(llvm::cast<llvm::IntegerType>(CDA->getElementType())
->getBitWidth() == 8));
Data = CDA->getRawDataValues().data();
} else if (llvm::isa<llvm::ConstantAggregateZero>(Initializer)) {
if (const llvm::ArrayType *AT =
llvm::dyn_cast<llvm::ArrayType>(Initializer->getType())) {
assert(llvm::isa<llvm::IntegerType>(AT->getElementType()) &&
(llvm::cast<llvm::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,
Ctx->getFlags().DisableTranslation);
} }
GlobalLowering.reset(); GlobalLowering.reset();
} }
...@@ -25,6 +25,7 @@ namespace Ice { ...@@ -25,6 +25,7 @@ namespace Ice {
class ClFlags; class ClFlags;
class Cfg; class Cfg;
class GlobalAddress;
class GlobalContext; class GlobalContext;
// Base class for translating ICE to machine code. // Base class for translating ICE to machine code.
...@@ -33,6 +34,8 @@ class GlobalContext; ...@@ -33,6 +34,8 @@ class GlobalContext;
// machine instructions. // machine instructions.
class Translator { class Translator {
public: public:
typedef std::vector<Ice::GlobalAddress *> GlobalAddressList;
Translator(GlobalContext *Ctx, const ClFlags &Flags) Translator(GlobalContext *Ctx, const ClFlags &Flags)
: Ctx(Ctx), Flags(Flags), ErrorStatus(0) {} : Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
...@@ -51,15 +54,26 @@ public: ...@@ -51,15 +54,26 @@ public:
/// Emits the constant pool. /// Emits the constant pool.
void emitConstants(); void emitConstants();
// Walks module and generates names for unnamed globals and /// Lowers the given list of global addresses to target.
// functions using prefix getFlags().DefaultGlobalPrefix, if the void lowerGlobals(const GlobalAddressList &GlobalAddresses);
// prefix is non-empty.
/// Creates a name using the given prefix and corresponding index.
std::string createUnnamedName(const IceString &Prefix, SizeT Index);
/// Reports if there is a (potential) conflict between Name, and using
/// Prefix to name unnamed names. Errors are put on Ostream.
/// Returns true if there isn't a potential conflict.
bool checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
const IceString &Prefix, Ostream &Stream);
// Walks module and generates names for unnamed globals using prefix
// getFlags().DefaultGlobalPrefix, if the prefix is non-empty.
void nameUnnamedGlobalAddresses(llvm::Module *Mod); void nameUnnamedGlobalAddresses(llvm::Module *Mod);
// Converts globals to ICE, and then machine code. // Walks module and generates names for unnamed functions using
// TODO(kschimpf) Remove this once we have ported to PNaClTranslator, // prefix getFlags().DefaultFunctionPrefix, if the prefix is
// and PNaClTranslator generates initializers while parsing. // non-empty.
void convertGlobals(llvm::Module *Mod); void nameUnnamedFunctions(llvm::Module *Mod);
protected: protected:
GlobalContext *Ctx; GlobalContext *Ctx;
......
...@@ -19,25 +19,25 @@ ...@@ -19,25 +19,25 @@
namespace Ice { namespace Ice {
TypeConverter::TypeConverter(llvm::LLVMContext &Context) { TypeConverter::TypeConverter(llvm::LLVMContext &Context) {
AddLLVMType(IceType_void, llvm::Type::getVoidTy(Context)); addLLVMType(IceType_void, llvm::Type::getVoidTy(Context));
AddLLVMType(IceType_i1, llvm::IntegerType::get(Context, 1)); addLLVMType(IceType_i1, llvm::IntegerType::get(Context, 1));
AddLLVMType(IceType_i8, llvm::IntegerType::get(Context, 8)); addLLVMType(IceType_i8, llvm::IntegerType::get(Context, 8));
AddLLVMType(IceType_i16, llvm::IntegerType::get(Context, 16)); addLLVMType(IceType_i16, llvm::IntegerType::get(Context, 16));
AddLLVMType(IceType_i32, llvm::IntegerType::get(Context, 32)); addLLVMType(IceType_i32, llvm::IntegerType::get(Context, 32));
AddLLVMType(IceType_i64, llvm::IntegerType::get(Context, 64)); addLLVMType(IceType_i64, llvm::IntegerType::get(Context, 64));
AddLLVMType(IceType_f32, llvm::Type::getFloatTy(Context)); addLLVMType(IceType_f32, llvm::Type::getFloatTy(Context));
AddLLVMType(IceType_f64, llvm::Type::getDoubleTy(Context)); addLLVMType(IceType_f64, llvm::Type::getDoubleTy(Context));
AddLLVMType(IceType_v4i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 4)); addLLVMType(IceType_v4i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 4));
AddLLVMType(IceType_v8i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 8)); addLLVMType(IceType_v8i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 8));
AddLLVMType(IceType_v16i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 16)); addLLVMType(IceType_v16i1, llvm::VectorType::get(LLVMTypes[IceType_i1], 16));
AddLLVMType(IceType_v16i8, llvm::VectorType::get(LLVMTypes[IceType_i8], 16)); addLLVMType(IceType_v16i8, llvm::VectorType::get(LLVMTypes[IceType_i8], 16));
AddLLVMType(IceType_v8i16, llvm::VectorType::get(LLVMTypes[IceType_i16], 8)); addLLVMType(IceType_v8i16, llvm::VectorType::get(LLVMTypes[IceType_i16], 8));
AddLLVMType(IceType_v4i32, llvm::VectorType::get(LLVMTypes[IceType_i32], 4)); addLLVMType(IceType_v4i32, llvm::VectorType::get(LLVMTypes[IceType_i32], 4));
AddLLVMType(IceType_v4f32, llvm::VectorType::get(LLVMTypes[IceType_f32], 4)); addLLVMType(IceType_v4f32, llvm::VectorType::get(LLVMTypes[IceType_f32], 4));
assert(LLVMTypes.size() == static_cast<size_t>(IceType_NUM)); assert(LLVMTypes.size() == static_cast<size_t>(IceType_NUM));
} }
void TypeConverter::AddLLVMType(Type Ty, llvm::Type *LLVMTy) { void TypeConverter::addLLVMType(Type Ty, llvm::Type *LLVMTy) {
assert(static_cast<size_t>(Ty) == LLVMTypes.size()); assert(static_cast<size_t>(Ty) == LLVMTypes.size());
LLVMTypes.push_back(LLVMTy); LLVMTypes.push_back(LLVMTy);
LLVM2IceMap[LLVMTy] = Ty; LLVM2IceMap[LLVMTy] = Ty;
......
...@@ -68,7 +68,7 @@ private: ...@@ -68,7 +68,7 @@ private:
std::map<llvm::Type *, Type> LLVM2IceMap; std::map<llvm::Type *, Type> LLVM2IceMap;
// Add LLVM/ICE pair to internal tables. // Add LLVM/ICE pair to internal tables.
void AddLLVMType(Type Ty, llvm::Type *LLVMTy); void addLLVMType(Type Ty, llvm::Type *LLVMTy);
// Converts types not in LLVM2IceMap. // Converts types not in LLVM2IceMap.
Type convertToIceTypeOther(llvm::Type *LLVMTy) const; Type convertToIceTypeOther(llvm::Type *LLVMTy) const;
......
...@@ -12,10 +12,6 @@ ...@@ -12,10 +12,6 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include <cassert>
#include <memory>
#include <vector>
#include "llvm/Analysis/NaCl/PNaClABIProps.h" #include "llvm/Analysis/NaCl/PNaClABIProps.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h" #include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
#include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h"
...@@ -34,6 +30,7 @@ ...@@ -34,6 +30,7 @@
#include "IceCfgNode.h" #include "IceCfgNode.h"
#include "IceClFlags.h" #include "IceClFlags.h"
#include "IceDefs.h" #include "IceDefs.h"
#include "IceGlobalInits.h"
#include "IceInst.h" #include "IceInst.h"
#include "IceOperand.h" #include "IceOperand.h"
#include "IceTypeConverter.h" #include "IceTypeConverter.h"
...@@ -62,13 +59,12 @@ public: ...@@ -62,13 +59,12 @@ public:
Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout), Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout),
Header(Header), TypeConverter(getLLVMContext()), Header(Header), TypeConverter(getLLVMContext()),
ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0), ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
NumFunctionBlocks(0), NumFunctionBlocks(0) {
GlobalVarPlaceHolderType(convertToLLVMType(Ice::IceType_i8)) {
Mod->setDataLayout(PNaClDataLayout); Mod->setDataLayout(PNaClDataLayout);
setErrStream(Translator.getContext()->getStrDump()); setErrStream(Translator.getContext()->getStrDump());
} }
~TopLevelParser() override {} ~TopLevelParser() override { DeleteContainerPointers(GlobalIDAddresses); }
Ice::Translator &getTranslator() { return Translator; } Ice::Translator &getTranslator() { return Translator; }
...@@ -103,8 +99,8 @@ public: ...@@ -103,8 +99,8 @@ public:
/// Returns the type associated with the given index. /// Returns the type associated with the given index.
Type *getTypeByID(unsigned ID) { Type *getTypeByID(unsigned ID) {
// Note: method resizeTypeIDValues expands TypeIDValues // Note: method resizeTypeIDValues expands TypeIDValues
// to the specified size, and fills elements with NULL. // to the specified size, and fills elements with nullptr.
Type *Ty = ID < TypeIDValues.size() ? TypeIDValues[ID] : NULL; Type *Ty = ID < TypeIDValues.size() ? TypeIDValues[ID] : nullptr;
if (Ty) if (Ty)
return Ty; return Ty;
return reportTypeIDAsUndefined(ID); return reportTypeIDAsUndefined(ID);
...@@ -112,7 +108,7 @@ public: ...@@ -112,7 +108,7 @@ public:
/// Defines type for ID. /// Defines type for ID.
void setTypeID(unsigned ID, Type *Ty) { void setTypeID(unsigned ID, Type *Ty) {
if (ID < TypeIDValues.size() && TypeIDValues[ID] == NULL) { if (ID < TypeIDValues.size() && TypeIDValues[ID] == nullptr) {
TypeIDValues[ID] = Ty; TypeIDValues[ID] = Ty;
return; return;
} }
...@@ -122,13 +118,13 @@ public: ...@@ -122,13 +118,13 @@ public:
/// Sets the next function ID to the given LLVM function. /// Sets the next function ID to the given LLVM function.
void setNextFunctionID(Function *Fcn) { void setNextFunctionID(Function *Fcn) {
++NumFunctionIds; ++NumFunctionIds;
ValueIDValues.push_back(Fcn); FunctionIDValues.push_back(Fcn);
} }
/// Defines the next function ID as one that has an implementation /// Defines the next function ID as one that has an implementation
/// (i.e a corresponding function block in the bitcode). /// (i.e a corresponding function block in the bitcode).
void setNextValueIDAsImplementedFunction() { void setNextValueIDAsImplementedFunction() {
DefiningFunctionsList.push_back(ValueIDValues.size()); DefiningFunctionsList.push_back(FunctionIDValues.size());
} }
/// Returns the value id that should be associated with the the /// Returns the value id that should be associated with the the
...@@ -142,28 +138,48 @@ public: ...@@ -142,28 +138,48 @@ public:
} }
/// Returns the LLVM IR value associatd with the global value ID. /// Returns the LLVM IR value associatd with the global value ID.
Value *getGlobalValueByID(unsigned ID) const { Function *getFunctionByID(unsigned ID) const {
if (ID >= ValueIDValues.size()) if (ID >= FunctionIDValues.size())
return NULL; return nullptr;
return ValueIDValues[ID]; Value *V = FunctionIDValues[ID];
return cast<Function>(V);
} }
/// Returns the corresponding constant associated with a global value /// Returns the corresponding constant associated with a global value
/// (i.e. relocatable). /// (i.e. relocatable).
Ice::Constant *getOrCreateGlobalConstantByID(unsigned ID) { Ice::Constant *getOrCreateGlobalConstantByID(unsigned ID) {
// TODO(kschimpf): Can this be built when creating global initializers? // TODO(kschimpf): Can this be built when creating global initializers?
Ice::Constant *C;
if (ID >= ValueIDConstants.size()) { if (ID >= ValueIDConstants.size()) {
if (ID >= ValueIDValues.size()) C = nullptr;
return NULL; unsigned ExpectedSize =
ValueIDConstants.resize(ValueIDValues.size()); FunctionIDValues.size() + GlobalIDAddresses.size();
if (ID >= ExpectedSize)
ExpectedSize = ID;
ValueIDConstants.resize(ExpectedSize);
} else {
C = ValueIDConstants[ID];
} }
Ice::Constant *C = ValueIDConstants[ID]; if (C != nullptr)
if (C != NULL)
return C; return C;
Value *V = ValueIDValues[ID];
assert(isa<GlobalValue>(V)); // If reached, no such constant exists, create one.
C = getTranslator().getContext()->getConstantSym(getIcePointerType(), 0, std::string Name;
V->getName()); unsigned FcnIDSize = FunctionIDValues.size();
if (ID < FcnIDSize) {
Name = FunctionIDValues[ID]->getName();
} else if ((ID - FcnIDSize) < GlobalIDAddresses.size()) {
Name = GlobalIDAddresses[ID - FcnIDSize]->getName();
} else {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Reference to global not defined: " << ID;
Error(StrBuf.str());
Name = "??";
}
const uint64_t Offset = 0;
C = getTranslator().getContext()->getConstantSym(
getIcePointerType(), Offset, Name);
ValueIDConstants[ID] = C; ValueIDConstants[ID] = C;
return C; return C;
} }
...@@ -172,51 +188,43 @@ public: ...@@ -172,51 +188,43 @@ public:
/// the bitcode file. /// the bitcode file.
unsigned getNumFunctionIDs() const { return NumFunctionIds; } unsigned getNumFunctionIDs() const { return NumFunctionIds; }
/// Returns the number of global values defined in the bitcode /// Returns the number of global IDs (function and global addresses)
/// file. /// defined in the bitcode file.
unsigned getNumGlobalValueIDs() const { return ValueIDValues.size(); } unsigned getNumGlobalIDs() const {
return FunctionIDValues.size() + GlobalIDAddresses.size();
/// Resizes the list of value IDs to include Count global variable
/// IDs.
void resizeValueIDsForGlobalVarCount(unsigned Count) {
ValueIDValues.resize(ValueIDValues.size() + Count);
}
/// Returns the global variable address associated with the given
/// value ID. If the ID refers to a global variable address not yet
/// defined, a placeholder is created so that we can fix it up
/// later.
Constant *getOrCreateGlobalVarRef(unsigned ID) {
if (ID >= ValueIDValues.size())
return NULL;
if (Value *C = ValueIDValues[ID])
return dyn_cast<Constant>(C);
Constant *C = new GlobalVariable(*Mod, GlobalVarPlaceHolderType, false,
GlobalValue::ExternalLinkage, 0);
ValueIDValues[ID] = C;
return C;
} }
/// Assigns the given global variable (address) to the given value /// Creates Count global addresses.
/// ID. Returns true if ID is a valid global variable ID. Otherwise void CreateGlobalAddresses(size_t Count) {
/// returns false. assert(GlobalIDAddresses.empty());
bool assignGlobalVariable(GlobalVariable *GV, unsigned ID) { for (size_t i = 0; i < Count; ++i) {
if (ID < NumFunctionIds || ID >= ValueIDValues.size()) GlobalIDAddresses.push_back(new Ice::GlobalAddress());
return false;
WeakVH &OldV = ValueIDValues[ID];
if (OldV == NULL) {
ValueIDValues[ID] = GV;
return true;
} }
}
// If reached, there was a forward reference to this value. Replace it. /// Returns the number of global addresses (i.e. ID's) defined in
Value *PrevVal = OldV; /// the bitcode file.
GlobalVariable *Placeholder = cast<GlobalVariable>(PrevVal); Ice::SizeT getNumGlobalAddresses() const { return GlobalIDAddresses.size(); }
Placeholder->replaceAllUsesWith(
ConstantExpr::getBitCast(GV, Placeholder->getType())); /// Returns the global address with the given index.
Placeholder->eraseFromParent(); Ice::GlobalAddress *getGlobalAddress(size_t Index) {
ValueIDValues[ID] = GV; if (Index < GlobalIDAddresses.size())
return true; return GlobalIDAddresses[Index];
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Global index " << Index
<< " not allowed. Out of range. Must be less than "
<< GlobalIDAddresses.size();
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
if (!GlobalIDAddresses.empty())
return GlobalIDAddresses[0];
report_fatal_error("Unable to continue");
}
/// Returns the list of read global addresses.
const Ice::Translator::GlobalAddressList &getGlobalIDAddresses() {
return GlobalIDAddresses;
} }
/// Returns the corresponding ICE type for LLVMTy. /// Returns the corresponding ICE type for LLVMTy.
...@@ -234,13 +242,13 @@ public: ...@@ -234,13 +242,13 @@ public:
} }
/// Returns the LLVM integer type with the given number of Bits. If /// Returns the LLVM integer type with the given number of Bits. If
/// Bits is not a valid PNaCl type, returns NULL. /// Bits is not a valid PNaCl type, returns nullptr.
Type *getLLVMIntegerType(unsigned Bits) const { Type *getLLVMIntegerType(unsigned Bits) const {
return TypeConverter.getLLVMIntegerType(Bits); return TypeConverter.getLLVMIntegerType(Bits);
} }
/// Returns the LLVM vector with the given Size and Ty. If not a /// Returns the LLVM vector with the given Size and Ty. If not a
/// valid PNaCl vector type, returns NULL. /// valid PNaCl vector type, returns nullptr.
Type *getLLVMVectorType(unsigned Size, Ice::Type Ty) const { Type *getLLVMVectorType(unsigned Size, Ice::Type Ty) const {
return TypeConverter.getLLVMVectorType(Size, Ty); return TypeConverter.getLLVMVectorType(Size, Ty);
} }
...@@ -267,9 +275,12 @@ private: ...@@ -267,9 +275,12 @@ private:
unsigned NumErrors; unsigned NumErrors;
// The types associated with each type ID. // The types associated with each type ID.
std::vector<Type *> TypeIDValues; std::vector<Type *> TypeIDValues;
// The (global) value IDs. // The set of function value IDs.
std::vector<WeakVH> ValueIDValues; std::vector<WeakVH> FunctionIDValues;
// Relocatable constants associated with ValueIDValues. // The set of global addresses IDs.
Ice::Translator::GlobalAddressList GlobalIDAddresses;
// Relocatable constants associated with FunctionIDValues and
// GlobalIDAddresses.
std::vector<Ice::Constant *> ValueIDConstants; std::vector<Ice::Constant *> ValueIDConstants;
// The number of function IDs. // The number of function IDs.
unsigned NumFunctionIds; unsigned NumFunctionIds;
...@@ -278,9 +289,6 @@ private: ...@@ -278,9 +289,6 @@ private:
// The list of value IDs (in the order found) of defining function // The list of value IDs (in the order found) of defining function
// addresses. // addresses.
std::vector<unsigned> DefiningFunctionsList; std::vector<unsigned> DefiningFunctionsList;
// Cached global variable placeholder type. Used for all forward
// references to global variable addresses.
Type *GlobalVarPlaceHolderType;
bool ParseBlock(unsigned BlockID) override; bool ParseBlock(unsigned BlockID) override;
...@@ -380,7 +388,7 @@ protected: ...@@ -380,7 +388,7 @@ protected:
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
if (Values.size() == Size) if (Values.size() == Size)
return true; return true;
ReportRecordSizeError(Size, RecordName, NULL); ReportRecordSizeError(Size, RecordName, nullptr);
return false; return false;
} }
...@@ -418,7 +426,7 @@ protected: ...@@ -418,7 +426,7 @@ protected:
private: private:
/// Generates a record size error. ExpectedSize is the number /// Generates a record size error. ExpectedSize is the number
/// of elements expected. RecordName is the name of the kind of /// of elements expected. RecordName is the name of the kind of
/// record that has incorrect size. ContextMessage (if not NULL) /// record that has incorrect size. ContextMessage (if not nullptr)
/// is appended to "record expects" to describe how ExpectedSize /// is appended to "record expects" to describe how ExpectedSize
/// should be interpreted. /// should be interpreted.
void ReportRecordSizeError(unsigned ExpectedSize, const char *RecordName, void ReportRecordSizeError(unsigned ExpectedSize, const char *RecordName,
...@@ -477,7 +485,7 @@ private: ...@@ -477,7 +485,7 @@ private:
}; };
void TypesParser::ProcessRecord() { void TypesParser::ProcessRecord() {
Type *Ty = NULL; Type *Ty = nullptr;
const NaClBitcodeRecord::RecordVector &Values = Record.GetValues(); const NaClBitcodeRecord::RecordVector &Values = Record.GetValues();
switch (Record.GetCode()) { switch (Record.GetCode()) {
case naclbitc::TYPE_CODE_NUMENTRY: case naclbitc::TYPE_CODE_NUMENTRY:
...@@ -509,7 +517,7 @@ void TypesParser::ProcessRecord() { ...@@ -509,7 +517,7 @@ void TypesParser::ProcessRecord() {
if (!isValidRecordSize(1, "Type integer")) if (!isValidRecordSize(1, "Type integer"))
return; return;
Ty = Context->getLLVMIntegerType(Values[0]); Ty = Context->getLLVMIntegerType(Values[0]);
if (Ty == NULL) { if (Ty == nullptr) {
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Type integer record with invalid bitsize: " << Values[0]; StrBuf << "Type integer record with invalid bitsize: " << Values[0];
...@@ -526,7 +534,7 @@ void TypesParser::ProcessRecord() { ...@@ -526,7 +534,7 @@ void TypesParser::ProcessRecord() {
Type *BaseTy = Context->getTypeByID(Values[1]); Type *BaseTy = Context->getTypeByID(Values[1]);
Ty = Context->getLLVMVectorType(Values[0], Ty = Context->getLLVMVectorType(Values[0],
Context->convertToIceType(BaseTy)); Context->convertToIceType(BaseTy));
if (Ty == NULL) { if (Ty == nullptr) {
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid type vector record: <" << Values[0] << " x " << *BaseTy StrBuf << "Invalid type vector record: <" << Values[0] << " x " << *BaseTy
...@@ -552,7 +560,7 @@ void TypesParser::ProcessRecord() { ...@@ -552,7 +560,7 @@ void TypesParser::ProcessRecord() {
return; return;
} }
// If Ty not defined, assume error. Use void as filler. // If Ty not defined, assume error. Use void as filler.
if (Ty == NULL) if (Ty == nullptr)
Ty = Context->convertToLLVMType(Ice::IceType_void); Ty = Context->convertToLLVMType(Ice::IceType_void);
Context->setTypeID(NextTypeId++, Ty); Context->setTypeID(NextTypeId++, Ty);
} }
...@@ -562,38 +570,33 @@ class GlobalsParser : public BlockParserBaseClass { ...@@ -562,38 +570,33 @@ class GlobalsParser : public BlockParserBaseClass {
public: public:
GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser) GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: BlockParserBaseClass(BlockID, EnclosingParser), InitializersNeeded(0), : BlockParserBaseClass(BlockID, EnclosingParser), InitializersNeeded(0),
Alignment(1), IsConstant(false) { NextGlobalID(0), CurrentAddress(&DummyAddress) {}
NextGlobalID = Context->getNumFunctionIDs();
}
~GlobalsParser() override {} ~GlobalsParser() override {}
private: private:
// Holds the sequence of initializers for the global. // Keeps track of how many initializers are expected for the global variable
SmallVector<Constant *, 10> Initializers; // being built.
// Keeps track of how many initializers are expected for
// the global variable being built.
unsigned InitializersNeeded; unsigned InitializersNeeded;
// The alignment assumed for the global variable being built.
unsigned Alignment;
// True if the global variable being built is a constant.
bool IsConstant;
// The index of the next global variable. // The index of the next global variable.
unsigned NextGlobalID; unsigned NextGlobalID;
// Holds the current global address whose initializer is being defined.
Ice::GlobalAddress *CurrentAddress;
// Dummy global address to guarantee CurrentAddress is always defined
// (allowing code to not need to check if CurrentAddress is nullptr).
Ice::GlobalAddress DummyAddress;
void ExitBlock() override { void ExitBlock() override {
verifyNoMissingInitializers(); verifyNoMissingInitializers();
unsigned NumIDs = Context->getNumGlobalValueIDs(); unsigned NumIDs = Context->getNumGlobalAddresses();
if (NextGlobalID < NumIDs) { if (NextGlobalID < NumIDs) {
unsigned NumFcnIDs = Context->getNumFunctionIDs();
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Globals block expects " << (NumIDs - NumFcnIDs) StrBuf << "Globals block expects " << NumIDs
<< " global definitions. Found: " << (NextGlobalID - NumFcnIDs); << " global definitions. Found: " << NextGlobalID;
Error(StrBuf.str()); Error(StrBuf.str());
} }
BlockParserBaseClass::ExitBlock(); BlockParserBaseClass::ExitBlock();
...@@ -601,70 +604,22 @@ private: ...@@ -601,70 +604,22 @@ private:
void ProcessRecord() override; void ProcessRecord() override;
// Checks if the number of initializers needed is the same as the // Checks if the number of initializers for the CurrentAddress is the same as
// number found in the bitcode file. If different, and error message // the number found in the bitcode file. If different, and error message is
// is generated, and the internal state of the parser is fixed so // generated, and the internal state of the parser is fixed so this condition
// this condition is no longer violated. // is no longer violated.
void verifyNoMissingInitializers() { void verifyNoMissingInitializers() {
if (InitializersNeeded != Initializers.size()) { size_t NumInits = CurrentAddress->getInitializers().size();
if (InitializersNeeded != NumInits) {
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Global variable @g" StrBuf << "Global variable @g" << NextGlobalID << " expected "
<< (NextGlobalID - Context->getNumFunctionIDs()) << " expected "
<< InitializersNeeded << " initializer"; << InitializersNeeded << " initializer";
if (InitializersNeeded > 1) if (InitializersNeeded > 1)
StrBuf << "s"; StrBuf << "s";
StrBuf << ". Found: " << Initializers.size(); StrBuf << ". Found: " << NumInits;
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
// Fix up state so that we can continue.
InitializersNeeded = Initializers.size();
installGlobalVar();
}
}
// Reserves a slot in the list of initializers being built. If there
// isn't room for the slot, an error message is generated.
void reserveInitializer(const char *RecordName) {
if (InitializersNeeded <= Initializers.size()) {
Error(std::string(RecordName) +
" record: Too many initializers, ignoring.");
}
}
// Takes the initializers (and other parser state values) and
// installs a global variable (with the initializers) into the list
// of ValueIDs.
void installGlobalVar() {
Constant *Init = NULL;
switch (Initializers.size()) {
case 0:
Error("No initializer for global variable in global vars block");
return;
case 1:
Init = Initializers[0];
break;
default:
Init = ConstantStruct::getAnon(Context->getLLVMContext(), Initializers,
true);
break;
}
GlobalVariable *GV =
new GlobalVariable(*Context->getModule(), Init->getType(), IsConstant,
GlobalValue::InternalLinkage, Init, "");
GV->setAlignment(Alignment);
if (!Context->assignGlobalVariable(GV, NextGlobalID)) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Defining global V[" << NextGlobalID
<< "] not allowed. Out of range.";
Error(StrBuf.str()); Error(StrBuf.str());
} }
++NextGlobalID;
Initializers.clear();
InitializersNeeded = 0;
Alignment = 1;
IsConstant = false;
} }
}; };
...@@ -675,12 +630,11 @@ void GlobalsParser::ProcessRecord() { ...@@ -675,12 +630,11 @@ void GlobalsParser::ProcessRecord() {
// COUNT: [n] // COUNT: [n]
if (!isValidRecordSize(1, "Globals count")) if (!isValidRecordSize(1, "Globals count"))
return; return;
if (NextGlobalID != Context->getNumFunctionIDs()) { if (NextGlobalID != Context->getNumGlobalAddresses()) {
Error("Globals count record not first in block."); Error("Globals count record not first in block.");
return; return;
} }
verifyNoMissingInitializers(); Context->CreateGlobalAddresses(Values[0]);
Context->resizeValueIDsForGlobalVarCount(Values[0]);
return; return;
case naclbitc::GLOBALVAR_VAR: { case naclbitc::GLOBALVAR_VAR: {
// VAR: [align, isconst] // VAR: [align, isconst]
...@@ -688,16 +642,17 @@ void GlobalsParser::ProcessRecord() { ...@@ -688,16 +642,17 @@ void GlobalsParser::ProcessRecord() {
return; return;
verifyNoMissingInitializers(); verifyNoMissingInitializers();
InitializersNeeded = 1; InitializersNeeded = 1;
Initializers.clear(); CurrentAddress = Context->getGlobalAddress(NextGlobalID);
Alignment = (1 << Values[0]) >> 1; CurrentAddress->setAlignment((1 << Values[0]) >> 1);
IsConstant = Values[1] != 0; CurrentAddress->setIsConstant(Values[1] != 0);
++NextGlobalID;
return; return;
} }
case naclbitc::GLOBALVAR_COMPOUND: case naclbitc::GLOBALVAR_COMPOUND:
// COMPOUND: [size] // COMPOUND: [size]
if (!isValidRecordSize(1, "globals compound")) if (!isValidRecordSize(1, "globals compound"))
return; return;
if (Initializers.size() > 0 || InitializersNeeded != 1) { if (!CurrentAddress->getInitializers().empty()) {
Error("Globals compound record not first initializer"); Error("Globals compound record not first initializer");
return; return;
} }
...@@ -714,55 +669,44 @@ void GlobalsParser::ProcessRecord() { ...@@ -714,55 +669,44 @@ void GlobalsParser::ProcessRecord() {
// ZEROFILL: [size] // ZEROFILL: [size]
if (!isValidRecordSize(1, "Globals zerofill")) if (!isValidRecordSize(1, "Globals zerofill"))
return; return;
reserveInitializer("Globals zerofill"); CurrentAddress->addInitializer(
Type *Ty = new Ice::GlobalAddress::ZeroInitializer(Values[0]));
ArrayType::get(Context->convertToLLVMType(Ice::IceType_i8), Values[0]);
Constant *Zero = ConstantAggregateZero::get(Ty);
Initializers.push_back(Zero);
break; break;
} }
case naclbitc::GLOBALVAR_DATA: { case naclbitc::GLOBALVAR_DATA: {
// DATA: [b0, b1, ...] // DATA: [b0, b1, ...]
if (!isValidRecordSizeAtLeast(1, "Globals data")) if (!isValidRecordSizeAtLeast(1, "Globals data"))
return; return;
reserveInitializer("Globals data"); CurrentAddress->addInitializer(
unsigned Size = Values.size(); new Ice::GlobalAddress::DataInitializer(Values));
SmallVector<uint8_t, 32> Buf;
for (unsigned i = 0; i < Size; ++i)
Buf.push_back(static_cast<uint8_t>(Values[i]));
Constant *Init = ConstantDataArray::get(
Context->getLLVMContext(), ArrayRef<uint8_t>(Buf.data(), Buf.size()));
Initializers.push_back(Init);
break; break;
} }
case naclbitc::GLOBALVAR_RELOC: { case naclbitc::GLOBALVAR_RELOC: {
// RELOC: [val, [addend]] // RELOC: [val, [addend]]
if (!isValidRecordSizeInRange(1, 2, "Globals reloc")) if (!isValidRecordSizeInRange(1, 2, "Globals reloc"))
return; return;
Constant *BaseVal = Context->getOrCreateGlobalVarRef(Values[0]); unsigned Index = Values[0];
if (BaseVal == NULL) { Ice::SizeT Offset = 0;
std::string Buffer; if (Values.size() == 2)
raw_string_ostream StrBuf(Buffer); Offset = Values[1];
StrBuf << "Can't find global relocation value: " << Values[0]; unsigned NumFunctions = Context->getNumFunctionIDs();
Error(StrBuf.str()); if (Index < NumFunctions) {
return; llvm::Function *Fcn = Context->getFunctionByID(Index);
} Ice::GlobalAddress::RelocationAddress Addr(Fcn);
Type *IntPtrType = Context->convertToLLVMType(Context->getIcePointerType()); CurrentAddress->addInitializer(
Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType); new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
if (Values.size() == 2) { } else {
Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType, Values[1])); Ice::GlobalAddress::RelocationAddress Addr(
Context->getGlobalAddress(Index - NumFunctions));
CurrentAddress->addInitializer(
new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
} }
Initializers.push_back(Val);
break; break;
} }
default: default:
BlockParserBaseClass::ProcessRecord(); BlockParserBaseClass::ProcessRecord();
return; return;
} }
// If reached, just processed another initializer. See if time
// to install global.
if (InitializersNeeded == Initializers.size())
installGlobalVar();
} }
/// Base class for parsing a valuesymtab block in the bitcode file. /// Base class for parsing a valuesymtab block in the bitcode file.
...@@ -838,9 +782,9 @@ public: ...@@ -838,9 +782,9 @@ public:
: BlockParserBaseClass(BlockID, EnclosingParser), : BlockParserBaseClass(BlockID, EnclosingParser),
Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0), Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
FcnId(Context->getNextFunctionBlockValueID()), FcnId(Context->getNextFunctionBlockValueID()),
LLVMFunc(cast<Function>(Context->getGlobalValueByID(FcnId))), LLVMFunc(Context->getFunctionByID(FcnId)),
CachedNumGlobalValueIDs(Context->getNumGlobalValueIDs()), CachedNumGlobalValueIDs(Context->getNumGlobalIDs()),
NextLocalInstIndex(Context->getNumGlobalValueIDs()), NextLocalInstIndex(Context->getNumGlobalIDs()),
InstIsTerminating(false) { InstIsTerminating(false) {
Func->setFunctionName(LLVMFunc->getName()); Func->setFunctionName(LLVMFunc->getName());
if (getFlags().TimeEachFunction) if (getFlags().TimeEachFunction)
...@@ -961,7 +905,7 @@ private: ...@@ -961,7 +905,7 @@ private:
uint32_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs; uint32_t LocalIndex = NextLocalInstIndex - CachedNumGlobalValueIDs;
if (LocalIndex < LocalOperands.size()) { if (LocalIndex < LocalOperands.size()) {
Ice::Operand *Op = LocalOperands[LocalIndex]; Ice::Operand *Op = LocalOperands[LocalIndex];
if (Op != NULL) { if (Op != nullptr) {
if (Ice::Variable *Var = dyn_cast<Ice::Variable>(Op)) { if (Ice::Variable *Var = dyn_cast<Ice::Variable>(Op)) {
if (Var->getType() == Ty) { if (Var->getType() == Ty) {
++NextLocalInstIndex; ++NextLocalInstIndex;
...@@ -1012,7 +956,7 @@ private: ...@@ -1012,7 +956,7 @@ private:
report_fatal_error("Unable to continue"); report_fatal_error("Unable to continue");
} }
Ice::Operand *Op = LocalOperands[LocalIndex]; Ice::Operand *Op = LocalOperands[LocalIndex];
if (Op == NULL) { if (Op == nullptr) {
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Value index " << Index << " not defined!"; StrBuf << "Value index " << Index << " not defined!";
...@@ -1038,7 +982,7 @@ private: ...@@ -1038,7 +982,7 @@ private:
// If element not defined, set it. // If element not defined, set it.
Ice::Operand *OldOp = LocalOperands[LocalIndex]; Ice::Operand *OldOp = LocalOperands[LocalIndex];
if (OldOp == NULL) { if (OldOp == nullptr) {
LocalOperands[LocalIndex] = Op; LocalOperands[LocalIndex] = Op;
return; return;
} }
...@@ -1688,7 +1632,7 @@ void FunctionParser::ProcessRecord() { ...@@ -1688,7 +1632,7 @@ void FunctionParser::ProcessRecord() {
if (Values.size() == 1) { if (Values.size() == 1) {
// BR: [bb#] // BR: [bb#]
Ice::CfgNode *Block = getBranchBasicBlock(Values[0]); Ice::CfgNode *Block = getBranchBasicBlock(Values[0]);
if (Block == NULL) if (Block == nullptr)
return; return;
CurrentNode->appendInst(Ice::InstBr::create(Func, Block)); CurrentNode->appendInst(Ice::InstBr::create(Func, Block));
} else { } else {
...@@ -1706,7 +1650,7 @@ void FunctionParser::ProcessRecord() { ...@@ -1706,7 +1650,7 @@ void FunctionParser::ProcessRecord() {
} }
Ice::CfgNode *ThenBlock = getBranchBasicBlock(Values[0]); Ice::CfgNode *ThenBlock = getBranchBasicBlock(Values[0]);
Ice::CfgNode *ElseBlock = getBranchBasicBlock(Values[1]); Ice::CfgNode *ElseBlock = getBranchBasicBlock(Values[1]);
if (ThenBlock == NULL || ElseBlock == NULL) if (ThenBlock == nullptr || ElseBlock == nullptr)
return; return;
CurrentNode->appendInst( CurrentNode->appendInst(
Ice::InstBr::create(Func, Cond, ThenBlock, ElseBlock)); Ice::InstBr::create(Func, Cond, ThenBlock, ElseBlock));
...@@ -1907,11 +1851,10 @@ void FunctionParser::ProcessRecord() { ...@@ -1907,11 +1851,10 @@ void FunctionParser::ProcessRecord() {
uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex); uint32_t CalleeIndex = convertRelativeToAbsIndex(Values[1], BaseIndex);
Ice::Operand *Callee = getOperand(CalleeIndex); Ice::Operand *Callee = getOperand(CalleeIndex);
Ice::Type ReturnType = Ice::IceType_void; Ice::Type ReturnType = Ice::IceType_void;
const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = NULL; const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr;
if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) { if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
Function *Fcn = Function *Fcn = Context->getFunctionByID(CalleeIndex);
dyn_cast<Function>(Context->getGlobalValueByID(CalleeIndex)); if (Fcn == nullptr) {
if (Fcn == NULL) {
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Function call to non-function: " << *Callee; StrBuf << "Function call to non-function: " << *Callee;
...@@ -1942,10 +1885,11 @@ void FunctionParser::ProcessRecord() { ...@@ -1942,10 +1885,11 @@ void FunctionParser::ProcessRecord() {
} }
// Create the call instruction. // Create the call instruction.
Ice::Variable *Dest = Ice::Variable *Dest = (ReturnType == Ice::IceType_void)
(ReturnType == Ice::IceType_void) ? NULL : getNextInstVar(ReturnType); ? nullptr
: getNextInstVar(ReturnType);
Ice::SizeT NumParams = Values.size() - ParamsStartIndex; Ice::SizeT NumParams = Values.size() - ParamsStartIndex;
Ice::InstCall *Inst = NULL; Ice::InstCall *Inst = nullptr;
if (IntrinsicInfo) { if (IntrinsicInfo) {
Inst = Inst =
Ice::InstIntrinsicCall::create(Func, NumParams, Dest, Callee, Ice::InstIntrinsicCall::create(Func, NumParams, Dest, Callee,
...@@ -2225,15 +2169,29 @@ private: ...@@ -2225,15 +2169,29 @@ private:
// and generated global constant initializers. // and generated global constant initializers.
bool GlobalAddressNamesAndInitializersInstalled; bool GlobalAddressNamesAndInitializersInstalled;
// Temporary hack to generate names for unnamed global addresses, // Generates names for unnamed global addresses, and lowers global
// and generate global constant initializers. May be called multiple // constant initializers to the target. May be called multiple
// times. Only the first call will do the installation. // times. Only the first call will do the installation.
// NOTE: Doesn't handle relocations for global constant initializers.
void InstallGlobalAddressNamesAndInitializers() { void InstallGlobalAddressNamesAndInitializers() {
if (!GlobalAddressNamesAndInitializersInstalled) { if (!GlobalAddressNamesAndInitializersInstalled) {
getTranslator().nameUnnamedGlobalAddresses(Context->getModule()); Ice::Translator &Trans = getTranslator();
const Ice::IceString &GlobalPrefix = getFlags().DefaultGlobalPrefix;
if (!GlobalPrefix.empty()) {
uint32_t NameIndex = 0;
for (Ice::GlobalAddress *Address : Context->getGlobalIDAddresses()) {
if (!Address->hasName()) {
Address->setName(Trans.createUnnamedName(GlobalPrefix, NameIndex));
++NameIndex;
} else {
Trans.checkIfUnnamedNameSafe(Address->getName(), "global",
GlobalPrefix,
Trans.getContext()->getStrDump());
}
}
}
Trans.nameUnnamedFunctions(Context->getModule());
if (!getFlags().DisableGlobals) if (!getFlags().DisableGlobals)
getTranslator().convertGlobals(Context->getModule()); getTranslator().lowerGlobals(Context->getGlobalIDAddresses());
GlobalAddressNamesAndInitializersInstalled = true; GlobalAddressNamesAndInitializersInstalled = true;
} }
} }
...@@ -2264,15 +2222,26 @@ private: ...@@ -2264,15 +2222,26 @@ private:
}; };
void ModuleValuesymtabParser::setValueName(uint64_t Index, StringType &Name) { void ModuleValuesymtabParser::setValueName(uint64_t Index, StringType &Name) {
Value *V = Context->getGlobalValueByID(Index); if (Index < Context->getNumFunctionIDs()) {
if (V == NULL) { Function *Fcn = Context->getFunctionByID(Index);
std::string Buffer; if (Fcn != nullptr) {
raw_string_ostream StrBuf(Buffer); Fcn->setName(StringRef(Name.data(), Name.size()));
StrBuf << "Invalid global address ID in valuesymtab: " << Index; return;
Error(StrBuf.str()); }
} else {
unsigned NumFunctions = Context->getNumFunctionIDs();
if (Index >= NumFunctions) {
Context->getGlobalAddress(Index - NumFunctions)
->setName(StringRef(Name.data(), Name.size()));
}
return; return;
} }
V->setName(StringRef(Name.data(), Name.size()));
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid global address ID in valuesymtab: " << Index;
Error(StrBuf.str());
return;
} }
void ModuleValuesymtabParser::setBbName(uint64_t Index, StringType &Name) { void ModuleValuesymtabParser::setBbName(uint64_t Index, StringType &Name) {
...@@ -2331,7 +2300,7 @@ void ModuleParser::ProcessRecord() { ...@@ -2331,7 +2300,7 @@ void ModuleParser::ProcessRecord() {
return; return;
Type *Ty = Context->getTypeByID(Values[0]); Type *Ty = Context->getTypeByID(Values[0]);
FunctionType *FTy = dyn_cast<FunctionType>(Ty); FunctionType *FTy = dyn_cast<FunctionType>(Ty);
if (FTy == NULL) { if (FTy == nullptr) {
std::string Buffer; std::string Buffer;
raw_string_ostream StrBuf(Buffer); raw_string_ostream StrBuf(Buffer);
StrBuf << "Function heading expects function type. Found: " << Ty; StrBuf << "Function heading expects function type. Found: " << Ty;
......
...@@ -65,6 +65,9 @@ static cl::opt<bool> UseSandboxing("sandbox", cl::desc("Use sandboxing")); ...@@ -65,6 +65,9 @@ static cl::opt<bool> UseSandboxing("sandbox", cl::desc("Use sandboxing"));
static cl::opt<bool> static cl::opt<bool>
FunctionSections("ffunction-sections", FunctionSections("ffunction-sections",
cl::desc("Emit functions into separate sections")); cl::desc("Emit functions into separate sections"));
static cl::opt<bool>
DataSections("fdata-sections",
cl::desc("Emit (global) data into separate sections"));
static cl::opt<Ice::OptLevel> static cl::opt<Ice::OptLevel>
OptLevel(cl::desc("Optimization level"), cl::init(Ice::Opt_m1), OptLevel(cl::desc("Optimization level"), cl::init(Ice::Opt_m1),
cl::value_desc("level"), cl::value_desc("level"),
...@@ -121,6 +124,11 @@ static cl::opt<bool> ...@@ -121,6 +124,11 @@ static cl::opt<bool>
DumpStats("stats", DumpStats("stats",
cl::desc("Print statistics after translating each function")); cl::desc("Print statistics after translating each function"));
// This is currently needed by crosstest.py.
static cl::opt<bool> AllowUninitializedGlobals(
"allow-uninitialized-globals",
cl::desc("Allow global variables to be uninitialized"));
static cl::opt<NaClFileFormat> InputFileFormat( static cl::opt<NaClFileFormat> InputFileFormat(
"bitcode-format", cl::desc("Define format of input file:"), "bitcode-format", cl::desc("Define format of input file:"),
cl::values(clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"), cl::values(clEnumValN(LLVMFormat, "llvm", "LLVM file (default)"),
...@@ -149,9 +157,20 @@ static cl::opt<bool> ...@@ -149,9 +157,20 @@ static cl::opt<bool>
UseIntegratedAssembler("integrated-as", UseIntegratedAssembler("integrated-as",
cl::desc("Use integrated assembler (default yes)"), cl::desc("Use integrated assembler (default yes)"),
cl::init(true)); cl::init(true));
static cl::alias UseIas("ias", cl::desc("Alias for -integrated-as"), static cl::alias UseIas("ias", cl::desc("Alias for -integrated-as"),
cl::NotHidden, cl::aliasopt(UseIntegratedAssembler)); cl::NotHidden, cl::aliasopt(UseIntegratedAssembler));
static cl::opt<bool> AlwaysExitSuccess(
"exit-success", cl::desc("Exit with success status, even if errors found"),
cl::init(false));
static int GetReturnValue(int Val) {
if (AlwaysExitSuccess)
return 0;
return Val;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv); cl::ParseCommandLineOptions(argc, argv);
...@@ -180,9 +199,11 @@ int main(int argc, char **argv) { ...@@ -180,9 +199,11 @@ int main(int argc, char **argv) {
Flags.DisableTranslation = DisableTranslation; Flags.DisableTranslation = DisableTranslation;
Flags.DisableGlobals = DisableGlobals; Flags.DisableGlobals = DisableGlobals;
Flags.FunctionSections = FunctionSections; Flags.FunctionSections = FunctionSections;
Flags.DataSections = DataSections;
Flags.UseIntegratedAssembler = UseIntegratedAssembler; Flags.UseIntegratedAssembler = UseIntegratedAssembler;
Flags.UseSandboxing = UseSandboxing; Flags.UseSandboxing = UseSandboxing;
Flags.DumpStats = DumpStats; Flags.DumpStats = DumpStats;
Flags.AllowUninitializedGlobals = AllowUninitializedGlobals;
Flags.TimeEachFunction = TimeEachFunction; Flags.TimeEachFunction = TimeEachFunction;
Flags.DefaultGlobalPrefix = DefaultGlobalPrefix; Flags.DefaultGlobalPrefix = DefaultGlobalPrefix;
Flags.DefaultFunctionPrefix = DefaultFunctionPrefix; Flags.DefaultFunctionPrefix = DefaultFunctionPrefix;
...@@ -207,7 +228,7 @@ int main(int argc, char **argv) { ...@@ -207,7 +228,7 @@ int main(int argc, char **argv) {
if (!Mod) { if (!Mod) {
Err.print(argv[0], errs()); Err.print(argv[0], errs());
return 1; return GetReturnValue(1);
} }
Ice::Converter Converter(Mod, &Ctx, Flags); Ice::Converter Converter(Mod, &Ctx, Flags);
...@@ -222,5 +243,5 @@ int main(int argc, char **argv) { ...@@ -222,5 +243,5 @@ int main(int argc, char **argv) {
Ctx.dumpTimers(); Ctx.dumpTimers();
const bool FinalStats = true; const bool FinalStats = true;
Ctx.dumpStats("_FINAL_", FinalStats); Ctx.dumpStats("_FINAL_", FinalStats);
return ErrorStatus; return GetReturnValue(ErrorStatus);
} }
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
; RUN: %lc2i -i %s --args --verbose inst | FileCheck %s ; RUN: %lc2i -i %s --args --verbose inst | FileCheck %s
; RUN: %lc2i -i %s --args --verbose none | FileCheck --check-prefix=ERRORS %s ; RUN: %lc2i -i %s --args --verbose none | FileCheck --check-prefix=ERRORS %s
; Note: PNaCl ABI Doesn't allow external globals. Hence, not tested.
@intern_global = internal global [4 x i8] c"\00\00\00\0C", 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() { define i32 @test_intern_global() {
; CHECK: define i32 @test_intern_global ; CHECK: define i32 @test_intern_global
...@@ -16,12 +16,4 @@ entry: ...@@ -16,12 +16,4 @@ entry:
ret i32 %v0 ret i32 %v0
} }
define i32 @test_extern_global() {
; CHECK: define i32 @test_extern_global
entry:
%__1 = bitcast [4 x i8]* @extern_global to i32*
%v0 = load i32* %__1, align 1
ret i32 %v0
}
; ERRORS-NOT: ICE translation error ; ERRORS-NOT: ICE translation error
; Tests that we name unnamed global addresses.
; RUN: %p2i -i %s --insts | FileCheck %s
; RUN: %p2i -i %s --insts --args -default-function-prefix=h \
; RUN: -default-global-prefix=g | FileCheck --check-prefix=BAD %s
@0 = internal global [4 x i8] zeroinitializer, align 4
; CHECK: @Global = internal global [4 x i8] zeroinitializer, align 4
@1 = internal constant [10 x i8] c"Some stuff", align 1
; CHECK-NEXT: @Global1 = internal constant [10 x i8] c"Some stuff", align 1
@g = internal global [4 x i8] zeroinitializer, align 4
; BAD: Warning: Default global prefix 'g' conflicts with name 'g'.
; CHECK-NEXT: @g = internal global [4 x i8] zeroinitializer, align 4
define i32 @2(i32 %v) {
ret i32 %v
}
; CHECK-NEXT: define i32 @Function(i32 %v) {
; CHECK-NEXT: __0:
; CHECK-NEXT: ret i32 %v
; CHECK-NEXT: }
define void @hg() {
ret void
}
; BAD: Warning: Default function prefix 'h' conflicts with name 'hg'.
; CHECK-NEXT: define void @hg() {
; CHECK-NEXT: __0:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
define void @3() {
ret void
}
; CHECK-NEXT: define void @Function1() {
; CHECK-NEXT: __0:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
; Tests if we handle global variables with relocation initializers.
; Test that we handle it in the ICE converter.
; RUN: %lc2i -i %s --insts | FileCheck %s
; Test that we handle it using Subzero's bitcode reader.
; RUN: %p2i -i %s --insts | FileCheck %s
@bytes = internal global [7 x i8] c"abcdefg"
; CHECK: @bytes = internal global [7 x i8] c"abcdefg"
@const_bytes = internal constant [7 x i8] c"abcdefg"
; CHECK-NEXT: @const_bytes = internal constant [7 x i8] c"abcdefg"
@ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32)
; CHECK-NEXT: @ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32)
@const_ptr_to_ptr = internal constant i32 ptrtoint (i32* @ptr to i32)
; CHECK-NEXT: @const_ptr_to_ptr = internal constant i32 ptrtoint (i32* @ptr to i32)
@ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32)
; CHECK-NEXT: @ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32)
@const_ptr_to_func = internal constant i32 ptrtoint (void ()* @func to i32)
; CHECK-NEXT: @const_ptr_to_func = internal constant i32 ptrtoint (void ()* @func to i32)
@compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK-NEXT: @compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
@const_compound = internal constant <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK-NEXT: @const_compound = internal constant <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
@ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32)
; CHECK-NEXT: @ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32)
@const_ptr = internal constant i32 ptrtoint ([7 x i8]* @bytes to i32)
; CHECK-NEXT: @const_ptr = internal constant i32 ptrtoint ([7 x i8]* @bytes to i32)
@addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK-NEXT: @addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
@const_addend_ptr = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK-NEXT: @const_addend_ptr = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
@addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
; CHECK-NEXT: @addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
@const_addend_negative = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
; CHECK-NEXT: @const_addend_negative = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
@addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
; CHECK-NEXT: @addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
@const_addend_array1 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
; CHECK-NEXT: @const_addend_array1 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
@addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
; CHECK-NEXT: @addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
@const_addend_array2 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
; CHECK-NEXT: @const_addend_array2 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
@addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
; CHECK-NEXT: @addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
@const_addend_array3 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
; CHECK-NEXT: @const_addend_array3 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
@addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
; CHECK-NEXT: @addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
@const_addend_struct1 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
; CHECK-NEXT: @const_addend_struct1 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
@addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK-NEXT: @addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
@const_addend_struct2 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK-NEXT: @const_addend_struct2 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
@ptr_to_func_align = internal global i32 ptrtoint (void ()* @func to i32), align 8
; CHECK-NEXT: @ptr_to_func_align = internal global i32 ptrtoint (void ()* @func to i32), align 8
@const_ptr_to_func_align = internal constant i32 ptrtoint (void ()* @func to i32), align 8
; CHECK-NEXT: @const_ptr_to_func_align = internal constant i32 ptrtoint (void ()* @func to i32), align 8
@char = internal constant [1 x i8] c"0"
; CHECK-NEXT: @char = internal constant [1 x i8] c"0"
@short = internal constant [2 x i8] zeroinitializer
; CHECK-NEXT: @short = internal constant [2 x i8] zeroinitializer
define void @func() {
ret void
}
; CHECK-NEXT: define void @func() {
; Tests that we name unnamed global addresses. ; Tests that we name unnamed global addresses.
; Check that the ICE converter handles renaming correctly.
; RUN: %l2i --no-local-syms -i %s --insts | FileCheck %s
; RUN: %l2i --no-local-syms -i %s --insts --args --exit-success \
; RUN: -default-function-prefix=h -default-global-prefix=g \
; RUN: | FileCheck --check-prefix=BAD %s
; Check that Subzero's bitcode reader handles renaming correctly.
; RUN: %p2i --no-local-syms -i %s --insts | FileCheck %s ; RUN: %p2i --no-local-syms -i %s --insts | FileCheck %s
; RUN: %p2i --no-local-syms -i %s --insts --args \ ; RUN: %p2i --no-local-syms -i %s --insts --args --exit-success \
; RUN: -default-function-prefix=h -default-global-prefix=g \ ; RUN: -default-function-prefix=h -default-global-prefix=g \
; RUN: | FileCheck --check-prefix=BAD %s ; RUN: | FileCheck --check-prefix=BAD %s
...@@ -12,8 +20,6 @@ ...@@ -12,8 +20,6 @@
@1 = internal constant [10 x i8] c"Some stuff", align 1 @1 = internal constant [10 x i8] c"Some stuff", align 1
@g = internal global [4 x i8] zeroinitializer, align 4 @g = internal global [4 x i8] zeroinitializer, align 4
; BAD: Warning: Default global prefix 'g' conflicts with name 'g'.
define i32 @2(i32 %v) { define i32 @2(i32 %v) {
ret i32 %v ret i32 %v
} }
...@@ -27,7 +33,6 @@ define void @hg() { ...@@ -27,7 +33,6 @@ define void @hg() {
ret void ret void
} }
; BAD: Warning: Default function prefix 'h' conflicts with name 'hg'.
; CHECK-NEXT: define void @hg() { ; CHECK-NEXT: define void @hg() {
; CHECK-NEXT: __0: ; CHECK-NEXT: __0:
...@@ -42,3 +47,15 @@ define void @3() { ...@@ -42,3 +47,15 @@ define void @3() {
; CHECK-NEXT: __0: ; CHECK-NEXT: __0:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; CHECK-NEXT: } ; CHECK-NEXT: }
define void @h5() {
ret void
}
; CHECK-NEXT: define void @h5() {
; CHECK-NEXT: __0:
; CHECK-NEXT: ret void
; CHECK-NEXT: }
; BAD: Warning : Default global prefix 'g' potentially conflicts with name 'g'.
; BAD: Warning : Default function prefix 'h' potentially conflicts with name 'h5'.
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