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
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index 2a1fdb6..e6a9cab 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -32,15 +32,16 @@
}
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");
diff --git a/src/IceClFlags.h b/src/IceClFlags.h
index 6fcbbbb..1133f8c 100644
--- a/src/IceClFlags.h
+++ b/src/IceClFlags.h
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
NumTranslationThreads = NewValue;
}
+ uint64_t getRandomSeed() const { return RandomSeed; }
+ void setRandomSeed(size_t NewValue) { RandomSeed = NewValue; }
+
private:
bool AllowErrorRecovery;
bool AllowUninitializedGlobals;
@@ -149,19 +190,29 @@
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
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index 073163a..9761dde 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -64,7 +64,8 @@
} // 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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<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::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::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 @@
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 @@
// 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 {
diff --git a/src/IceELFObjectWriter.h b/src/IceELFObjectWriter.h
index d27ee9c..1103845 100644
--- a/src/IceELFObjectWriter.h
+++ b/src/IceELFObjectWriter.h
@@ -93,6 +93,7 @@
GlobalContext &Ctx;
ELFStreamer &Str;
bool SectionNumbersAssigned;
+ bool ELF64;
// All created sections, separated into different pools.
typedef std::vector<ELFSection *> SectionList;
@@ -121,7 +122,7 @@
// 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 @@
// 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>
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index af4d358..c710edf 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -162,12 +162,9 @@
}
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 @@
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 @@
// _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 @@
// 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 @@
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 @@
// Transform bar ==> Prefixbar
// ^^^^^^
- return getTestPrefix() + Name;
+ return TestPrefix + Name;
}
GlobalContext::~GlobalContext() {
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index ec821c0..a709981 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -146,12 +146,9 @@
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 @@
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 @@
// 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 @@
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;
diff --git a/src/IceRNG.cpp b/src/IceRNG.cpp
index 03171ad..43c7f07 100644
--- a/src/IceRNG.cpp
+++ b/src/IceRNG.cpp
@@ -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 @@
// 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)
diff --git a/src/IceRNG.h b/src/IceRNG.h
index 174e3e0..bf01e41 100644
--- a/src/IceRNG.h
+++ b/src/IceRNG.h
@@ -27,7 +27,7 @@
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:
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 3ea9e6d..39d27fe 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -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(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 @@
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 @@
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
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 8b4bd27..112572c 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -99,7 +99,7 @@
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 @@
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 @@
Cfg *Func;
GlobalContext *Ctx;
- const bool RandomizeRegisterAllocation;
bool HasComputedFrame;
bool CallsReturnsTwice;
// StackAdjustment keeps track of the current stack offset from its
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 0a41cc8..84333b4 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -13,7 +13,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MathExtras.h"
#include "IceCfg.h"
@@ -153,16 +152,6 @@
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 @@
} // 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 @@
Func->dump("After branch optimization");
// Nop insertion
- if (shouldDoNopInsertion()) {
+ if (Ctx->getFlags().shouldDoNopInsertion()) {
Func->doNopInsertion();
}
}
@@ -437,7 +433,7 @@
Func->dump("After stack frame mapping");
// Nop insertion
- if (shouldDoNopInsertion()) {
+ if (Ctx->getFlags().shouldDoNopInsertion()) {
Func->doNopInsertion();
}
}
@@ -3230,7 +3226,7 @@
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 @@
}
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.
diff --git a/src/IceTargetLoweringX8632.h b/src/IceTargetLoweringX8632.h
index aa16010..74e0d50 100644
--- a/src/IceTargetLoweringX8632.h
+++ b/src/IceTargetLoweringX8632.h
@@ -71,9 +71,11 @@
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; }
diff --git a/src/IceTypes.h b/src/IceTypes.h
index 2cf5e40..297fad3 100644
--- a/src/IceTypes.h
+++ b/src/IceTypes.h
@@ -40,6 +40,16 @@
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);
diff --git a/src/main.cpp b/src/main.cpp
index bd96142..9858fa2 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -69,6 +69,16 @@
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 @@
// 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 @@
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 @@
} 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);
diff --git a/unittest/BitcodeMunge.cpp b/unittest/BitcodeMunge.cpp
index 2b7b918..fd7100c 100644
--- a/unittest/BitcodeMunge.cpp
+++ b/unittest/BitcodeMunge.cpp
@@ -28,10 +28,11 @@
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());