Commit 9d98d791 by Karl Schimpf

Introduce the notion of function addresses in Subzero.

Introduces the notion of a function address, to replace using LLVM IR's Function class. Modifies Ice converter, and Subzero's bitcode reader, to build function addresses. BUG=None R=jvoung@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/641193002
parent d026c448
......@@ -23,6 +23,16 @@ namespace Subzero_ {
#include "test_global.h"
}
int ExternName1 = 36363;
float ExternName2 = 357.05e-10;
char ExternName3[] = {'a', 'b', 'c'};
struct {
int a;
float b;
double d;
} ExternName4 = {-111, 2.69, 55.19};
double ExternName5 = 3.44e26;
int main(int argc, char **argv) {
size_t TotalTests = 0;
size_t Passes = 0;
......
......@@ -34,6 +34,7 @@
#include "IceTypes.h"
#include "IceTypeConverter.h"
// TODO(kschimpf): Remove two namespaces being visible at once.
using namespace llvm;
namespace {
......@@ -52,11 +53,14 @@ class LLVM2ICEConverter {
LLVM2ICEConverter &operator=(const LLVM2ICEConverter &) = delete;
public:
LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: Ctx(Ctx), TypeConverter(LLVMContext) {}
LLVM2ICEConverter(Ice::Converter &Converter)
: Converter(Converter), Ctx(Converter.getContext()),
TypeConverter(Converter.getModule()->getContext()) {}
Ice::Converter &getConverter() const { return Converter; }
protected:
// Data
Ice::Converter &Converter;
Ice::GlobalContext *Ctx;
const Ice::TypeConverter TypeConverter;
};
......@@ -72,8 +76,8 @@ class LLVM2ICEFunctionConverter : LLVM2ICEConverter {
operator=(const LLVM2ICEFunctionConverter &) = delete;
public:
LLVM2ICEFunctionConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: LLVM2ICEConverter(Ctx, LLVMContext), Func(NULL) {}
LLVM2ICEFunctionConverter(Ice::Converter &Converter)
: LLVM2ICEConverter(Converter), Func(nullptr) {}
// Caller is expected to delete the returned Ice::Cfg object.
Ice::Cfg *convertFunction(const Function *F) {
......@@ -126,12 +130,12 @@ public:
else if (Type == Ice::IceType_f64)
return Ctx->getConstantDouble(CFP->getValueAPF().convertToDouble());
llvm_unreachable("Unexpected floating point type");
return NULL;
return nullptr;
} else if (const auto CU = dyn_cast<UndefValue>(Const)) {
return Ctx->getConstantUndef(convertToIceType(CU->getType()));
} else {
llvm_unreachable("Unhandled constant type");
return NULL;
return nullptr;
}
}
......@@ -141,7 +145,7 @@ private:
// and a version that just uses convertToIceType on V.
Ice::Variable *mapValueToIceVar(const Value *V, Ice::Type IceTy) {
if (IceTy == Ice::IceType_void)
return NULL;
return nullptr;
if (VarMap.find(V) == VarMap.end()) {
VarMap[V] = Func->makeVariable(IceTy, V->getName());
}
......@@ -169,10 +173,10 @@ private:
// Given an LLVM instruction and an operand number, produce the
// Ice::Operand this refers to. If there's no such operand, return
// NULL.
// nullptr.
Ice::Operand *convertOperand(const Instruction *Inst, unsigned OpNum) {
if (OpNum >= Inst->getNumOperands()) {
return NULL;
return nullptr;
}
const Value *Op = Inst->getOperand(OpNum);
return convertValue(Op);
......@@ -292,7 +296,7 @@ private:
}
llvm_unreachable("convertInstruction");
return NULL;
return nullptr;
}
Ice::Inst *convertLoadInstruction(const LoadInst *Inst) {
......@@ -524,8 +528,8 @@ private:
unsigned NumArgs = Inst->getNumArgOperands();
// Note: Subzero doesn't (yet) do anything special with the Tail
// flag in the bitcode, i.e. CallInst::isTailCall().
Ice::InstCall *NewInst = NULL;
const Ice::Intrinsics::FullIntrinsicInfo *Info = NULL;
Ice::InstCall *NewInst = nullptr;
const Ice::Intrinsics::FullIntrinsicInfo *Info = nullptr;
if (const auto Target = dyn_cast<Ice::ConstantRelocatable>(CallTarget)) {
// Check if this direct call is to an Intrinsic (starts with "llvm.")
......@@ -545,7 +549,7 @@ private:
}
// Not an intrinsic call.
if (NewInst == NULL) {
if (NewInst == nullptr) {
NewInst = Ice::InstCall::create(Func, NumArgs, Dest, CallTarget,
Inst->isTailCall());
}
......@@ -636,48 +640,37 @@ class LLVM2ICEGlobalsConverter : public LLVM2ICEConverter {
operator-(const LLVM2ICEGlobalsConverter &) = delete;
public:
LLVM2ICEGlobalsConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: LLVM2ICEConverter(Ctx, LLVMContext) {}
~LLVM2ICEGlobalsConverter() { DeleteContainerSeconds(GlobalVarAddressMap); }
LLVM2ICEGlobalsConverter(Ice::Converter &Converter)
: LLVM2ICEConverter(Converter) {}
/// 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);
/// Converts global variables, and their initializers into ICE
/// global variable declarations, for module Mod. Puts corresponding
/// converted declarations into VariableDeclarations.
void convertGlobalsToIce(
Module *Mod,
Ice::Translator::VariableDeclarationListType &VariableDeclarations);
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,
// Adds the Initializer to the list of initializers for the Global
// variable declaraation.
void addGlobalInitializer(Ice::VariableDeclaration &Global,
const Constant *Initializer) {
const bool HasOffset = false;
const Ice::GlobalAddress::RelocOffsetType Offset = 0;
const Ice::VariableDeclaration::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,
// Adds Initializer to the list of initializers for Global variable
// declaration. HasOffset is true only if Initializer is a
// relocation initializer and Offset should be added to the
// relocation.
void addGlobalInitializer(Ice::VariableDeclaration &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];
}
Ice::VariableDeclaration::RelocOffsetType Offset);
// Converts the given constant C to the corresponding integer
// literal it contains.
Ice::GlobalAddress::RelocOffsetType
Ice::VariableDeclaration::RelocOffsetType
getIntegerLiteralConstant(const Value *C) {
const auto CI = dyn_cast<ConstantInt>(C);
if (CI && CI->getType()->isIntegerTy(32))
......@@ -692,30 +685,26 @@ private:
};
void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
Module *Mod, Ice::Translator::GlobalAddressList &GlobalAddresses) {
Module *Mod,
Ice::Translator::VariableDeclarationListType &VariableDeclarations) {
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);
const GlobalVariable *GV = I;
Ice::IceString Name = GV->getName();
if (!GV->hasInternalLinkage()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't define external global address: " << Name;
StrBuf << "Can't define external global declaration: " << 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);
Ice::GlobalDeclaration *Var = getConverter().getGlobalDeclaration(GV);
Ice::VariableDeclaration* VarDecl = cast<Ice::VariableDeclaration>(Var);
VariableDeclarations.push_back(VarDecl);
const Constant *Initializer = GV->getInitializer();
if (const auto CompoundInit = dyn_cast<ConstantStruct>(Initializer)) {
......@@ -723,24 +712,25 @@ void LLVM2ICEGlobalsConverter::convertGlobalsToIce(
E = CompoundInit->op_end();
I != E; ++I) {
if (const auto Init = dyn_cast<Constant>(I)) {
addGlobalInitializer(*Addr, Init);
addGlobalInitializer(*VarDecl, Init);
}
}
} else {
addGlobalInitializer(*Addr, Initializer);
addGlobalInitializer(*VarDecl, Initializer);
}
}
}
void LLVM2ICEGlobalsConverter::addGlobalInitializer(
Ice::GlobalAddress &Global, const Constant *Initializer, bool HasOffset,
Ice::GlobalAddress::RelocOffsetType Offset) {
Ice::VariableDeclaration &Global, const Constant *Initializer,
bool HasOffset, Ice::VariableDeclaration::RelocOffsetType Offset) {
(void)HasOffset;
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(
Global.addInitializer(new Ice::VariableDeclaration::DataInitializer(
CDA->getRawDataValues().data(), CDA->getNumElements()));
return;
}
......@@ -750,7 +740,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer(
assert(!HasOffset && isa<IntegerType>(AT->getElementType()) &&
(cast<IntegerType>(AT->getElementType())->getBitWidth() == 8));
Global.addInitializer(
new Ice::GlobalAddress::ZeroInitializer(AT->getNumElements()));
new Ice::VariableDeclaration::ZeroInitializer(AT->getNumElements()));
} else {
llvm_unreachable("Unhandled constant aggregate zero type");
}
......@@ -769,18 +759,11 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer(
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;
const Ice::GlobalDeclaration *Addr =
getConverter().getGlobalDeclaration(GV);
Global.addInitializer(
new Ice::VariableDeclaration::RelocInitializer(Addr, Offset));
return;
}
default:
break;
......@@ -797,19 +780,96 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer(
namespace Ice {
void Converter::nameUnnamedGlobalVariables(Module *Mod) {
const IceString &GlobalPrefix = Flags.DefaultGlobalPrefix;
if (GlobalPrefix.empty())
return;
uint32_t NameIndex = 0;
Ostream &errs = Ctx->getStrDump();
for (auto V = Mod->global_begin(), E = Mod->global_end(); V != E; ++V) {
if (!V->hasName()) {
V->setName(createUnnamedName(GlobalPrefix, NameIndex));
++NameIndex;
} else {
checkIfUnnamedNameSafe(V->getName(), "global", GlobalPrefix, errs);
}
}
}
void Converter::nameUnnamedFunctions(Module *Mod) {
const IceString &FunctionPrefix = Flags.DefaultFunctionPrefix;
if (FunctionPrefix.empty())
return;
uint32_t NameIndex = 0;
Ostream &errs = Ctx->getStrDump();
for (Function &F : *Mod) {
if (!F.hasName()) {
F.setName(createUnnamedName(FunctionPrefix, NameIndex));
++NameIndex;
} else {
checkIfUnnamedNameSafe(F.getName(), "function", FunctionPrefix, errs);
}
}
}
void Converter::convertToIce() {
TimerMarker T(TimerStack::TT_convertToIce, Ctx);
nameUnnamedGlobalAddresses(Mod);
nameUnnamedGlobalVariables(Mod);
nameUnnamedFunctions(Mod);
installGlobalDeclarations(Mod);
convertGlobals(Mod);
convertFunctions();
}
GlobalDeclaration *Converter::getGlobalDeclaration(const GlobalValue *V) {
GlobalDeclarationMapType::const_iterator Pos = GlobalDeclarationMap.find(V);
if (Pos == GlobalDeclarationMap.end()) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Can't find global declaration for: " << V->getName();
report_fatal_error(StrBuf.str());
}
return Pos->second;
}
void Converter::installGlobalDeclarations(Module *Mod) {
const TypeConverter Converter(Mod->getContext());
// Install function declarations.
for (const Function &Func : *Mod) {
FuncSigType Signature;
FunctionType *FuncType = Func.getFunctionType();
Signature.setReturnType(
Converter.convertToIceType(FuncType->getReturnType()));
for (size_t I = 0; I < FuncType->getNumParams(); ++I) {
Signature.appendArgType(
Converter.convertToIceType(FuncType->getParamType(I)));
}
FunctionDeclaration *IceFunc = FunctionDeclaration::create(
Ctx, Signature, Func.getCallingConv(), Func.getLinkage(), Func.empty());
IceFunc->setName(Func.getName());
GlobalDeclarationMap[&Func] = IceFunc;
}
// Install global variable declarations.
for (Module::const_global_iterator I = Mod->global_begin(),
E = Mod->global_end();
I != E; ++I) {
const GlobalVariable *GV = I;
VariableDeclaration *Var = VariableDeclaration::create(Ctx);
Var->setName(GV->getName());
Var->setAlignment(GV->getAlignment());
Var->setIsConstant(GV->isConstant());
// Note: We allow external for cross tests.
// TODO(kschimpf) Put behind flag AllowUninitializedGlobals.
Var->setIsInternal(!GV->isExternallyInitialized());
GlobalDeclarationMap[GV] = Var;
}
}
void Converter::convertGlobals(Module *Mod) {
LLVM2ICEGlobalsConverter GlobalsConverter(Ctx, Mod->getContext());
Translator::GlobalAddressList GlobalAddresses;
GlobalsConverter.convertGlobalsToIce(Mod, GlobalAddresses);
lowerGlobals(GlobalAddresses);
LLVM2ICEGlobalsConverter GlobalsConverter(*this);
Translator::VariableDeclarationListType VariableDeclarations;
GlobalsConverter.convertGlobalsToIce(Mod, VariableDeclarations);
lowerGlobals(VariableDeclarations);
}
void Converter::convertFunctions() {
......@@ -823,7 +883,7 @@ void Converter::convertFunctions() {
TimerID = Ctx->getTimerID(StackID, I.getName());
Ctx->pushTimer(TimerID, StackID);
}
LLVM2ICEFunctionConverter FunctionConverter(Ctx, Mod->getContext());
LLVM2ICEFunctionConverter FunctionConverter(*this);
Cfg *Fcn = FunctionConverter.convertFunction(&I);
translateFcn(Fcn);
......
......@@ -14,9 +14,11 @@
#ifndef SUBZERO_SRC_ICECONVERTER_H
#define SUBZERO_SRC_ICECONVERTER_H
#include "IceDefs.h"
#include "IceTranslator.h"
namespace llvm {
class GlobalValue;
class Module;
}
......@@ -27,18 +29,42 @@ public:
Converter(llvm::Module *Mod, GlobalContext *Ctx, const Ice::ClFlags &Flags)
: Translator(Ctx, Flags), Mod(Mod) {}
~Converter() {}
/// Converts the LLVM Module to ICE. Sets exit status to false if successful,
/// true otherwise.
void convertToIce();
llvm::Module *getModule() const { return Mod; }
// Returns the global declaration associated with the corresponding
// global value V. If no such global address, generates fatal error.
GlobalDeclaration *getGlobalDeclaration(const llvm::GlobalValue *V);
private:
llvm::Module *Mod;
typedef std::map<const llvm::GlobalValue *, GlobalDeclaration *>
GlobalDeclarationMapType;
GlobalDeclarationMapType GlobalDeclarationMap;
// Walks module and generates names for unnamed globals using prefix
// getFlags().DefaultGlobalPrefix, if the prefix is non-empty.
void nameUnnamedGlobalVariables(llvm::Module *Mod);
// Walks module and generates names for unnamed functions using
// prefix getFlags().DefaultFunctionPrefix, if the prefix is
// non-empty.
void nameUnnamedFunctions(llvm::Module *Mod);
// Converts functions to ICE, and then machine code.
void convertFunctions();
// Converts globals to ICE, and then machine code.
void convertGlobals(llvm::Module *Mod);
// Installs global declarations into GlobalDeclarationMap.
void installGlobalDeclarations(llvm::Module *Mod);
Converter(const Converter &) = delete;
Converter &operator=(const Converter &) = delete;
};
......
......@@ -26,7 +26,6 @@
#include <set>
#include <string>
#include <vector>
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallBitVector.h"
......@@ -39,7 +38,9 @@ namespace Ice {
class Cfg;
class CfgNode;
class Constant;
class FunctionDeclaration;
class GlobalContext;
class GlobalDeclaration;
class Inst;
class InstPhi;
class InstTarget;
......@@ -48,6 +49,7 @@ class Liveness;
class Operand;
class TargetLowering;
class Variable;
class VariableDeclaration;
class VariablesMetadata;
// TODO: Switch over to LLVM's ADT container classes.
......
......@@ -19,6 +19,7 @@
#include "IceClFlags.h"
#include "IceDefs.h"
#include "IceGlobalContext.h"
#include "IceGlobalInits.h"
#include "IceOperand.h"
#include "IceTargetLowering.h"
#include "IceTimerTree.h"
......@@ -289,7 +290,9 @@ IceString GlobalContext::mangleName(const IceString &Name) const {
return getTestPrefix() + Name;
}
GlobalContext::~GlobalContext() {}
GlobalContext::~GlobalContext() {
llvm::DeleteContainerPointers(GlobalDeclarations);
}
Constant *GlobalContext::getConstantInt64(Type Ty, uint64_t ConstantInt64) {
assert(Ty == IceType_i64);
......@@ -385,6 +388,23 @@ ConstantList GlobalContext::getConstantPool(Type Ty) const {
llvm_unreachable("Unknown type");
}
FunctionDeclaration *
GlobalContext::newFunctionDeclaration(const FuncSigType *Signature,
unsigned CallingConv, unsigned Linkage,
bool IsProto) {
FunctionDeclaration *Func = new FunctionDeclaration(
*Signature, static_cast<llvm::CallingConv::ID>(CallingConv),
static_cast<llvm::GlobalValue::LinkageTypes>(Linkage), IsProto);
GlobalDeclarations.push_back(Func);
return Func;
}
VariableDeclaration *GlobalContext::newVariableDeclaration() {
VariableDeclaration *Var = new VariableDeclaration();
GlobalDeclarations.push_back(Var);
return Var;
}
TimerIdT GlobalContext::getTimerID(TimerStackIdT StackID,
const IceString &Name) {
assert(StackID < Timers.size());
......
......@@ -21,6 +21,7 @@
#include "llvm/Support/raw_ostream.h"
#include "IceDefs.h"
#include "IceClFlags.h"
#include "IceIntrinsics.h"
#include "IceRNG.h"
#include "IceTimerTree.h"
......@@ -29,6 +30,7 @@
namespace Ice {
class ClFlags;
class FuncSigType;
// This class collects rudimentary statistics during translation.
class CodeStats {
......@@ -117,6 +119,17 @@ public:
// getConstantPool() returns a copy of the constant pool for
// constants of a given type.
ConstantList getConstantPool(Type Ty) const;
// Returns a new function declaration, allocated in an internal
// memory pool. Ownership of the function is maintained by this
// class instance.
FunctionDeclaration *newFunctionDeclaration(const FuncSigType *Signature,
unsigned CallingConv,
unsigned Linkage, bool IsProto);
// Returns a new global variable declaration, allocated in an
// internal memory pool. Ownership of the function is maintained by
// this class instance.
VariableDeclaration *newVariableDeclaration();
const ClFlags &getFlags() const { return Flags; }
......@@ -186,6 +199,7 @@ private:
CodeStats StatsFunction;
CodeStats StatsCumulative;
std::vector<TimerStack> Timers;
std::vector<GlobalDeclaration *> GlobalDeclarations;
GlobalContext(const GlobalContext &) = delete;
GlobalContext &operator=(const GlobalContext &) = delete;
......
//===- subzero/src/IceGlobalInits.cpp - Global initializers ---------------===//
//===- subzero/src/IceGlobalInits.cpp - Global declarations ---------------===//
//
// The Subzero Code Generator
//
......@@ -7,8 +7,9 @@
//
//===----------------------------------------------------------------------===//
//
// This file implements the notion of global addresses and
// initializers in Subzero.
// This file implements the notion of function declarations, global
// variable declarations, and the corresponding variable initializers
// in Subzero.
//
//===----------------------------------------------------------------------===//
......@@ -17,18 +18,82 @@
#include "llvm/IR/Value.h"
#include "IceDefs.h"
#include "IceGlobalContext.h"
#include "IceGlobalInits.h"
#include "IceTypes.h"
namespace {
char hexdigit(unsigned X) { return X < 10 ? '0' + X : 'A' + X - 10; }
void dumpLinkage(Ice::Ostream &Stream,
llvm::GlobalValue::LinkageTypes Linkage) {
switch (Linkage) {
case llvm::GlobalValue::ExternalLinkage:
Stream << "external";
return;
case llvm::GlobalValue::InternalLinkage:
Stream << "internal";
return;
default:
break;
}
std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer);
StrBuf << "Unknown linkage value: " << Linkage;
llvm::report_fatal_error(StrBuf.str());
}
void dumpCallingConv(Ice::Ostream &, llvm::CallingConv::ID CallingConv) {
if (CallingConv == llvm::CallingConv::C)
return;
std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer);
StrBuf << "Unknown calling convention: " << CallingConv;
llvm::report_fatal_error(StrBuf.str());
}
} // end of anonymous namespace
namespace Ice {
GlobalAddress::~GlobalAddress() { llvm::DeleteContainerPointers(Initializers); }
FunctionDeclaration *
FunctionDeclaration::create(GlobalContext *Ctx, const FuncSigType &Signature,
llvm::CallingConv::ID CallingConv,
llvm::GlobalValue::LinkageTypes Linkage,
bool IsProto) {
return Ctx->newFunctionDeclaration(&Signature, CallingConv, Linkage, IsProto);
}
void FunctionDeclaration::dumpType(Ostream &Stream) const {
Stream << Signature;
}
void FunctionDeclaration::dump(Ostream &Stream) const {
if (IsProto)
Stream << "declare ";
::dumpLinkage(Stream, Linkage);
::dumpCallingConv(Stream, CallingConv);
Stream << Signature.getReturnType() << " @" << Name << "(";
bool IsFirst = true;
for (Type ArgTy : Signature.getArgList()) {
if (IsFirst)
IsFirst = false;
else
Stream << ", ";
Stream << ArgTy;
}
Stream << ")";
}
VariableDeclaration *VariableDeclaration::create(GlobalContext *Ctx) {
return Ctx->newVariableDeclaration();
}
void GlobalAddress::dumpType(Ostream &Stream) const {
VariableDeclaration::~VariableDeclaration() {
llvm::DeleteContainerPointers(Initializers);
}
void VariableDeclaration::dumpType(Ostream &Stream) const {
if (Initializers.size() == 1) {
Initializers.front()->dumpType(Stream);
} else {
......@@ -46,8 +111,8 @@ void GlobalAddress::dumpType(Ostream &Stream) const {
}
}
void GlobalAddress::dump(Ostream &Stream) const {
Stream << "@" << getName() << " = internal "
void VariableDeclaration::dump(Ostream &Stream) const {
Stream << "@" << Name << " = internal "
<< (IsConstant ? "constant" : "global") << " ";
// Add initializer.
......@@ -74,11 +139,11 @@ void GlobalAddress::dump(Ostream &Stream) const {
Stream << "\n";
}
void GlobalAddress::Initializer::dumpType(Ostream &Stream) const {
void VariableDeclaration::Initializer::dumpType(Ostream &Stream) const {
Stream << "[" << getNumBytes() << " x " << Ice::IceType_i8 << "]";
}
void GlobalAddress::DataInitializer::dump(Ostream &Stream) const {
void VariableDeclaration::DataInitializer::dump(Ostream &Stream) const {
dumpType(Stream);
Stream << " c\"";
// Code taken from PrintEscapedString() in AsmWriter.cpp. Keep
......@@ -93,41 +158,24 @@ void GlobalAddress::DataInitializer::dump(Ostream &Stream) const {
Stream << "\"";
}
void GlobalAddress::ZeroInitializer::dump(Ostream &Stream) const {
void VariableDeclaration::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 {
void VariableDeclaration::RelocInitializer::dumpType(Ostream &Stream) const {
Stream << Ice::IceType_i32;
}
void GlobalAddress::RelocInitializer::dump(Ostream &Stream) const {
void VariableDeclaration::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 ";
Declaration->dumpType(Stream);
Stream << "* @" << Declaration->getName() << " to ";
dumpType(Stream);
Stream << ")";
if (Offset != 0) {
......@@ -136,4 +184,5 @@ void GlobalAddress::RelocInitializer::dump(Ostream &Stream) const {
Stream << " " << Offset << ")";
}
}
}
} // end of namespace Ice
//===- subzero/src/IceGlobalInits.h - Global initializers -------*- C++ -*-===//
//===- subzero/src/IceGlobalInits.h - Global declarations -------*- C++ -*-===//
//
// The Subzero Code Generator
//
......@@ -7,29 +7,117 @@
//
//===----------------------------------------------------------------------===//
//
// This file declares the representation of global addresses and
// initializers in Subzero. Global initializers are represented as a
// sequence of simple initializers.
// This file declares the representation of function declarations,
// global variable declarations, and the corresponding variable
// initializers in Subzero. Global variable initializers are
// represented as a sequence of simple initializers.
//
//===----------------------------------------------------------------------===//
#ifndef SUBZERO_SRC_ICEGLOBALINITS_H
#define SUBZERO_SRC_ICEGLOBALINITS_H
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/GlobalValue.h" // for GlobalValue::LinkageTypes
#include "IceDefs.h"
#include "IceTypes.h"
namespace llvm {
// TODO(kschimpf): Remove this dependency on LLVM IR.
class Value;
}
// TODO(kschimpf): Remove ourselves from using LLVM representation for calling
// conventions and linkage types.
namespace Ice {
/// Models a global address, and its initializers.
class GlobalAddress {
GlobalAddress(const GlobalAddress &) = delete;
GlobalAddress &operator=(const GlobalAddress &) = delete;
/// Base class for global variable and function declarations.
class GlobalDeclaration {
GlobalDeclaration(const GlobalDeclaration &) = delete;
GlobalDeclaration &operator=(const GlobalDeclaration &) = delete;
public:
/// Discriminator for LLVM-style RTTI.
enum GlobalDeclarationKind {
FunctionDeclarationKind,
VariableDeclarationKind
};
GlobalDeclarationKind getKind() const { return Kind; }
const IceString &getName() const { return Name; }
void setName(const IceString &NewName) { Name = NewName; }
bool hasName() const { return !Name.empty(); }
virtual ~GlobalDeclaration() {}
/// Returns true if the declaration is external.
virtual bool getIsExternal() const = 0;
/// Prints out type of the global declaration.
virtual void dumpType(Ostream &Stream) const = 0;
/// Prints out the global declaration.
virtual void dump(Ostream &Stream) const = 0;
// Mangles name for cross tests, unless external and not defined locally
// (so that relocations accross llvm2ice and pnacl-llc will work).
virtual IceString mangleName(GlobalContext *Ctx) const = 0;
protected:
GlobalDeclaration(GlobalDeclarationKind Kind) : Kind(Kind) {}
const GlobalDeclarationKind Kind;
IceString Name;
};
// Models a function declaration. This includes the type signature of
// the function, its calling conventions, and its linkage.
class FunctionDeclaration : public GlobalDeclaration {
FunctionDeclaration(const FunctionDeclaration &) = delete;
FunctionDeclaration &operator=(const FunctionDeclaration &) = delete;
friend class GlobalContext;
public:
static FunctionDeclaration *create(GlobalContext *Ctx,
const FuncSigType &Signature,
llvm::CallingConv::ID CallingConv,
llvm::GlobalValue::LinkageTypes Linkage,
bool IsProto);
~FunctionDeclaration() final {}
const FuncSigType &getSignature() const { return Signature; }
llvm::CallingConv::ID getCallingConv() const { return CallingConv; }
llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; }
// isProto implies that there isn't a (local) definition for the function.
bool isProto() const { return IsProto; }
static bool classof(const GlobalDeclaration *Addr) {
return Addr->getKind() == FunctionDeclarationKind;
}
void dumpType(Ostream &Stream) const final;
void dump(Ostream &Stream) const final;
bool getIsExternal() const final {
return Linkage == llvm::GlobalValue::ExternalLinkage;
}
virtual IceString mangleName(GlobalContext *Ctx) const final {
return (getIsExternal() && IsProto) ? Name : Ctx->mangleName(Name);
}
private:
const Ice::FuncSigType Signature;
llvm::CallingConv::ID CallingConv;
llvm::GlobalValue::LinkageTypes Linkage;
bool IsProto;
FunctionDeclaration(const FuncSigType &Signature,
llvm::CallingConv::ID CallingConv,
llvm::GlobalValue::LinkageTypes Linkage, bool IsProto)
: GlobalDeclaration(FunctionDeclarationKind), Signature(Signature),
CallingConv(CallingConv), Linkage(Linkage), IsProto(IsProto) {}
};
/// Models a global variable declaration, and its initializers.
class VariableDeclaration : public GlobalDeclaration {
VariableDeclaration(const VariableDeclaration &) = delete;
VariableDeclaration &operator=(const VariableDeclaration &) = delete;
friend class GlobalContext;
// TODO(kschimpf) Factor out allocation of initializers into the
// global context, so that memory allocation/collection can be
// optimized.
public:
/// Base class for a global variable initializer.
class Initializer {
......@@ -81,8 +169,8 @@ public:
}
~DataInitializer() override {}
const DataVecType &getContents() const { return Contents; }
SizeT getNumBytes() const override { return Contents.size(); }
void dump(Ostream &Stream) const override;
SizeT getNumBytes() const final { return Contents.size(); }
void dump(Ostream &Stream) const final;
static bool classof(const Initializer *D) {
return D->getKind() == DataInitializerKind;
}
......@@ -101,8 +189,8 @@ public:
explicit ZeroInitializer(SizeT Size)
: Initializer(ZeroInitializerKind), Size(Size) {}
~ZeroInitializer() override {}
SizeT getNumBytes() const override { return Size; }
void dump(Ostream &Stream) const override;
SizeT getNumBytes() const final { return Size; }
void dump(Ostream &Stream) const final;
static bool classof(const Initializer *Z) {
return Z->getKind() == ZeroInitializerKind;
}
......@@ -112,76 +200,33 @@ public:
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.
/// Defines the relocation value of another global declaration.
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(const GlobalDeclaration *Declaration,
RelocOffsetType Offset)
: Initializer(RelocInitializerKind), Declaration(Declaration),
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;
const GlobalDeclaration *getDeclaration() const { return Declaration; }
SizeT getNumBytes() const final { return RelocAddrSize; }
void dump(Ostream &Stream) const final;
void dumpType(Ostream &Stream) const final;
static bool classof(const Initializer *R) {
return R->getKind() == RelocInitializerKind;
}
private:
// The global address used in the relocation.
const RelocationAddress Address;
// The global declaration used in the relocation.
const GlobalDeclaration *Declaration;
// The offset to add to the relocation.
const RelocOffsetType Offset;
};
......@@ -189,19 +234,21 @@ public:
/// Models the list of initializers.
typedef std::vector<Initializer *> InitializerListType;
GlobalAddress() : Alignment(0), IsConstant(false), IsInternal(true) {}
~GlobalAddress();
static VariableDeclaration *create(GlobalContext *Ctx);
~VariableDeclaration() final;
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; }
bool getIsExternal() const final { return !getIsInternal(); }
bool hasInitializer() const {
return !(Initializers.size() == 1 &&
llvm::isa<ZeroInitializer>(Initializers[0]));
}
/// Returns the number of bytes for the initializer of the global
/// address.
......@@ -219,36 +266,49 @@ public:
Initializers.push_back(Initializer);
}
/// Prints out type for initializer associated with the global address
/// Prints out type for initializer associated with the declaration
/// to Stream.
void dumpType(Ostream &Stream) const;
void dumpType(Ostream &Stream) const final;
/// Prints out the definition of the global variable declaration
/// (including initialization).
void dump(Ostream &Stream) const final;
static bool classof(const GlobalDeclaration *Addr) {
return Addr->getKind() == VariableDeclarationKind;
}
IceString mangleName(GlobalContext *Ctx) const final {
return (getIsExternal() && !hasInitializer())
? Name : Ctx->mangleName(Name);
}
/// Prints out the definition of the global address (including
/// initialization).
void dump(Ostream &Stream) const;
private:
// list of initializers associated with the global address.
// list of initializers for the declared variable.
InitializerListType Initializers;
// The name for the global.
IceString Name;
// The alignment of the initializer.
// The alignment of the declared variable.
uint32_t Alignment;
// True if a constant initializer.
// True if a declared (global) constant.
bool IsConstant;
// True if the address is internal.
// True if the declaration is internal.
bool IsInternal;
VariableDeclaration()
: GlobalDeclaration(VariableDeclarationKind), Alignment(0),
IsConstant(false), IsInternal(true) {}
};
template <class StreamType>
inline StreamType &operator<<(StreamType &Stream,
const GlobalAddress::Initializer &Init) {
const VariableDeclaration::Initializer &Init) {
Init.dump(Stream);
return Stream;
}
template <class StreamType>
inline StreamType &operator<<(StreamType &Stream, const GlobalAddress &Addr) {
inline StreamType &operator<<(StreamType &Stream,
const GlobalDeclaration &Addr) {
Addr.dump(Stream);
return Stream;
}
......
......@@ -27,7 +27,6 @@ namespace Ice {
typedef uint8_t AsmCodeByte;
class Assembler;
class GlobalAddress;
// LoweringContext makes it easy to iterate through non-deleted
// instructions in a node, and insert new (lowered) instructions at
......@@ -249,7 +248,7 @@ public:
GlobalContext *Ctx);
virtual ~TargetGlobalInitLowering();
virtual void lower(const GlobalAddress &Addr, bool DisableTranslation) = 0;
virtual void lower(const VariableDeclaration &Var) = 0;
protected:
TargetGlobalInitLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
......
......@@ -4427,32 +4427,19 @@ void ConstantUndef::emit(GlobalContext *) const {
TargetGlobalInitX8632::TargetGlobalInitX8632(GlobalContext *Ctx)
: TargetGlobalInitLowering(Ctx) {}
void TargetGlobalInitX8632::lower(const GlobalAddress &Global,
bool DisableTranslation) {
if (Ctx->isVerbose()) {
Global.dump(Ctx->getStrDump());
}
if (DisableTranslation)
return;
void TargetGlobalInitX8632::lower(const VariableDeclaration &Var) {
Ostream &Str = Ctx->getStrEmit();
// TODO(kschimpf): Don't mangle name if external and uninitialized. This
// will allow us to cross test relocations for references to external
// global variables.
const GlobalAddress::InitializerListType &Initializers =
Global.getInitializers();
const VariableDeclaration::InitializerListType &Initializers =
Var.getInitializers();
assert(Initializers.size());
bool HasInitializer =
!(Initializers.size() == 1 &&
llvm::isa<GlobalAddress::ZeroInitializer>(Initializers[0]));
bool IsConstant = Global.getIsConstant();
bool IsExternal = !Global.getIsInternal();
uint32_t Align = Global.getAlignment();
SizeT Size = Global.getNumBytes();
IceString MangledName = Ctx->mangleName(Global.getName());
bool HasInitializer = Var.hasInitializer();
bool IsConstant = Var.getIsConstant();
bool IsExternal = Var.getIsExternal();
uint32_t Align = Var.getAlignment();
SizeT Size = Var.getNumBytes();
IceString MangledName = Var.mangleName(Ctx);
IceString SectionSuffix = "";
if (Ctx->getFlags().DataSections)
SectionSuffix = "." + MangledName;
......@@ -4483,30 +4470,29 @@ void TargetGlobalInitX8632::lower(const GlobalAddress &Global,
Str << "\t.comm\t" << MangledName << "," << Size << "," << Align << "\n";
if (HasInitializer) {
for (GlobalAddress::Initializer *Init : Initializers) {
for (VariableDeclaration::Initializer *Init : Initializers) {
switch (Init->getKind()) {
case GlobalAddress::Initializer::DataInitializerKind: {
const auto Data =
llvm::cast<GlobalAddress::DataInitializer>(Init)->getContents();
case VariableDeclaration::Initializer::DataInitializerKind: {
const auto Data = llvm::cast<VariableDeclaration::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:
case VariableDeclaration::Initializer::ZeroInitializerKind:
Str << "\t.zero\t" << Init->getNumBytes() << "\n";
break;
case GlobalAddress::Initializer::RelocInitializerKind: {
const auto Reloc = llvm::cast<GlobalAddress::RelocInitializer>(Init);
case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto Reloc =
llvm::cast<VariableDeclaration::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 << Reloc->getDeclaration()->mangleName(Ctx);
if (VariableDeclaration::RelocOffsetType Offset = Reloc->getOffset()) {
if (Offset >= 0 || (Offset == INT32_MIN))
Str << " + " << Offset;
else
Str << " - " << -Offset;
}
Str << "\n";
break;
......
......@@ -482,8 +482,7 @@ public:
return new TargetGlobalInitX8632(Ctx);
}
virtual void lower(const GlobalAddress &Addr,
bool DisableTranslation) override;
virtual void lower(const VariableDeclaration &Var) final;
protected:
TargetGlobalInitX8632(GlobalContext *Ctx);
......
......@@ -22,6 +22,7 @@
#include "IceCfg.h"
#include "IceClFlags.h"
#include "IceDefs.h"
#include "IceGlobalInits.h"
#include "IceTargetLowering.h"
#include "IceTranslator.h"
......@@ -54,38 +55,6 @@ bool Translator::checkIfUnnamedNameSafe(const IceString &Name, const char *Kind,
return false;
}
void Translator::nameUnnamedGlobalAddresses(llvm::Module *Mod) {
const IceString &GlobalPrefix = Flags.DefaultGlobalPrefix;
if (GlobalPrefix.empty())
return;
uint32_t NameIndex = 0;
Ostream &errs = Ctx->getStrDump();
for (auto V = Mod->global_begin(), E = Mod->global_end(); V != E; ++V) {
if (!V->hasName()) {
V->setName(createUnnamedName(GlobalPrefix, NameIndex));
++NameIndex;
} else {
checkIfUnnamedNameSafe(V->getName(), "global", GlobalPrefix, errs);
}
}
}
void Translator::nameUnnamedFunctions(llvm::Module *Mod) {
const IceString &FunctionPrefix = Flags.DefaultFunctionPrefix;
if (FunctionPrefix.empty())
return;
uint32_t NameIndex = 0;
Ostream &errs = Ctx->getStrDump();
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) {
Ctx->resetStats();
Func.reset(Fcn);
......@@ -110,12 +79,18 @@ void Translator::emitConstants() {
Func->getTarget()->emitConstants();
}
void Translator::lowerGlobals(const GlobalAddressList &GlobalAddresses) {
llvm::OwningPtr<Ice::TargetGlobalInitLowering> GlobalLowering(
Ice::TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
void Translator::lowerGlobals(
const VariableDeclarationListType &VariableDeclarations) {
llvm::OwningPtr<TargetGlobalInitLowering> GlobalLowering(
TargetGlobalInitLowering::createLowering(Ctx->getTargetArch(), Ctx));
bool DisableTranslation = Ctx->getFlags().DisableTranslation;
for (const Ice::GlobalAddress *Addr : GlobalAddresses) {
GlobalLowering->lower(*Addr, DisableTranslation);
bool DumpGlobalVariables = Ctx->isVerbose();
Ostream &Stream = Ctx->getStrDump();
for (const Ice::VariableDeclaration *Global : VariableDeclarations) {
if (DumpGlobalVariables)
Global->dump(Stream);
if(!DisableTranslation)
GlobalLowering->lower(*Global);
}
GlobalLowering.reset();
}
......@@ -25,16 +25,15 @@ namespace Ice {
class ClFlags;
class Cfg;
class GlobalAddress;
class VariableDeclaration;
class GlobalContext;
// Base class for translating ICE to machine code.
// Derived classes convert other intermediate representations down to ICE,
// and then call the appropriate (inherited) methods to convert ICE into
// machine instructions.
// Base class for translating ICE to machine code. Derived classes convert
// other intermediate representations down to ICE, and then call the appropriate
// (inherited) methods to convert ICE into machine instructions.
class Translator {
public:
typedef std::vector<Ice::GlobalAddress *> GlobalAddressList;
typedef std::vector<VariableDeclaration *> VariableDeclarationListType;
Translator(GlobalContext *Ctx, const ClFlags &Flags)
: Ctx(Ctx), Flags(Flags), ErrorStatus(0) {}
......@@ -54,8 +53,9 @@ public:
/// Emits the constant pool.
void emitConstants();
/// Lowers the given list of global addresses to target.
void lowerGlobals(const GlobalAddressList &GlobalAddresses);
/// Lowers the given list of global addresses to target. Generates
/// list of corresponding variable declarations.
void lowerGlobals(const VariableDeclarationListType &VariableDeclarations);
/// Creates a name using the given prefix and corresponding index.
std::string createUnnamedName(const IceString &Prefix, SizeT Index);
......@@ -66,15 +66,6 @@ public:
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);
// Walks module and generates names for unnamed functions using
// prefix getFlags().DefaultFunctionPrefix, if the prefix is
// non-empty.
void nameUnnamedFunctions(llvm::Module *Mod);
protected:
GlobalContext *Ctx;
const ClFlags &Flags;
......
......@@ -24,7 +24,6 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ValueHandle.h"
#include "IceCfg.h"
#include "IceCfgNode.h"
......@@ -36,9 +35,8 @@
#include "IceTypeConverter.h"
#include "PNaClTranslator.h"
using namespace llvm;
namespace {
using namespace llvm;
// TODO(kschimpf) Remove error recovery once implementation complete.
static cl::opt<bool> AllowErrorRecovery(
......@@ -160,19 +158,21 @@ class TopLevelParser : public NaClBitcodeParser {
TopLevelParser &operator=(const TopLevelParser &) = delete;
public:
typedef std::vector<Ice::FunctionDeclaration *> FunctionDeclarationListType;
TopLevelParser(Ice::Translator &Translator, const std::string &InputName,
NaClBitcodeHeader &Header, NaClBitstreamCursor &Cursor,
bool &ErrorStatus)
: NaClBitcodeParser(Cursor), Translator(Translator),
Mod(new Module(InputName, getGlobalContext())), DL(PNaClDataLayout),
Header(Header), TypeConverter(getLLVMContext()),
Header(Header), TypeConverter(Mod->getContext()),
ErrorStatus(ErrorStatus), NumErrors(0), NumFunctionIds(0),
NumFunctionBlocks(0) {
Mod->setDataLayout(PNaClDataLayout);
setErrStream(Translator.getContext()->getStrDump());
}
~TopLevelParser() override { DeleteContainerPointers(GlobalIDAddresses); }
~TopLevelParser() override {}
Ice::Translator &getTranslator() { return Translator; }
......@@ -198,9 +198,6 @@ public:
/// Returns the number of bytes in the bitcode header.
size_t getHeaderSize() const { return Header.getHeaderSize(); }
/// Returns the llvm context to use.
LLVMContext &getLLVMContext() const { return Mod->getContext(); }
/// Changes the size of the type list to the given size.
void resizeTypeIDValues(unsigned NewSize) { TypeIDValues.resize(NewSize); }
......@@ -236,36 +233,40 @@ public:
}
/// Sets the next function ID to the given LLVM function.
void setNextFunctionID(Function *Fcn) {
void setNextFunctionID(Ice::FunctionDeclaration *Fcn) {
++NumFunctionIds;
FunctionIDValues.push_back(Fcn);
FunctionDeclarationList.push_back(Fcn);
}
/// Defines the next function ID as one that has an implementation
/// (i.e a corresponding function block in the bitcode).
void setNextValueIDAsImplementedFunction() {
DefiningFunctionsList.push_back(FunctionIDValues.size());
DefiningFunctionDeclarationsList.push_back(FunctionDeclarationList.size());
}
/// Returns the value id that should be associated with the the
/// current function block. Increments internal counters during call
/// so that it will be in correct position for next function block.
unsigned getNextFunctionBlockValueID() {
if (NumFunctionBlocks >= DefiningFunctionsList.size())
if (NumFunctionBlocks >= DefiningFunctionDeclarationsList.size())
report_fatal_error(
"More function blocks than defined function addresses");
return DefiningFunctionsList[NumFunctionBlocks++];
return DefiningFunctionDeclarationsList[NumFunctionBlocks++];
}
/// Returns the LLVM Function address associated with ID.
Function *getFunctionByID(unsigned ID) const {
if (ID >= FunctionIDValues.size())
return nullptr;
Value *V = FunctionIDValues[ID];
return cast<Function>(V);
/// Returns the function associated with ID.
Ice::FunctionDeclaration *getFunctionByID(unsigned ID) {
if (ID < FunctionDeclarationList.size())
return FunctionDeclarationList[ID];
return reportGetFunctionByIDError(ID);
}
/// Returns the corresponding constant associated with a global value
/// Returns the list of function declarations.
const FunctionDeclarationListType &getFunctionDeclarationList() const {
return FunctionDeclarationList;
}
/// Returns the corresponding constant associated with a global declaration.
/// (i.e. relocatable).
Ice::Constant *getOrCreateGlobalConstantByID(unsigned ID) {
// TODO(kschimpf): Can this be built when creating global initializers?
......@@ -273,7 +274,7 @@ public:
if (ID >= ValueIDConstants.size()) {
C = nullptr;
unsigned ExpectedSize =
FunctionIDValues.size() + GlobalIDAddresses.size();
FunctionDeclarationList.size() + VariableDeclarations.size();
if (ID >= ExpectedSize)
ExpectedSize = ID;
ValueIDConstants.resize(ExpectedSize);
......@@ -284,12 +285,13 @@ public:
return C;
// If reached, no such constant exists, create one.
// TODO(kschimpf) Don't get addresses of intrinsic function declarations.
std::string Name;
unsigned FcnIDSize = FunctionIDValues.size();
unsigned FcnIDSize = FunctionDeclarationList.size();
if (ID < FcnIDSize) {
Name = FunctionIDValues[ID]->getName();
} else if ((ID - FcnIDSize) < GlobalIDAddresses.size()) {
Name = GlobalIDAddresses[ID - FcnIDSize]->getName();
Name = FunctionDeclarationList[ID]->getName();
} else if ((ID - FcnIDSize) < VariableDeclarations.size()) {
Name = VariableDeclarations[ID - FcnIDSize]->getName();
} else {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
......@@ -304,47 +306,49 @@ public:
return C;
}
/// Returns the number of function addresses (i.e. ID's) defined in
/// the bitcode file.
/// Returns the number of function declarations in the bitcode file.
unsigned getNumFunctionIDs() const { return NumFunctionIds; }
/// Returns the number of global IDs (function and global addresses)
/// defined in the bitcode file.
/// Returns the number of global declarations (i.e. IDs) defined in
/// the bitcode file.
unsigned getNumGlobalIDs() const {
return FunctionIDValues.size() + GlobalIDAddresses.size();
return FunctionDeclarationList.size() + VariableDeclarations.size();
}
/// Creates Count global addresses.
void CreateGlobalAddresses(size_t Count) {
assert(GlobalIDAddresses.empty());
/// Creates Count global variable declarations.
void CreateGlobalVariables(size_t Count) {
assert(VariableDeclarations.empty());
Ice::GlobalContext *Context = getTranslator().getContext();
for (size_t i = 0; i < Count; ++i) {
GlobalIDAddresses.push_back(new Ice::GlobalAddress());
VariableDeclarations.push_back(Ice::VariableDeclaration::create(Context));
}
}
/// Returns the number of global addresses (i.e. ID's) defined in
/// the bitcode file.
Ice::SizeT getNumGlobalAddresses() const { return GlobalIDAddresses.size(); }
/// Returns the number of global variable declarations in the
/// bitcode file.
Ice::SizeT getNumGlobalVariables() const {
return VariableDeclarations.size();
}
/// Returns the global address with the given index.
Ice::GlobalAddress *getGlobalAddress(size_t Index) {
if (Index < GlobalIDAddresses.size())
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 global variable declaration with the given index.
Ice::VariableDeclaration *getGlobalVariableByID(unsigned Index) {
if (Index < VariableDeclarations.size())
return VariableDeclarations[Index];
return reportGetGlobalVariableByIDError(Index);
}
/// Returns the global declaration (variable or function) with the
/// given Index.
Ice::GlobalDeclaration *getGlobalDeclarationByID(size_t Index) {
if (Index < NumFunctionIds)
return getFunctionByID(Index);
else
return getGlobalVariableByID(Index - NumFunctionIds);
}
/// Returns the list of read global addresses.
const Ice::Translator::GlobalAddressList &getGlobalIDAddresses() {
return GlobalIDAddresses;
/// Returns the list of parsed global variable declarations.
const Ice::Translator::VariableDeclarationListType &getGlobalVariables() {
return VariableDeclarations;
}
/// Returns the corresponding ICE type for LLVMTy.
......@@ -383,20 +387,21 @@ private:
unsigned NumErrors;
// The types associated with each type ID.
std::vector<ExtendedType> TypeIDValues;
// The set of function value IDs.
std::vector<WeakVH> FunctionIDValues;
// The set of global addresses IDs.
Ice::Translator::GlobalAddressList GlobalIDAddresses;
// Relocatable constants associated with FunctionIDValues and
// GlobalIDAddresses.
// The set of functions.
FunctionDeclarationListType FunctionDeclarationList;
// The set of global variables.
Ice::Translator::VariableDeclarationListType VariableDeclarations;
// Relocatable constants associated with global declarations.
std::vector<Ice::Constant *> ValueIDConstants;
// The number of function IDs.
// The number of function declarations (i.e. IDs).
unsigned NumFunctionIds;
// The number of function blocks (processed so far).
unsigned NumFunctionBlocks;
// The list of value IDs (in the order found) of defining function
// addresses.
std::vector<unsigned> DefiningFunctionsList;
// The list of function declaration IDs (in the order found) that
// aren't just proto declarations.
// TODO(kschimpf): Instead of using this list, just use
// FunctionDeclarationList, and the isProto member function.
std::vector<unsigned> DefiningFunctionDeclarationsList;
// Error recovery value to use when getFuncSigTypeByID fails.
Ice::FuncSigType UndefinedFuncSigType;
......@@ -423,6 +428,14 @@ private:
void reportBadTypeIDAs(unsigned ID, const ExtendedType *Ty,
ExtendedType::TypeKind WantedType);
// Reports that there is no function declaration for ID. Returns an
// error recovery value to use.
Ice::FunctionDeclaration *reportGetFunctionByIDError(unsigned ID);
// Reports that there is not global variable declaration for
// ID. Returns an error recovery value to use.
Ice::VariableDeclaration *reportGetGlobalVariableByIDError(unsigned Index);
// Reports that there is no corresponding ICE type for LLVMTy, and
// returns ICE::IceType_void.
Ice::Type convertToIceTypeError(Type *LLVMTy);
......@@ -440,6 +453,34 @@ void TopLevelParser::reportBadTypeIDAs(unsigned ID, const ExtendedType *Ty,
Error(StrBuf.str());
}
Ice::FunctionDeclaration *
TopLevelParser::reportGetFunctionByIDError(unsigned ID) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Function index " << ID
<< " not allowed. Out of range. Must be less than "
<< FunctionDeclarationList.size();
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
if (!FunctionDeclarationList.empty())
return FunctionDeclarationList[0];
report_fatal_error("Unable to continue");
}
Ice::VariableDeclaration *
TopLevelParser::reportGetGlobalVariableByIDError(unsigned Index) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Global index " << Index
<< " not allowed. Out of range. Must be less than "
<< VariableDeclarations.size();
Error(StrBuf.str());
// TODO(kschimpf) Remove error recovery once implementation complete.
if (!VariableDeclarations.empty())
return VariableDeclarations[0];
report_fatal_error("Unable to continue");
}
Ice::Type TopLevelParser::convertToIceTypeError(Type *LLVMTy) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
......@@ -747,38 +788,40 @@ void TypesParser::ProcessRecord() {
llvm_unreachable("Unknown type block record not processed!");
}
/// Parses the globals block (i.e. global variables).
/// Parses the globals block (i.e. global variable declarations and
/// corresponding initializers).
class GlobalsParser : public BlockParserBaseClass {
public:
GlobalsParser(unsigned BlockID, BlockParserBaseClass *EnclosingParser)
: BlockParserBaseClass(BlockID, EnclosingParser), InitializersNeeded(0),
NextGlobalID(0), CurrentAddress(&DummyAddress) {}
~GlobalsParser() override {}
NextGlobalID(0), DummyGlobalVar(Ice::VariableDeclaration::create(
getTranslator().getContext())),
CurGlobalVar(DummyGlobalVar) {}
private:
// Keeps track of how many initializers are expected for the global variable
// being built.
// declaration being built.
unsigned InitializersNeeded;
// The index of the next global variable.
// The index of the next global variable declaration.
unsigned NextGlobalID;
// Holds the current global address whose initializer is being defined.
Ice::GlobalAddress *CurrentAddress;
// Dummy global variable declaration to guarantee CurGlobalVar is
// always defined (allowing code to not need to check if
// CurGlobalVar is nullptr).
Ice::VariableDeclaration *DummyGlobalVar;
// Dummy global address to guarantee CurrentAddress is always defined
// (allowing code to not need to check if CurrentAddress is nullptr).
Ice::GlobalAddress DummyAddress;
// Holds the current global variable declaration being built.
Ice::VariableDeclaration *CurGlobalVar;
void ExitBlock() override {
verifyNoMissingInitializers();
unsigned NumIDs = Context->getNumGlobalAddresses();
unsigned NumIDs = Context->getNumGlobalVariables();
if (NextGlobalID < NumIDs) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Globals block expects " << NumIDs
<< " global definitions. Found: " << NextGlobalID;
<< " global variable declarations. Found: " << NextGlobalID;
Error(StrBuf.str());
}
BlockParserBaseClass::ExitBlock();
......@@ -786,12 +829,12 @@ private:
void ProcessRecord() override;
// Checks if the number of initializers for the CurrentAddress is the same as
// Checks if the number of initializers for the CurGlobalVar is the same as
// the number found in the bitcode file. If different, and error message is
// generated, and the internal state of the parser is fixed so this condition
// is no longer violated.
void verifyNoMissingInitializers() {
size_t NumInits = CurrentAddress->getInitializers().size();
size_t NumInits = CurGlobalVar->getInitializers().size();
if (InitializersNeeded != NumInits) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
......@@ -801,6 +844,7 @@ private:
StrBuf << "s";
StrBuf << ". Found: " << NumInits;
Error(StrBuf.str());
InitializersNeeded = NumInits;
}
}
};
......@@ -812,11 +856,11 @@ void GlobalsParser::ProcessRecord() {
// COUNT: [n]
if (!isValidRecordSize(1, "Globals count"))
return;
if (NextGlobalID != Context->getNumGlobalAddresses()) {
if (NextGlobalID != Context->getNumGlobalVariables()) {
Error("Globals count record not first in block.");
return;
}
Context->CreateGlobalAddresses(Values[0]);
Context->CreateGlobalVariables(Values[0]);
return;
case naclbitc::GLOBALVAR_VAR: {
// VAR: [align, isconst]
......@@ -824,9 +868,9 @@ void GlobalsParser::ProcessRecord() {
return;
verifyNoMissingInitializers();
InitializersNeeded = 1;
CurrentAddress = Context->getGlobalAddress(NextGlobalID);
CurrentAddress->setAlignment((1 << Values[0]) >> 1);
CurrentAddress->setIsConstant(Values[1] != 0);
CurGlobalVar = Context->getGlobalVariableByID(NextGlobalID);
CurGlobalVar->setAlignment((1 << Values[0]) >> 1);
CurGlobalVar->setIsConstant(Values[1] != 0);
++NextGlobalID;
return;
}
......@@ -834,7 +878,7 @@ void GlobalsParser::ProcessRecord() {
// COMPOUND: [size]
if (!isValidRecordSize(1, "globals compound"))
return;
if (!CurrentAddress->getInitializers().empty()) {
if (!CurGlobalVar->getInitializers().empty()) {
Error("Globals compound record not first initializer");
return;
}
......@@ -851,17 +895,17 @@ void GlobalsParser::ProcessRecord() {
// ZEROFILL: [size]
if (!isValidRecordSize(1, "Globals zerofill"))
return;
CurrentAddress->addInitializer(
new Ice::GlobalAddress::ZeroInitializer(Values[0]));
break;
CurGlobalVar->addInitializer(
new Ice::VariableDeclaration::ZeroInitializer(Values[0]));
return;
}
case naclbitc::GLOBALVAR_DATA: {
// DATA: [b0, b1, ...]
if (!isValidRecordSizeAtLeast(1, "Globals data"))
return;
CurrentAddress->addInitializer(
new Ice::GlobalAddress::DataInitializer(Values));
break;
CurGlobalVar->addInitializer(
new Ice::VariableDeclaration::DataInitializer(Values));
return;
}
case naclbitc::GLOBALVAR_RELOC: {
// RELOC: [val, [addend]]
......@@ -871,19 +915,9 @@ void GlobalsParser::ProcessRecord() {
Ice::SizeT Offset = 0;
if (Values.size() == 2)
Offset = Values[1];
unsigned NumFunctions = Context->getNumFunctionIDs();
if (Index < NumFunctions) {
llvm::Function *Fcn = Context->getFunctionByID(Index);
Ice::GlobalAddress::RelocationAddress Addr(Fcn);
CurrentAddress->addInitializer(
new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
} else {
Ice::GlobalAddress::RelocationAddress Addr(
Context->getGlobalAddress(Index - NumFunctions));
CurrentAddress->addInitializer(
new Ice::GlobalAddress::RelocInitializer(Addr, Offset));
}
break;
CurGlobalVar->addInitializer(new Ice::VariableDeclaration::RelocInitializer(
Context->getGlobalDeclarationByID(Index), Offset));
return;
}
default:
BlockParserBaseClass::ProcessRecord();
......@@ -964,23 +998,25 @@ public:
: BlockParserBaseClass(BlockID, EnclosingParser),
Func(new Ice::Cfg(getTranslator().getContext())), CurrentBbIndex(0),
FcnId(Context->getNextFunctionBlockValueID()),
LLVMFunc(Context->getFunctionByID(FcnId)),
FuncDecl(Context->getFunctionByID(FcnId)),
CachedNumGlobalValueIDs(Context->getNumGlobalIDs()),
NextLocalInstIndex(Context->getNumGlobalIDs()),
InstIsTerminating(false) {
Func->setFunctionName(LLVMFunc->getName());
Func->setFunctionName(FuncDecl->getName());
if (getFlags().TimeEachFunction)
getTranslator().getContext()->pushTimer(
getTranslator().getContext()->getTimerID(
Ice::GlobalContext::TSK_Funcs, Func->getFunctionName()),
Ice::GlobalContext::TSK_Funcs);
Func->setReturnType(Context->convertToIceType(LLVMFunc->getReturnType()));
Func->setInternal(LLVMFunc->hasInternalLinkage());
// TODO(kschimpf) Clean up API to add a function signature to
// a CFG.
const Ice::FuncSigType &Signature = FuncDecl->getSignature();
Func->setReturnType(Signature.getReturnType());
Func->setInternal(FuncDecl->getLinkage() == GlobalValue::InternalLinkage);
CurrentNode = InstallNextBasicBlock();
Func->setEntryNode(CurrentNode);
for (auto ArgI = LLVMFunc->arg_begin(), ArgE = LLVMFunc->arg_end();
ArgI != ArgE; ++ArgI) {
Func->addArg(getNextInstVar(Context->convertToIceType(ArgI->getType())));
for (Ice::Type ArgType : Signature.getArgList()) {
Func->addArg(getNextInstVar(ArgType));
}
}
......@@ -1000,8 +1036,8 @@ private:
Ice::CfgNode *CurrentNode;
// The ID for the function.
unsigned FcnId;
// The corresponding LLVM function.
Function *LLVMFunc;
// The corresponding function declaration.
Ice::FunctionDeclaration *FuncDecl;
// Holds the dividing point between local and global absolute value indices.
uint32_t CachedNumGlobalValueIDs;
// Holds operands local to the function block, based on indices
......@@ -1999,12 +2035,12 @@ void FunctionParser::ProcessRecord() {
// CALL_INDIRECT: [cc, fn, returnty, args...]
//
// Note: The difference between CALL and CALL_INDIRECT is that
// CALL has an explicit function address, while the CALL_INDIRECT
// is just an address. For CALL, we can infer the return type by
// looking up the type signature associated with the function
// address. For CALL_INDIRECT we can only infer the type signature
// via argument types, and the corresponding return type stored in
// CALL_INDIRECT record.
// CALL has a reference to an explicit function declaration, while
// the CALL_INDIRECT is just an address. For CALL, we can infer
// the return type by looking up the type signature associated
// with the function declaration. For CALL_INDIRECT we can only
// infer the type signature via argument types, and the
// corresponding return type stored in CALL_INDIRECT record.
Ice::SizeT ParamsStartIndex = 2;
if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
if (!isValidRecordSizeAtLeast(2, "function block call"))
......@@ -2034,17 +2070,9 @@ void FunctionParser::ProcessRecord() {
Ice::Type ReturnType = Ice::IceType_void;
const Ice::Intrinsics::FullIntrinsicInfo *IntrinsicInfo = nullptr;
if (Record.GetCode() == naclbitc::FUNC_CODE_INST_CALL) {
Function *Fcn = Context->getFunctionByID(CalleeIndex);
if (Fcn == nullptr) {
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Function call to non-function: " << *Callee;
Error(StrBuf.str());
return;
}
FunctionType *FcnTy = Fcn->getFunctionType();
ReturnType = Context->convertToIceType(FcnTy->getReturnType());
Ice::FunctionDeclaration *Fcn = Context->getFunctionByID(CalleeIndex);
const Ice::FuncSigType &Signature = Fcn->getSignature();
ReturnType = Signature.getReturnType();
// Check if this direct call is to an Intrinsic (starts with "llvm.")
static Ice::IceString LLVMPrefix("llvm.");
......@@ -2339,45 +2367,60 @@ class ModuleParser : public BlockParserBaseClass {
public:
ModuleParser(unsigned BlockID, TopLevelParser *Context)
: BlockParserBaseClass(BlockID, Context),
GlobalAddressNamesAndInitializersInstalled(false) {}
GlobalDeclarationNamesAndInitializersInstalled(false) {}
~ModuleParser() override {}
private:
// True if we have already instaledl names for unnamed global addresses,
// and generated global constant initializers.
bool GlobalAddressNamesAndInitializersInstalled;
// Generates names for unnamed global addresses, and lowers global
// constant initializers to the target. May be called multiple
// times. Only the first call will do the installation.
void InstallGlobalAddressNamesAndInitializers() {
if (!GlobalAddressNamesAndInitializersInstalled) {
// True if we have already installed names for unnamed global declarations,
// and have generated global constant initializers.
bool GlobalDeclarationNamesAndInitializersInstalled;
// Generates names for unnamed global addresses (i.e. functions and
// global variables). Then lowers global variable declaration
// initializers to the target. May be called multiple times. Only
// the first call will do the installation.
void InstallGlobalNamesAndGlobalVarInitializers() {
if (!GlobalDeclarationNamesAndInitializersInstalled) {
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());
}
for (Ice::VariableDeclaration *Var : Context->getGlobalVariables()) {
installDeclarationName(Trans, Var, GlobalPrefix, "global", NameIndex);
}
}
const Ice::IceString &FunctionPrefix = getFlags().DefaultFunctionPrefix;
if (!FunctionPrefix.empty()) {
uint32_t NameIndex = 0;
for (Ice::FunctionDeclaration *Func :
Context->getFunctionDeclarationList()) {
installDeclarationName(Trans, Func, FunctionPrefix, "function",
NameIndex);
}
}
Trans.nameUnnamedFunctions(Context->getModule());
getTranslator().lowerGlobals(Context->getGlobalIDAddresses());
GlobalAddressNamesAndInitializersInstalled = true;
getTranslator().lowerGlobals(Context->getGlobalVariables());
GlobalDeclarationNamesAndInitializersInstalled = true;
}
}
void installDeclarationName(Ice::Translator &Trans,
Ice::GlobalDeclaration *Decl,
const Ice::IceString &Prefix, const char *Context,
uint32_t &NameIndex) {
if (!Decl->hasName()) {
Decl->setName(Trans.createUnnamedName(Prefix, NameIndex));
++NameIndex;
} else {
Trans.checkIfUnnamedNameSafe(Decl->getName(), Context, Prefix,
Trans.getContext()->getStrDump());
}
}
bool ParseBlock(unsigned BlockID) override;
void ExitBlock() override {
InstallGlobalAddressNamesAndInitializers();
InstallGlobalNamesAndGlobalVarInitializers();
getTranslator().emitConstants();
}
......@@ -2400,26 +2443,8 @@ private:
};
void ModuleValuesymtabParser::setValueName(uint64_t Index, StringType &Name) {
if (Index < Context->getNumFunctionIDs()) {
Function *Fcn = Context->getFunctionByID(Index);
if (Fcn != nullptr) {
Fcn->setName(StringRef(Name.data(), Name.size()));
return;
}
} else {
unsigned NumFunctions = Context->getNumFunctionIDs();
if (Index >= NumFunctions) {
Context->getGlobalAddress(Index - NumFunctions)
->setName(StringRef(Name.data(), Name.size()));
}
return;
}
std::string Buffer;
raw_string_ostream StrBuf(Buffer);
StrBuf << "Invalid global address ID in valuesymtab: " << Index;
Error(StrBuf.str());
return;
Context->getGlobalDeclarationByID(Index)
->setName(StringRef(Name.data(), Name.size()));
}
void ModuleValuesymtabParser::setBbName(uint64_t Index, StringType &Name) {
......@@ -2447,7 +2472,7 @@ bool ModuleParser::ParseBlock(unsigned BlockID) {
return Parser.ParseThisBlock();
}
case naclbitc::FUNCTION_BLOCK_ID: {
InstallGlobalAddressNamesAndInitializers();
InstallGlobalNamesAndGlobalVarInitializers();
FunctionParser Parser(BlockID, this);
return Parser.ParseThisBlock();
}
......@@ -2476,7 +2501,7 @@ void ModuleParser::ProcessRecord() {
// FUNCTION: [type, callingconv, isproto, linkage]
if (!isValidRecordSize(4, "Function heading"))
return;
const Ice::FuncSigType &Ty = Context->getFuncSigTypeByID(Values[0]);
const Ice::FuncSigType &Signature = Context->getFuncSigTypeByID(Values[0]);
CallingConv::ID CallingConv;
if (!naclbitc::DecodeCallingConv(Values[1], CallingConv)) {
std::string Buffer;
......@@ -2494,19 +2519,12 @@ void ModuleParser::ProcessRecord() {
Error(StrBuf.str());
return;
}
SmallVector<Type *, 8> ArgTys;
for (Ice::Type ArgType : Ty.getArgList()) {
ArgTys.push_back(Context->convertToLLVMType(ArgType));
}
Function *Func = Function::Create(
FunctionType::get(Context->convertToLLVMType(Ty.getReturnType()),
ArgTys, false),
Linkage, "", Context->getModule());
Func->setCallingConv(CallingConv);
Ice::FunctionDeclaration *Func = Ice::FunctionDeclaration::create(
getTranslator().getContext(), Signature, CallingConv, Linkage,
Values[2] == 0);
if (Values[2] == 0)
Context->setNextValueIDAsImplementedFunction();
Context->setNextFunctionID(Func);
// TODO(kschimpf) verify if Func matches PNaCl ABI.
return;
}
default:
......
; Tests if we handle global variables with relocation initializers.
; Test that we handle it in the ICE converter.
; RUN: %lc2i -i %s --args -verbose inst | FileCheck %s
; Test that we handle it using Subzero's bitcode reader.
; RUN: %p2i -i %s --args -verbose inst | FileCheck %s
@bytes = internal global [7 x i8] c"abcdefg"
; CHECK: @bytes = internal global [7 x i8] c"abcdefg"
; CHECK: .type bytes,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:bytes:
; CHECK: .byte 97
; CHECK: .byte 98
; CHECK: .byte 99
; CHECK: .byte 100
; CHECK: .byte 101
; CHECK: .byte 102
; CHECK: .byte 103
; CHECK: .size bytes, 7
@const_bytes = internal constant [7 x i8] c"abcdefg"
; CHECK: @const_bytes = internal constant [7 x i8] c"abcdefg"
; CHECK: .type const_bytes,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_bytes:
; CHECK: .byte 97
; CHECK: .byte 98
; CHECK: .byte 99
; CHECK: .byte 100
; CHECK: .byte 101
; CHECK: .byte 102
; CHECK: .byte 103
; CHECK: .size const_bytes, 7
@ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32)
; CHECK: @ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32)
; CHECK: .type ptr_to_ptr,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:ptr_to_ptr:
; CHECK: .long ptr
; CHECK: .size ptr_to_ptr, 4
@const_ptr_to_ptr = internal constant i32 ptrtoint (i32* @ptr to i32)
; CHECK: @const_ptr_to_ptr = internal constant i32 ptrtoint (i32* @ptr to i32)
; CHECK: .type const_ptr_to_ptr,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_ptr_to_ptr:
; CHECK: .long ptr
; CHECK: .size const_ptr_to_ptr, 4
@ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32)
; CHECK: @ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32)
; CHECK: .type ptr_to_func,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:ptr_to_func:
; CHECK: .long func
; CHECK: .size ptr_to_func, 4
@const_ptr_to_func = internal constant i32 ptrtoint (void ()* @func to i32)
; CHECK: @const_ptr_to_func = internal constant i32 ptrtoint (void ()* @func to i32)
; CHECK: .type const_ptr_to_func,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_ptr_to_func:
; CHECK: .long func
; CHECK: .size const_ptr_to_func, 4
@compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK: @compound = internal global <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK: .type compound,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:compound:
; CHECK: .byte 102
; CHECK: .byte 111
; CHECK: .byte 111
; CHECK: .long func
; CHECK: .size compound, 7
@const_compound = internal constant <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK: @const_compound = internal constant <{ [3 x i8], i32 }> <{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK: .type const_compound,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_compound:
; CHECK: .byte 102
; CHECK: .byte 111
; CHECK: .byte 111
; CHECK: .long func
; CHECK: .size const_compound, 7
@ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32)
; CHECK: @ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32)
; CHECK: .type ptr,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:ptr:
; CHECK: .long bytes
; CHECK: .size ptr, 4
@const_ptr = internal constant i32 ptrtoint ([7 x i8]* @bytes to i32)
; CHECK: @const_ptr = internal constant i32 ptrtoint ([7 x i8]* @bytes to i32)
; CHECK: .type const_ptr,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_ptr:
; CHECK: .long bytes
; CHECK: .size const_ptr, 4
@addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK: @addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK: .type addend_ptr,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_ptr:
; CHECK: .long ptr + 1
; CHECK: .size addend_ptr, 4
@const_addend_ptr = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK: @const_addend_ptr = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK: .type const_addend_ptr,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_ptr:
; CHECK: .long ptr + 1
; CHECK: .size const_addend_ptr, 4
@addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
; CHECK: @addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
; CHECK: .type addend_negative,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_negative:
; CHECK: .long ptr - 1
; CHECK: .size addend_negative, 4
@const_addend_negative = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
; CHECK: @const_addend_negative = internal constant i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
; CHECK: .type const_addend_negative,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_negative:
; CHECK: .long ptr - 1
; CHECK: .size const_addend_negative, 4
@addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
; CHECK: @addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
; CHECK: .type addend_array1,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_array1:
; CHECK: .long bytes + 1
; CHECK: .size addend_array1, 4
@const_addend_array1 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
; CHECK: @const_addend_array1 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
; CHECK: .type const_addend_array1,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_array1:
; CHECK: .long bytes + 1
; CHECK: .size const_addend_array1, 4
@addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
; CHECK: @addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
; CHECK: .type addend_array2,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_array2:
; CHECK: .long bytes + 7
; CHECK: .size addend_array2, 4
@const_addend_array2 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
; CHECK: @const_addend_array2 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
; CHECK: .type const_addend_array2,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_array2:
; CHECK: .long bytes + 7
; CHECK: .size const_addend_array2, 4
@addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
; CHECK: @addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
; CHECK: .type addend_array3,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_array3:
; CHECK: .long bytes + 9
; CHECK: .size addend_array3, 4
@const_addend_array3 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
; CHECK: @const_addend_array3 = internal constant i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
; CHECK: .type const_addend_array3,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_array3:
; CHECK: .long bytes + 9
; CHECK: .size const_addend_array3, 4
@addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
; CHECK: @addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
; CHECK: .type addend_struct1,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_struct1:
; CHECK: .long compound + 1
; CHECK: .size addend_struct1, 4
@const_addend_struct1 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
; CHECK: @const_addend_struct1 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
; CHECK: .type const_addend_struct1,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_struct1:
; CHECK: .long compound + 1
; CHECK: .size const_addend_struct1, 4
@addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK: @addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK: .type addend_struct2,@object
; CHECK: .section .data,"aw",@progbits
; CHECK:addend_struct2:
; CHECK: .long compound + 4
; CHECK: .size addend_struct2, 4
@const_addend_struct2 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK: @const_addend_struct2 = internal constant i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK: .type const_addend_struct2,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:const_addend_struct2:
; CHECK: .long compound + 4
; CHECK: .size const_addend_struct2, 4
@ptr_to_func_align = internal global i32 ptrtoint (void ()* @func to i32), align 8
; CHECK: @ptr_to_func_align = internal global i32 ptrtoint (void ()* @func to i32), align 8
; CHECK: .type ptr_to_func_align,@object
; CHECK: .section .data,"aw",@progbits
; CHECK: .align 8
; CHECK:ptr_to_func_align:
; CHECK: .long func
; CHECK: .size ptr_to_func_align, 4
@const_ptr_to_func_align = internal constant i32 ptrtoint (void ()* @func to i32), align 8
; CHECK: @const_ptr_to_func_align = internal constant i32 ptrtoint (void ()* @func to i32), align 8
; CHECK: .type const_ptr_to_func_align,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK: .align 8
; CHECK:const_ptr_to_func_align:
; CHECK: .long func
; CHECK: .size const_ptr_to_func_align, 4
@char = internal constant [1 x i8] c"0"
; CHECK: @char = internal constant [1 x i8] c"0"
; CHECK: .type char,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:char:
; CHECK: .byte 48
; CHECK: .size char, 1
@short = internal constant [2 x i8] zeroinitializer
; CHECK: @short = internal constant [2 x i8] zeroinitializer
; CHECK: .type short,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK:short:
; CHECK: .zero 2
; CHECK: .size short, 2
define void @func() {
ret void
}
; CHECK: define void @func() {
; Test of global initializers.
; Check that we generate proper global initializers.
; RUN: %p2i -i %s --args -verbose inst | FileCheck %s
; Check that what we generate is valid assembly
; RUN: %p2i -i %s --args -verbose none \
; RUN: | llvm-mc -triple=i686-none-nacl -x86-asm-syntax=intel -filetype=obj
; Check that we don't generate errors
; RUN: %p2i -i %s --args -verbose none | FileCheck --check-prefix=ERRORS %s
; RUN: %l2i -i %s --insts | FileCheck %s
; RUN: %p2i -i %s --insts | FileCheck %s
@PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
; CHECK: .type PrimitiveInit,@object
; CHECK-NEXT: .section .data,"aw",@progbits
; CHECK-NEXT: .align 4
; CHECK-NEXT: PrimitiveInit:
; CHECK-NEXT: .byte
; CHECK: .size PrimitiveInit, 4
; CHECK: @PrimitiveInit = internal global [4 x i8] c"\1B\00\00\00", align 4
@PrimitiveInitConst = internal constant [4 x i8] c"\0D\00\00\00", align 4
; CHECK: .type PrimitiveInitConst,@object
; CHECK-NEXT: .section .rodata,"a",@progbits
; CHECK-NEXT: .align 4
; CHECK-NEXT: PrimitiveInitConst:
; CHECK-NEXT: .byte
; CHECK: .size PrimitiveInitConst, 4
; CHECK-NEXT: @PrimitiveInitConst = internal constant [4 x i8] c"\0D\00\00\00", align 4
@ArrayInit = internal global [20 x i8] c"\0A\00\00\00\14\00\00\00\1E\00\00\00(\00\00\002\00\00\00", align 4
; CHECK: .type ArrayInit,@object
; CHECK-NEXT: .section .data,"aw",@progbits
; CHECK-NEXT: .align 4
; CHECK-NEXT: ArrayInit:
; CHECK-NEXT: .byte
; CHECK: .size ArrayInit, 20
; CHECK-NEXT: @ArrayInit = internal global [20 x i8] c"\0A\00\00\00\14\00\00\00\1E\00\00\00(\00\00\002\00\00\00", align 4
@ArrayInitPartial = internal global [40 x i8] c"<\00\00\00F\00\00\00P\00\00\00Z\00\00\00d\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", align 4
; CHECK: .type ArrayInitPartial,@object
; CHECK-NEXT: .section .data,"aw",@progbits
; CHECK-NEXT: .align 4
; CHECK-NEXT: ArrayInitPartial:
; CHECK-NEXT: .byte
; CHECK: .size ArrayInitPartial, 40
; CHECK-NEXT: @ArrayInitPartial = internal global [40 x i8] c"<\00\00\00F\00\00\00P\00\00\00Z\00\00\00d\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", align 4
@PrimitiveInitStatic = internal global [4 x i8] zeroinitializer, align 4
; CHECK: .type PrimitiveInitStatic,@object
; CHECK-NEXT: .local PrimitiveInitStatic
; CHECK-NEXT: .comm PrimitiveInitStatic,4,4
; CHECK-NEXT: @PrimitiveInitStatic = internal global [4 x i8] zeroinitializer, align 4
@PrimitiveUninit = internal global [4 x i8] zeroinitializer, align 4
; CHECK: .type PrimitiveUninit,@object
; CHECK-NEXT: .local PrimitiveUninit
; CHECK-NEXT: .comm PrimitiveUninit,4,4
; CHECK-NEXT: @PrimitiveUninit = internal global [4 x i8] zeroinitializer, align 4
@ArrayUninit = internal global [20 x i8] zeroinitializer, align 4
; CHECK: .type ArrayUninit,@object
; CHECK-NEXT: .local ArrayUninit
; CHECK-NEXT: .comm ArrayUninit,20,4
; CHECK-NEXT: @ArrayUninit = internal global [20 x i8] zeroinitializer, align 4
@ArrayUninitConstDouble = internal constant [200 x i8] zeroinitializer, align 8
; CHECK: .type ArrayUninitConstDouble,@object
; CHECK-NEXT: .section .rodata,"a",@progbits
; CHECK-NEXT: .align 8
; CHECK-NEXT: ArrayUninitConstDouble:
; CHECK-NEXT: .zero 200
; CHECK-NEXT: .size ArrayUninitConstDouble, 200
; CHECK-NEXT: @ArrayUninitConstDouble = internal constant [200 x i8] zeroinitializer, align 8
@ArrayUninitConstInt = internal constant [20 x i8] zeroinitializer, align 4
; CHECK: .type ArrayUninitConstInt,@object
; CHECK: .section .rodata,"a",@progbits
; CHECK-NEXT: .align 4
; CHECK-NEXT: ArrayUninitConstInt:
; CHECK-NEXT: .zero 20
; CHECK-NEXT: .size ArrayUninitConstInt, 20
; CHECK-NEXT: @ArrayUninitConstInt = internal constant [20 x i8] zeroinitializer, align 4
@__init_array_start = internal constant [0 x i8] zeroinitializer, align 4
; CHECK-NEXT: @__init_array_start = internal constant [0 x i8] zeroinitializer, align 4
@__fini_array_start = internal constant [0 x i8] zeroinitializer, align 4
; CHECK: @__fini_array_start = internal constant [0 x i8] zeroinitializer, align 4
@__tls_template_start = internal constant [0 x i8] zeroinitializer, align 8
; CHECK: @__tls_template_start = internal constant [0 x i8] zeroinitializer, align 8
@__tls_template_alignment = internal constant [4 x i8] c"\01\00\00\00", align 4
; CHECK: @__tls_template_alignment = internal constant [4 x i8] c"\01\00\00\00", align 4
define internal i32 @main(i32 %argc, i32 %argv) {
entry:
......@@ -96,28 +61,6 @@ entry:
call void @use(i32 %expanded13)
ret i32 0
}
; CHECK-LABEL: main
; CHECK: .att_syntax
; CHECK: leal PrimitiveInit,
; CHECK: .intel_syntax
; CHECK: .att_syntax
; CHECK: leal PrimitiveInitConst,
; CHECK: .intel_syntax
; CHECK: .att_syntax
; CHECK: leal PrimitiveInitStatic,
; CHECK: .intel_syntax
; CHECK: .att_syntax
; CHECK: leal PrimitiveUninit,
; CHECK: .intel_syntax
; CHECK: .att_syntax
; CHECK: leal ArrayInit,
; CHECK: .intel_syntax
; CHECK: .att_syntax
; CHECK: leal ArrayInitPartial,
; CHECK: .intel_syntax
; CHECK: .att_syntax
; CHECK: leal ArrayUninit,
; CHECK: .intel_syntax
declare void @use(i32)
......
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