Commit 1f47ad02 by Jan Voung

Move some flag-like props from GlobalContext and TargetLowering to ClFlags.

Simplifies the GlobalContext constructor so that a future change may just set up the flags and the GlobalContext before calling into what is currently "main". Namely this change: https://codereview.chromium.org/997773002/ This also moves all uses of LLVM's CommandLine.h to a single file, so that in the future we may be able to simplify the flags parsing (especially for the minimal build). BUG= https://code.google.com/p/nativeclient/issues/detail?id=4091 BUG= https://code.google.com/p/nativeclient/issues/detail?id=4084 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1024203002
parent 5dfdf5fc
......@@ -32,15 +32,16 @@ ArenaAllocator<> *getCurrentCfgAllocator() {
}
Cfg::Cfg(GlobalContext *Ctx, uint32_t SequenceNumber)
: Ctx(Ctx), SequenceNumber(SequenceNumber), VMask(Ctx->getVerbose()),
FunctionName(""), ReturnType(IceType_void), IsInternalLinkage(false),
HasError(false), FocusedTiming(false), ErrorMessage(""), Entry(nullptr),
: Ctx(Ctx), SequenceNumber(SequenceNumber),
VMask(Ctx->getFlags().getVerbose()), FunctionName(""),
ReturnType(IceType_void), IsInternalLinkage(false), HasError(false),
FocusedTiming(false), ErrorMessage(""), Entry(nullptr),
NextInstNumber(Inst::NumberInitial), Allocator(new ArenaAllocator<>()),
Live(nullptr),
Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)),
Live(nullptr), Target(TargetLowering::createLowering(
Ctx->getFlags().getTargetArch(), this)),
VMetadata(new VariablesMetadata(this)),
TargetAssembler(
TargetLowering::createAssembler(Ctx->getTargetArch(), this)),
TargetAssembler(TargetLowering::createAssembler(
Ctx->getFlags().getTargetArch(), this)),
CurrentNode(nullptr) {
assert(!Ctx->isIRGenerationDisabled() &&
"Attempt to build cfg when IR generation disabled");
......
......@@ -14,7 +14,7 @@
#ifndef SUBZERO_SRC_ICECLFLAGS_H
#define SUBZERO_SRC_ICECLFLAGS_H
#include "IceTypes.def"
#include "IceTypes.h"
namespace Ice {
......@@ -30,15 +30,18 @@ public:
DecorateAsm(false), DisableInternal(false), DisableIRGeneration(false),
DisableTranslation(false), DumpStats(false), FunctionSections(false),
GenerateUnitTestMessages(false), PhiEdgeSplit(false),
RandomNopInsertion(false), RandomRegAlloc(false),
SubzeroTimingEnabled(false), TimeEachFunction(false),
UseSandboxing(false),
// FileType field
OutFileType(FT_Iasm),
// Enum and integer fields
Opt(Opt_m1), OutFileType(FT_Iasm), RandomMaxNopsPerInstruction(0),
RandomNopProbabilityAsPercentage(0), TArch(TargetArch_NUM),
VMask(IceV_None),
// IceString fields.
DefaultFunctionPrefix(""), DefaultGlobalPrefix(""), TimingFocusOn(""),
TranslateOnly(""), VerboseFocusOn(""),
// size_t fields.
NumTranslationThreads(0) {}
DefaultFunctionPrefix(""), DefaultGlobalPrefix(""), TestPrefix(""),
TimingFocusOn(""), TranslateOnly(""), VerboseFocusOn(""),
// size_t and 64-bit fields.
NumTranslationThreads(0), RandomSeed(0) {}
// bool accessors.
......@@ -87,6 +90,12 @@ public:
bool getPhiEdgeSplit() const { return PhiEdgeSplit; }
void setPhiEdgeSplit(bool NewValue) { PhiEdgeSplit = NewValue; }
bool shouldDoNopInsertion() const { return RandomNopInsertion; }
void setShouldDoNopInsertion(bool NewValue) { RandomNopInsertion = NewValue; }
bool shouldRandomizeRegAlloc() const { return RandomRegAlloc; }
void setShouldRandomizeRegAlloc(bool NewValue) { RandomRegAlloc = NewValue; }
bool getSubzeroTimingEnabled() const { return SubzeroTimingEnabled; }
void setSubzeroTimingEnabled(bool NewValue) {
SubzeroTimingEnabled = NewValue;
......@@ -98,10 +107,36 @@ public:
bool getUseSandboxing() const { return UseSandboxing; }
void setUseSandboxing(bool NewValue) { UseSandboxing = NewValue; }
// FileType accessor.
// Enum and integer accessors.
OptLevel getOptLevel() const { return Opt; }
void setOptLevel(OptLevel NewValue) { Opt = NewValue; }
FileType getOutFileType() const { return OutFileType; }
void setOutFileType(FileType NewValue) { OutFileType = NewValue; }
int getMaxNopsPerInstruction() const { return RandomMaxNopsPerInstruction; }
void setMaxNopsPerInstruction(int NewValue) {
RandomMaxNopsPerInstruction = NewValue;
}
int getNopProbabilityAsPercentage() const {
return RandomNopProbabilityAsPercentage;
}
void setNopProbabilityAsPercentage(int NewValue) {
RandomNopProbabilityAsPercentage = NewValue;
}
TargetArch getTargetArch() const { return TArch; }
void setTargetArch(TargetArch NewValue) { TArch = NewValue; }
TargetInstructionSet getTargetInstructionSet() const { return TInstrSet; }
void setTargetInstructionSet(TargetInstructionSet NewValue) {
TInstrSet = NewValue;
}
VerboseMask getVerbose() const { return ALLOW_DUMP ? VMask : IceV_None; }
void setVerbose(VerboseMask NewValue) { VMask = NewValue; }
// IceString accessors.
const IceString &getDefaultFunctionPrefix() const {
......@@ -118,6 +153,9 @@ public:
DefaultGlobalPrefix = NewValue;
}
const IceString &getTestPrefix() const { return TestPrefix; }
void setTestPrefix(const IceString &NewValue) { TestPrefix = NewValue; }
const IceString &getTimingFocusOn() const { return TimingFocusOn; }
void setTimingFocusOn(const IceString &NewValue) { TimingFocusOn = NewValue; }
......@@ -129,7 +167,7 @@ public:
VerboseFocusOn = NewValue;
}
// size_t accessors.
// size_t and 64-bit accessors.
size_t getNumTranslationThreads() const { return NumTranslationThreads; }
bool isSequential() const { return NumTranslationThreads == 0; }
......@@ -137,6 +175,9 @@ public:
NumTranslationThreads = NewValue;
}
uint64_t getRandomSeed() const { return RandomSeed; }
void setRandomSeed(size_t NewValue) { RandomSeed = NewValue; }
private:
bool AllowErrorRecovery;
bool AllowUninitializedGlobals;
......@@ -149,19 +190,29 @@ private:
bool FunctionSections;
bool GenerateUnitTestMessages;
bool PhiEdgeSplit;
bool RandomNopInsertion;
bool RandomRegAlloc;
bool SubzeroTimingEnabled;
bool TimeEachFunction;
bool UseSandboxing;
OptLevel Opt;
FileType OutFileType;
int RandomMaxNopsPerInstruction;
int RandomNopProbabilityAsPercentage;
TargetArch TArch;
TargetInstructionSet TInstrSet;
VerboseMask VMask;
IceString DefaultFunctionPrefix;
IceString DefaultGlobalPrefix;
IceString TestPrefix;
IceString TimingFocusOn;
IceString TranslateOnly;
IceString VerboseFocusOn;
size_t NumTranslationThreads; // 0 means completely sequential
uint64_t RandomSeed;
};
} // end of namespace Ice
......
......@@ -64,7 +64,8 @@ uint32_t getELFFlags(TargetArch Arch) {
} // end of anonymous namespace
ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out)
: Ctx(Ctx), Str(Out), SectionNumbersAssigned(false) {
: Ctx(Ctx), Str(Out), SectionNumbersAssigned(false),
ELF64(isELF64(Ctx.getFlags().getTargetArch())) {
// Create the special bookkeeping sections now.
const IceString NullSectionName("");
NullSection = new (Ctx.allocate<ELFSection>())
......@@ -76,10 +77,9 @@ ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out)
ShStrTab->add(ShStrTabName);
const IceString SymTabName(".symtab");
bool IsELF64 = isELF64(Ctx.getTargetArch());
const Elf64_Xword SymTabAlign = IsELF64 ? 8 : 4;
const Elf64_Xword SymTabAlign = ELF64 ? 8 : 4;
const Elf64_Xword SymTabEntSize =
IsELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
ELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym);
static_assert(sizeof(Elf64_Sym) == 24 && sizeof(Elf32_Sym) == 16,
"Elf_Sym sizes cannot be derived from sizeof");
SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0,
......@@ -103,18 +103,16 @@ T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType,
}
ELFRelocationSection *
ELFObjectWriter::createRelocationSection(bool IsELF64,
const ELFSection *RelatedSection) {
ELFObjectWriter::createRelocationSection(const ELFSection *RelatedSection) {
// Choice of RELA vs REL is actually separate from elf64 vs elf32,
// but in practice we've only had .rela for elf64 (x86-64).
// In the future, the two properties may need to be decoupled
// and the ShEntSize can vary more.
const Elf64_Word ShType = IsELF64 ? SHT_RELA : SHT_REL;
IceString RelPrefix = IsELF64 ? ".rela" : ".rel";
const Elf64_Word ShType = ELF64 ? SHT_RELA : SHT_REL;
IceString RelPrefix = ELF64 ? ".rela" : ".rel";
IceString RelSectionName = RelPrefix + RelatedSection->getName();
const Elf64_Xword ShAlign = IsELF64 ? 8 : 4;
const Elf64_Xword ShEntSize =
IsELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
const Elf64_Xword ShAlign = ELF64 ? 8 : 4;
const Elf64_Xword ShEntSize = ELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel);
static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8,
"Elf_Rel/Rela sizes cannot be derived from sizeof");
const Elf64_Xword ShFlags = 0;
......@@ -220,7 +218,6 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
IceString SectionName = ".text";
if (FunctionSections)
SectionName += "." + FuncName;
bool IsELF64 = isELF64(Ctx.getTargetArch());
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR;
const Elf64_Xword ShAlign = 1 << Asm->getBundleAlignLog2Bytes();
Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags,
......@@ -228,7 +225,7 @@ void ELFObjectWriter::writeFunctionCode(const IceString &FuncName,
Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign());
Section->setFileOffset(OffsetInFile);
TextSections.push_back(Section);
RelSection = createRelocationSection(IsELF64, Section);
RelSection = createRelocationSection(Section);
RelTextSections.push_back(RelSection);
} else {
Section = TextSections[0];
......@@ -295,17 +292,15 @@ void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
SectionList.reserve(Vars.size());
partitionGlobalsBySection(Vars, VarsBySection,
Ctx.getFlags().getTranslateOnly());
bool IsELF64 = isELF64(Ctx.getTargetArch());
size_t I = 0;
for (auto &SectionList : VarsBySection) {
writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
IsELF64);
writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind);
}
}
void ELFObjectWriter::writeDataOfType(SectionType ST,
const VariableDeclarationList &Vars,
FixupKind RelocationKind, bool IsELF64) {
FixupKind RelocationKind) {
if (Vars.empty())
return;
ELFDataSection *Section;
......@@ -329,7 +324,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
RODataSections.push_back(Section);
RelSection = createRelocationSection(IsELF64, Section);
RelSection = createRelocationSection(Section);
RelRODataSections.push_back(RelSection);
break;
}
......@@ -341,7 +336,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
DataSections.push_back(Section);
RelSection = createRelocationSection(IsELF64, Section);
RelSection = createRelocationSection(Section);
RelDataSections.push_back(RelSection);
break;
}
......@@ -422,7 +417,7 @@ void ELFObjectWriter::writeInitialELFHeader() {
const Elf64_Off DummySHOffset = 0;
const SizeT DummySHStrIndex = 0;
const SizeT DummyNumSections = 0;
if (isELF64(Ctx.getTargetArch())) {
if (ELF64) {
writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex,
DummyNumSections);
} else {
......@@ -453,17 +448,18 @@ void ELFObjectWriter::writeELFHeaderInternal(Elf64_Off SectionHeaderOffset,
assert(NumSections < SHN_LORESERVE);
assert(SectHeaderStrIndex < SHN_LORESERVE);
const TargetArch Arch = Ctx.getFlags().getTargetArch();
// Write the rest of the file header, which does depend on byte order
// and ELF class.
Str.writeLE16(ET_REL); // e_type
Str.writeLE16(getELFMachine(Ctx.getTargetArch())); // e_machine
Str.writeELFWord<IsELF64>(1); // e_version
Str.writeLE16(ET_REL); // e_type
Str.writeLE16(getELFMachine(Ctx.getFlags().getTargetArch())); // e_machine
Str.writeELFWord<IsELF64>(1); // e_version
// Since this is for a relocatable object, there is no entry point,
// and no program headers.
Str.writeAddrOrOffset<IsELF64>(0); // e_entry
Str.writeAddrOrOffset<IsELF64>(0); // e_phoff
Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset); // e_shoff
Str.writeELFWord<IsELF64>(getELFFlags(Ctx.getTargetArch())); // e_flags
Str.writeELFWord<IsELF64>(getELFFlags(Arch)); // e_flags
Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize
static_assert(sizeof(Elf64_Ehdr) == 64 && sizeof(Elf32_Ehdr) == 52,
"Elf_Ehdr sizes cannot be derived from sizeof");
......@@ -532,10 +528,10 @@ template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty);
template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty);
void ELFObjectWriter::writeAllRelocationSections(bool IsELF64) {
writeRelocationSections(IsELF64, RelTextSections);
writeRelocationSections(IsELF64, RelDataSections);
writeRelocationSections(IsELF64, RelRODataSections);
void ELFObjectWriter::writeAllRelocationSections() {
writeRelocationSections(RelTextSections);
writeRelocationSections(RelDataSections);
writeRelocationSections(RelRODataSections);
}
void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) {
......@@ -555,13 +551,12 @@ void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) {
}
}
void ELFObjectWriter::writeRelocationSections(bool IsELF64,
RelSectionList &RelSections) {
void ELFObjectWriter::writeRelocationSections(RelSectionList &RelSections) {
for (ELFRelocationSection *RelSec : RelSections) {
Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign());
RelSec->setFileOffset(Offset);
RelSec->setSize(RelSec->getSectionDataSize());
if (IsELF64) {
if (ELF64) {
RelSec->writeData<true>(Ctx, Str, SymTab);
} else {
RelSec->writeData<false>(Ctx, Str, SymTab);
......@@ -570,8 +565,6 @@ void ELFObjectWriter::writeRelocationSections(bool IsELF64,
}
void ELFObjectWriter::writeNonUserSections() {
bool IsELF64 = isELF64(Ctx.getTargetArch());
// Write out the shstrtab now that all sections are known.
ShStrTab->doLayout();
ShStrTab->setSize(ShStrTab->getSectionDataSize());
......@@ -591,19 +584,19 @@ void ELFObjectWriter::writeNonUserSections() {
Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign());
SymTab->setFileOffset(SymTabOffset);
SymTab->setSize(SymTab->getSectionDataSize());
SymTab->writeData(Str, IsELF64);
SymTab->writeData(Str, ELF64);
Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign());
StrTab->setFileOffset(StrTabOffset);
Str.writeBytes(StrTab->getSectionData());
writeAllRelocationSections(IsELF64);
writeAllRelocationSections();
// Write out the section headers.
const size_t ShdrAlign = IsELF64 ? 8 : 4;
const size_t ShdrAlign = ELF64 ? 8 : 4;
Elf64_Off ShOffset = alignFileOffset(ShdrAlign);
for (const auto S : AllSections) {
if (IsELF64)
if (ELF64)
S->writeHeader<true>(Str);
else
S->writeHeader<false>(Str);
......@@ -611,7 +604,7 @@ void ELFObjectWriter::writeNonUserSections() {
// Finally write the updated ELF header w/ the correct number of sections.
Str.seek(0);
if (IsELF64) {
if (ELF64) {
writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(),
AllSections.size());
} else {
......
......@@ -93,6 +93,7 @@ private:
GlobalContext &Ctx;
ELFStreamer &Str;
bool SectionNumbersAssigned;
bool ELF64;
// All created sections, separated into different pools.
typedef std::vector<ELFSection *> SectionList;
......@@ -121,7 +122,7 @@ private:
// Create a relocation section, given the related section
// (e.g., .text, .data., .rodata).
ELFRelocationSection *
createRelocationSection(bool IsELF64, const ELFSection *RelatedSection);
createRelocationSection(const ELFSection *RelatedSection);
// Align the file position before writing out a section's data,
// and return the position of the file.
......@@ -150,13 +151,13 @@ private:
// SectionType, given the global variables Vars belonging to that SectionType.
void writeDataOfType(SectionType SectionType,
const VariableDeclarationList &Vars,
FixupKind RelocationKind, bool IsELF64);
FixupKind RelocationKind);
// Write the final relocation sections given the final symbol table.
// May also be able to seek around the file and resolve function calls
// that are for functions within the same section.
void writeAllRelocationSections(bool IsELF64);
void writeRelocationSections(bool IsELF64, RelSectionList &RelSections);
void writeAllRelocationSections();
void writeRelocationSections(RelSectionList &RelSections);
// Write the ELF file header with the given information about sections.
template <bool IsELF64>
......
......@@ -162,12 +162,9 @@ void GlobalContext::CodeStats::dump(const IceString &Name, Ostream &Str) {
}
GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit,
ELFStreamer *ELFStr, VerboseMask Mask,
TargetArch Arch, OptLevel Opt,
IceString TestPrefix, const ClFlags &Flags)
ELFStreamer *ELFStr, const ClFlags &Flags)
: ConstPool(new ConstantPool()), ErrorStatus(), StrDump(OsDump),
StrEmit(OsEmit), VMask(Mask), Arch(Arch), Opt(Opt),
TestPrefix(TestPrefix), Flags(Flags), RNG(""), ObjectWriter(),
StrEmit(OsEmit), Flags(Flags), RNG(Flags.getRandomSeed()), ObjectWriter(),
OptQ(/*Sequential=*/Flags.isSequential(),
/*MaxSize=*/Flags.getNumTranslationThreads()),
// EmitQ is allowed unlimited size.
......@@ -267,7 +264,7 @@ void lowerGlobals(GlobalContext *Ctx,
std::unique_ptr<VariableDeclarationList> VariableDeclarations,
TargetDataLowering *DataLowering) {
TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx);
const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getVerbose() &&
const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() &&
Ctx->getFlags().getVerboseFocusOn().empty();
if (DumpGlobalVariables) {
OstreamLocker L(Ctx);
......@@ -459,10 +456,11 @@ IceString GlobalContext::mangleName(const IceString &Name) const {
// _Z3barxyz ==> ZN6Prefix3barExyz
// An unmangled, extern "C" style name, gets a simple prefix:
// bar ==> Prefixbar
if (!ALLOW_DUMP || getTestPrefix().empty())
if (!ALLOW_DUMP || getFlags().getTestPrefix().empty())
return Name;
unsigned PrefixLength = getTestPrefix().length();
const IceString &TestPrefix = getFlags().getTestPrefix();
unsigned PrefixLength = TestPrefix.length();
ManglerVector NameBase(1 + Name.length());
const size_t BufLen = 30 + Name.length() + PrefixLength;
ManglerVector NewName(BufLen);
......@@ -473,7 +471,7 @@ IceString GlobalContext::mangleName(const IceString &Name) const {
// Transform _ZN3foo3barExyz ==> _ZN6Prefix3foo3barExyz
// (splice in "6Prefix") ^^^^^^^
snprintf(NewName.data(), BufLen, "_ZN%u%s%s", PrefixLength,
getTestPrefix().c_str(), NameBase.data());
TestPrefix.c_str(), NameBase.data());
// We ignore the snprintf return value (here and below). If we
// somehow miscalculated the output buffer length, the output will
// be truncated, but it will be truncated consistently for all
......@@ -512,7 +510,7 @@ IceString GlobalContext::mangleName(const IceString &Name) const {
OrigName[ActualBaseLength] = '\0';
strcpy(OrigSuffix.data(), NameBase.data() + ActualBaseLength);
snprintf(NewName.data(), BufLen, "_ZN%u%s%u%sE%s", PrefixLength,
getTestPrefix().c_str(), BaseLength, OrigName.data(),
TestPrefix.c_str(), BaseLength, OrigName.data(),
OrigSuffix.data());
incrementSubstitutions(NewName);
return NewName.data();
......@@ -520,7 +518,7 @@ IceString GlobalContext::mangleName(const IceString &Name) const {
// Transform bar ==> Prefixbar
// ^^^^^^
return getTestPrefix() + Name;
return TestPrefix + Name;
}
GlobalContext::~GlobalContext() {
......
......@@ -146,12 +146,9 @@ class GlobalContext {
public:
GlobalContext(Ostream *OsDump, Ostream *OsEmit, ELFStreamer *ELFStreamer,
VerboseMask Mask, TargetArch Arch, OptLevel Opt,
IceString TestPrefix, const ClFlags &Flags);
const ClFlags &Flags);
~GlobalContext();
VerboseMask getVerbose() const { return VMask; }
// The dump and emit streams need to be used by only one thread at a
// time. This is done by exclusively reserving the streams via
// lockStr() and unlockStr(). The OstreamLocker class can be used
......@@ -168,8 +165,6 @@ public:
Ostream &getStrDump() { return *StrDump; }
Ostream &getStrEmit() { return *StrEmit; }
TargetArch getTargetArch() const { return Arch; }
OptLevel getOptLevel() const { return Opt; }
LockedPtr<ErrorCode> getErrorStatus() {
return LockedPtr<ErrorCode>(&ErrorStatus, &ErrorStatusLock);
}
......@@ -178,7 +173,6 @@ public:
// names of translated functions. This makes it easier to create an
// execution test against a reference translator like llc, with both
// translators using the same bitcode as input.
IceString getTestPrefix() const { return TestPrefix; }
IceString mangleName(const IceString &Name) const;
// Manage Constants.
......@@ -419,11 +413,7 @@ private:
ICE_CACHELINE_BOUNDARY;
const VerboseMask VMask;
Intrinsics IntrinsicsInfo;
const TargetArch Arch;
const OptLevel Opt;
const IceString TestPrefix;
const ClFlags &Flags;
RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg.
std::unique_ptr<ELFObjectWriter> ObjectWriter;
......
......@@ -13,24 +13,12 @@
#include <time.h>
#include "llvm/Support/CommandLine.h"
#include "IceRNG.h"
namespace Ice {
namespace {
namespace cl = llvm::cl;
// TODO(stichnot): See if we can easily use LLVM's -rng-seed option
// and implementation. I expect the implementation is different and
// therefore the tests would need to be changed.
cl::opt<unsigned long long>
RandomSeed("sz-seed", cl::desc("Seed the random number generator"),
cl::init(time(0)));
const unsigned MAX = 2147483647;
} // end of anonymous namespace
// TODO(wala,stichnot): Switch to RNG implementation from LLVM or C++11.
......@@ -39,8 +27,8 @@ const unsigned MAX = 2147483647;
// subsequent run, for reproducing a bug. Print the seed in a comment
// in the asm output. Embed the seed in the binary via metadata that an
// attacker can't introspect.
RandomNumberGenerator::RandomNumberGenerator(llvm::StringRef)
: State(RandomSeed) {}
RandomNumberGenerator::RandomNumberGenerator(uint64_t Seed, llvm::StringRef)
: State(Seed) {}
uint64_t RandomNumberGenerator::next(uint64_t Max) {
// Lewis, Goodman, and Miller (1969)
......
......@@ -27,7 +27,7 @@ class RandomNumberGenerator {
RandomNumberGenerator &operator=(const RandomNumberGenerator &) = delete;
public:
explicit RandomNumberGenerator(llvm::StringRef Salt);
explicit RandomNumberGenerator(uint64_t Seed, llvm::StringRef Salt = "");
uint64_t next(uint64_t Max);
private:
......
......@@ -15,8 +15,6 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
#include "assembler_ia32.h"
#include "IceCfg.h" // setError()
#include "IceCfgNode.h"
......@@ -27,27 +25,6 @@
namespace Ice {
namespace {
// TODO(stichnot): Move this machinery into main.cpp.
namespace cl = llvm::cl;
cl::opt<bool> DoNopInsertion("nop-insertion", cl::desc("Randomly insert NOPs"),
cl::init(false));
cl::opt<int> MaxNopsPerInstruction(
"max-nops-per-instruction",
cl::desc("Max number of nops to insert per instruction"), cl::init(1));
cl::opt<int> NopProbabilityAsPercentage(
"nop-insertion-percentage",
cl::desc("Nop insertion probability as percentage"), cl::init(10));
cl::opt<bool>
CLRandomizeRegisterAllocation("randomize-regalloc",
cl::desc("Randomize register allocation"),
cl::init(false));
} // end of anonymous namespace
void LoweringContext::init(CfgNode *N) {
Node = N;
End = getNode()->getInsts().end();
......@@ -102,10 +79,9 @@ TargetLowering *TargetLowering::createLowering(TargetArch Target, Cfg *Func) {
}
TargetLowering::TargetLowering(Cfg *Func)
: Func(Func), Ctx(Func->getContext()),
RandomizeRegisterAllocation(CLRandomizeRegisterAllocation),
HasComputedFrame(false), CallsReturnsTwice(false), StackAdjustment(0),
Context(), SnapshotStackAdjustment(0) {}
: Func(Func), Ctx(Func->getContext()), HasComputedFrame(false),
CallsReturnsTwice(false), StackAdjustment(0), Context(),
SnapshotStackAdjustment(0) {}
std::unique_ptr<Assembler> TargetLowering::createAssembler(TargetArch Target,
Cfg *Func) {
......@@ -126,16 +102,15 @@ void TargetLowering::doAddressOpt() {
Context.advanceNext();
}
bool TargetLowering::shouldDoNopInsertion() const { return DoNopInsertion; }
void TargetLowering::doNopInsertion() {
Inst *I = Context.getCur();
bool ShouldSkip = llvm::isa<InstFakeUse>(I) || llvm::isa<InstFakeDef>(I) ||
llvm::isa<InstFakeKill>(I) || I->isRedundantAssign() ||
I->isDeleted();
if (!ShouldSkip) {
for (int I = 0; I < MaxNopsPerInstruction; ++I) {
randomlyInsertNop(NopProbabilityAsPercentage / 100.0);
int Probability = Ctx->getFlags().getNopProbabilityAsPercentage();
for (int I = 0; I < Ctx->getFlags().getMaxNopsPerInstruction(); ++I) {
randomlyInsertNop(Probability / 100.0);
}
}
}
......@@ -251,14 +226,14 @@ void TargetLowering::regAlloc(RegAllocKind Kind) {
RegExclude |= RegSet_FramePointer;
LinearScan.init(Kind);
llvm::SmallBitVector RegMask = getRegisterSet(RegInclude, RegExclude);
LinearScan.scan(RegMask, RandomizeRegisterAllocation);
LinearScan.scan(RegMask, Ctx->getFlags().shouldRandomizeRegAlloc());
}
std::unique_ptr<TargetDataLowering>
TargetDataLowering::createLowering(GlobalContext *Ctx) {
// These statements can be #ifdef'd to specialize the code generator
// to a subset of the available targets. TODO: use CRTP.
TargetArch Target = Ctx->getTargetArch();
TargetArch Target = Ctx->getFlags().getTargetArch();
if (Target == Target_X8632)
return std::unique_ptr<TargetDataLowering>(TargetDataX8632::create(Ctx));
#if 0
......
......@@ -99,7 +99,7 @@ public:
static std::unique_ptr<Assembler> createAssembler(TargetArch Target,
Cfg *Func);
void translate() {
switch (Ctx->getOptLevel()) {
switch (Ctx->getFlags().getOptLevel()) {
case Opt_m1:
translateOm1();
break;
......@@ -164,7 +164,6 @@ public:
virtual SizeT getFrameOrStackReg() const = 0;
virtual size_t typeWidthInBytesOnStack(Type Ty) const = 0;
bool hasComputedFrame() const { return HasComputedFrame; }
bool shouldDoNopInsertion() const;
// Returns true if this function calls a function that has the
// "returns twice" attribute.
bool callsReturnsTwice() const { return CallsReturnsTwice; }
......@@ -244,7 +243,6 @@ protected:
Cfg *Func;
GlobalContext *Ctx;
const bool RandomizeRegisterAllocation;
bool HasComputedFrame;
bool CallsReturnsTwice;
// StackAdjustment keeps track of the current stack offset from its
......
......@@ -13,7 +13,6 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MathExtras.h"
#include "IceCfg.h"
......@@ -153,16 +152,6 @@ uint32_t applyStackAlignment(uint32_t Value) {
return applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES);
}
// Instruction set options
namespace cl = ::llvm::cl;
cl::opt<TargetX8632::X86InstructionSet> CLInstructionSet(
"mattr", cl::desc("X86 target attributes"), cl::init(TargetX8632::SSE2),
cl::values(clEnumValN(TargetX8632::SSE2, "sse2",
"Enable SSE2 instructions (default)"),
clEnumValN(TargetX8632::SSE4_1, "sse4.1",
"Enable SSE 4.1 instructions"),
clEnumValEnd));
// In some cases, there are x-macros tables for both high-level and
// low-level instructions/operands that use the same enum key value.
// The tables are kept separate to maintain a proper separation
......@@ -272,9 +261,16 @@ ICETYPE_TABLE
} // end of anonymous namespace
TargetX8632::TargetX8632(Cfg *Func)
: TargetLowering(Func), InstructionSet(CLInstructionSet),
: TargetLowering(Func),
InstructionSet(static_cast<X86InstructionSet>(
Func->getContext()->getFlags().getTargetInstructionSet() -
TargetInstructionSet::X86InstructionSet_Begin)),
IsEbpBasedFrame(false), NeedsStackAlignment(false), FrameSizeLocals(0),
SpillAreaSizeBytes(0), NextLabelNumber(0) {
static_assert((X86InstructionSet::End - X86InstructionSet::Begin) ==
(TargetInstructionSet::X86InstructionSet_End -
TargetInstructionSet::X86InstructionSet_Begin),
"X86InstructionSet range different from TargetInstructionSet");
// TODO: Don't initialize IntegerRegisters and friends every time.
// Instead, initialize in some sort of static initializer for the
// class.
......@@ -400,7 +396,7 @@ void TargetX8632::translateO2() {
Func->dump("After branch optimization");
// Nop insertion
if (shouldDoNopInsertion()) {
if (Ctx->getFlags().shouldDoNopInsertion()) {
Func->doNopInsertion();
}
}
......@@ -437,7 +433,7 @@ void TargetX8632::translateOm1() {
Func->dump("After stack frame mapping");
// Nop insertion
if (shouldDoNopInsertion()) {
if (Ctx->getFlags().shouldDoNopInsertion()) {
Func->doNopInsertion();
}
}
......@@ -3230,7 +3226,7 @@ void TargetX8632::lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr,
bool TargetX8632::tryOptimizedCmpxchgCmpBr(Variable *Dest, Operand *PtrToMem,
Operand *Expected,
Operand *Desired) {
if (Ctx->getOptLevel() == Opt_m1)
if (Ctx->getFlags().getOptLevel() == Opt_m1)
return false;
// Peek ahead a few instructions and see how Dest is used.
// It's very common to have:
......@@ -4543,7 +4539,7 @@ Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) {
}
void TargetX8632::postLower() {
if (Ctx->getOptLevel() == Opt_m1)
if (Ctx->getFlags().getOptLevel() == Opt_m1)
return;
// Find two-address non-SSA instructions where Dest==Src0, and set
// the DestNonKillable flag to keep liveness analysis consistent.
......
......@@ -71,9 +71,11 @@ public:
x86::Address stackVarToAsmOperand(const Variable *Var) const;
enum X86InstructionSet {
Begin,
// SSE2 is the PNaCl baseline instruction set.
SSE2,
SSE4_1
SSE2 = Begin,
SSE4_1,
End
};
X86InstructionSet getInstructionSet() const { return InstructionSet; }
......
......@@ -40,6 +40,16 @@ inline Ostream &operator<<(Ostream &Stream, TargetArch Arch) {
return Stream << targetArchString(Arch);
}
// The list of all target instruction sets. Individual targets will
// map this to include only what is valid for the target.
enum TargetInstructionSet {
X86InstructionSet_Begin,
// SSE2 is the PNaCl baseline instruction set.
X86InstructionSet_SSE2 = X86InstructionSet_Begin,
X86InstructionSet_SSE4_1,
X86InstructionSet_End,
};
enum OptLevel { Opt_m1, Opt_0, Opt_1, Opt_2 };
size_t typeWidthInBytes(Type Ty);
......
......@@ -69,6 +69,16 @@ static cl::opt<Ice::TargetArch> TargetArch(
clEnumValN(Ice::Target_ARM32, "arm", "arm32"),
clEnumValN(Ice::Target_ARM32, "arm32", "arm32 (same as arm)"),
clEnumValN(Ice::Target_ARM64, "arm64", "arm64"), clEnumValEnd));
cl::opt<Ice::TargetInstructionSet> InstructionSet(
"mattr", cl::desc("Target architecture attributes"),
cl::init(Ice::X86InstructionSet_SSE2),
cl::values(clEnumValN(Ice::X86InstructionSet_SSE2, "sse2",
"Enable SSE2 instructions (default)"),
clEnumValN(Ice::X86InstructionSet_SSE4_1, "sse4.1",
"Enable SSE 4.1 instructions"),
clEnumValEnd));
static cl::opt<bool> UseSandboxing("sandbox", cl::desc("Use sandboxing"));
static cl::opt<bool>
FunctionSections("ffunction-sections",
......@@ -211,6 +221,30 @@ static cl::opt<uint32_t> NumThreads(
// something related to std::thread::hardware_concurrency().
cl::init(2));
static cl::opt<bool> DoNopInsertion("nop-insertion",
cl::desc("Randomly insert NOPs"),
cl::init(false));
static cl::opt<int> MaxNopsPerInstruction(
"max-nops-per-instruction",
cl::desc("Max number of nops to insert per instruction"), cl::init(1));
static cl::opt<int> NopProbabilityAsPercentage(
"nop-insertion-percentage",
cl::desc("Nop insertion probability as percentage"), cl::init(10));
static cl::opt<bool>
RandomizeRegisterAllocation("randomize-regalloc",
cl::desc("Randomize register allocation"),
cl::init(false));
// TODO(stichnot): See if we can easily use LLVM's -rng-seed option
// and implementation. I expect the implementation is different and
// therefore the tests would need to be changed.
cl::opt<unsigned long long>
RandomSeed("sz-seed", cl::desc("Seed the random number generator"),
cl::init(time(0)));
static int GetReturnValue(int Val) {
if (AlwaysExitSuccess)
return 0;
......@@ -304,14 +338,24 @@ int main(int argc, char **argv) {
Flags.setDumpStats(DumpStats);
Flags.setFunctionSections(FunctionSections);
Flags.setNumTranslationThreads(NumThreads);
Flags.setOptLevel(OptLevel);
Flags.setPhiEdgeSplit(EnablePhiEdgeSplit);
Flags.setRandomSeed(RandomSeed);
Flags.setShouldDoNopInsertion(DoNopInsertion);
Flags.setShouldRandomizeRegAlloc(RandomizeRegisterAllocation);
Flags.setSubzeroTimingEnabled(SubzeroTimingEnabled);
Flags.setTargetArch(TargetArch);
Flags.setTargetInstructionSet(InstructionSet);
Flags.setTestPrefix(TestPrefix);
Flags.setTimeEachFunction(TimeEachFunction);
Flags.setTimingFocusOn(TimingFocusOn);
Flags.setTranslateOnly(TranslateOnly);
Flags.setUseSandboxing(UseSandboxing);
Flags.setVerboseFocusOn(VerboseFocusOn);
Flags.setOutFileType(OutFileType);
Flags.setMaxNopsPerInstruction(MaxNopsPerInstruction);
Flags.setNopProbabilityAsPercentage(NopProbabilityAsPercentage);
Flags.setVerbose(VMask);
// Force -build-on-read=0 for .ll files.
const std::string LLSuffix = ".ll";
......@@ -357,8 +401,7 @@ int main(int argc, char **argv) {
} break;
}
Ice::GlobalContext Ctx(Ls.get(), Os.get(), ELFStr.get(), VMask, TargetArch,
OptLevel, TestPrefix, Flags);
Ice::GlobalContext Ctx(Ls.get(), Os.get(), ELFStr.get(), Flags);
Ice::TimerMarker T(Ice::TimerStack::TT_szmain, &Ctx);
......
......@@ -28,10 +28,11 @@ bool IceTest::SubzeroBitcodeMunger::runTest(const char *TestName,
Ice::ClFlags Flags;
Flags.setAllowErrorRecovery(true);
Flags.setGenerateUnitTestMessages(true);
Flags.setOptLevel(Ice::Opt_m1);
Flags.setOutFileType(Ice::FT_Iasm);
Ice::GlobalContext Ctx(DumpStream, DumpStream, nullptr,
Ice::IceV_Instructions, Ice::Target_X8632, Ice::Opt_m1,
"", Flags);
Flags.setTargetArch(Ice::Target_X8632);
Flags.setVerbose(Ice::IceV_Instructions);
Ice::GlobalContext Ctx(DumpStream, DumpStream, nullptr, Flags);
Ice::PNaClTranslator Translator(&Ctx);
Translator.translateBuffer(TestName, MungedInput.get());
......
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