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());