diff options
Diffstat (limited to 'utils')
29 files changed, 396 insertions, 853 deletions
diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index b0ef67a..cd7bb5a 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -85,6 +85,9 @@ public: Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { } + /// getLoc - Return the location in source code. + SMLoc getLoc() const { return PatternLoc; } + /// ParsePattern - Parse the given string into the Pattern. SM provides the /// SourceMgr used for error reports, and LineNumber is the line number in /// the input file from which the pattern string was read. @@ -581,7 +584,7 @@ struct CheckString { /// NotStrings - These are all of the strings that are disallowed from /// occurring between this match string and the previous one (or start of /// file). - std::vector<std::pair<SMLoc, Pattern> > NotStrings; + std::vector<Pattern> NotStrings; CheckString(const Pattern &P, SMLoc L, bool isCheckNext) : Pat(P), Loc(L), IsCheckNext(isCheckNext) {} @@ -604,7 +607,7 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB, continue; } - // If current char is not a horizontal whitespace or if horizontal + // If current char is not a horizontal whitespace or if horizontal // whitespace canonicalization is disabled, dump it to output as is. if (PreserveHorizontal || (*Ptr != ' ' && *Ptr != '\t')) { NewFile.push_back(*Ptr); @@ -649,7 +652,7 @@ static bool ReadCheckFile(SourceMgr &SM, // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); - std::vector<std::pair<SMLoc, Pattern> > NotMatches; + std::vector<Pattern> NotMatches; // LineNumber keeps track of the line on which CheckPrefix instances are // found. @@ -716,8 +719,7 @@ static bool ReadCheckFile(SourceMgr &SM, // Handle CHECK-NOT. if (IsCheckNot) { - NotMatches.push_back(std::make_pair(SMLoc::getFromPointer(Buffer.data()), - P)); + NotMatches.push_back(P); continue; } @@ -877,14 +879,13 @@ int main(int argc, char **argv) { for (unsigned ChunkNo = 0, e = CheckStr.NotStrings.size(); ChunkNo != e; ++ChunkNo) { size_t MatchLen = 0; - size_t Pos = CheckStr.NotStrings[ChunkNo].second.Match(SkippedRegion, - MatchLen, - VariableTable); + size_t Pos = CheckStr.NotStrings[ChunkNo].Match(SkippedRegion, MatchLen, + VariableTable); if (Pos == StringRef::npos) continue; SM.PrintMessage(SMLoc::getFromPointer(LastMatch+Pos), SourceMgr::DK_Error, CheckPrefix+"-NOT: string occurred!"); - SM.PrintMessage(CheckStr.NotStrings[ChunkNo].first, SourceMgr::DK_Note, + SM.PrintMessage(CheckStr.NotStrings[ChunkNo].getLoc(), SourceMgr::DK_Note, CheckPrefix+"-NOT: pattern specified here"); return 1; } diff --git a/utils/Makefile b/utils/Makefile index 7a3c17d..ecb30be 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -9,7 +9,7 @@ LEVEL = .. PARALLEL_DIRS := FileCheck FileUpdate TableGen PerfectShuffle \ - count fpcmp llvm-lit not unittest yaml2obj + count fpcmp llvm-lit not unittest EXTRA_DIST := check-each-file codegen-diff countloc.sh \ DSAclean.py DSAextract.py emacs findsym.pl GenLibDeps.pl \ diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 6faf819..218af21 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -1322,27 +1322,6 @@ void AsmMatcherInfo::buildInfo() { if (CGI.TheDef->getValueAsBit("isCodeGenOnly")) continue; - // Validate the operand list to ensure we can handle this instruction. - for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) { - const CGIOperandList::OperandInfo &OI = CGI.Operands[i]; - - // Validate tied operands. - if (OI.getTiedRegister() != -1) { - // If we have a tied operand that consists of multiple MCOperands, - // reject it. We reject aliases and ignore instructions for now. - if (OI.MINumOperands != 1) { - // FIXME: Should reject these. The ARM backend hits this with $lane - // in a bunch of instructions. The right answer is unclear. - DEBUG({ - errs() << "warning: '" << CGI.TheDef->getName() << "': " - << "ignoring instruction with multi-operand tied operand '" - << OI.Name << "'\n"; - }); - continue; - } - } - } - OwningPtr<MatchableInfo> II(new MatchableInfo(CGI)); II->initialize(*this, SingletonRegisters, AsmVariantNo, RegisterPrefix); @@ -1529,7 +1508,9 @@ buildInstructionOperandReference(MatchableInfo *II, // we want to canonicalize to: // "inc $dst" // so that we know how to provide the $dst operand when filling in the result. - int OITied = Operands[Idx].getTiedRegister(); + int OITied = -1; + if (Operands[Idx].MINumOperands == 1) + OITied = Operands[Idx].getTiedRegister(); if (OITied != -1) { // The tied operand index is an MIOperand index, find the operand that // contains it. @@ -1578,7 +1559,9 @@ void MatchableInfo::buildInstructionResultOperands() { const CGIOperandList::OperandInfo &OpInfo = ResultInst->Operands[i]; // If this is a tied operand, just copy from the previously handled operand. - int TiedOp = OpInfo.getTiedRegister(); + int TiedOp = -1; + if (OpInfo.MINumOperands == 1) + TiedOp = OpInfo.getTiedRegister(); if (TiedOp != -1) { ResOperands.push_back(ResOperand::getTiedOp(TiedOp)); continue; @@ -1586,10 +1569,15 @@ void MatchableInfo::buildInstructionResultOperands() { // Find out what operand from the asmparser this MCInst operand comes from. int SrcOperand = findAsmOperandNamed(OpInfo.Name); - if (OpInfo.Name.empty() || SrcOperand == -1) - PrintFatalError(TheDef->getLoc(), "Instruction '" + - TheDef->getName() + "' has operand '" + OpInfo.Name + - "' that doesn't appear in asm string!"); + if (OpInfo.Name.empty() || SrcOperand == -1) { + // This may happen for operands that are tied to a suboperand of a + // complex operand. Simply use a dummy value here; nobody should + // use this operand slot. + // FIXME: The long term goal is for the MCOperand list to not contain + // tied operands at all. + ResOperands.push_back(ResOperand::getImmOp(0)); + continue; + } // Check if the one AsmOperand populates the entire operand. unsigned NumOperands = OpInfo.MINumOperands; @@ -1620,7 +1608,9 @@ void MatchableInfo::buildAliasResultOperands() { const CGIOperandList::OperandInfo *OpInfo = &ResultInst->Operands[i]; // If this is a tied operand, just copy from the previously handled operand. - int TiedOp = OpInfo->getTiedRegister(); + int TiedOp = -1; + if (OpInfo->MINumOperands == 1) + TiedOp = OpInfo->getTiedRegister(); if (TiedOp != -1) { ResOperands.push_back(ResOperand::getTiedOp(TiedOp)); continue; @@ -1843,13 +1833,12 @@ static void emitConvertFuncs(CodeGenTarget &Target, StringRef ClassName, case MatchableInfo::ResOperand::TiedOperand: { // If this operand is tied to a previous one, just copy the MCInst // operand from the earlier one.We can only tie single MCOperand values. - //assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand"); + assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand"); unsigned TiedOp = OpInfo.TiedOperandNum; assert(i > TiedOp && "Tied operand precedes its target!"); Signature += "__Tie" + utostr(TiedOp); ConversionRow.push_back(CVT_Tied); ConversionRow.push_back(TiedOp); - // FIXME: Handle the operand number lookup for tied operands. break; } case MatchableInfo::ResOperand::ImmOperand: { @@ -2296,29 +2285,25 @@ static std::string GetAliasRequiredFeatures(Record *R, return Result; } -/// emitMnemonicAliases - If the target has any MnemonicAlias<> definitions, -/// emit a function for them and return true, otherwise return false. -static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) { - // Ignore aliases when match-prefix is set. - if (!MatchPrefix.empty()) - return false; - - std::vector<Record*> Aliases = - Info.getRecords().getAllDerivedDefinitions("MnemonicAlias"); - if (Aliases.empty()) return false; - - OS << "static void applyMnemonicAliases(StringRef &Mnemonic, " - "unsigned Features) {\n"; - +static void emitMnemonicAliasVariant(raw_ostream &OS,const AsmMatcherInfo &Info, + std::vector<Record*> &Aliases, + unsigned Indent = 0, + StringRef AsmParserVariantName = StringRef()){ // Keep track of all the aliases from a mnemonic. Use an std::map so that the // iteration order of the map is stable. std::map<std::string, std::vector<Record*> > AliasesFromMnemonic; for (unsigned i = 0, e = Aliases.size(); i != e; ++i) { Record *R = Aliases[i]; + // FIXME: Allow AssemblerVariantName to be a comma separated list. + std::string AsmVariantName = R->getValueAsString("AsmVariantName"); + if (AsmVariantName != AsmParserVariantName) + continue; AliasesFromMnemonic[R->getValueAsString("FromMnemonic")].push_back(R); } - + if (AliasesFromMnemonic.empty()) + return; + // Process each alias a "from" mnemonic at a time, building the code executed // by the string remapper. std::vector<StringMatcher::StringPair> Cases; @@ -2370,8 +2355,39 @@ static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) { Cases.push_back(std::make_pair(I->first, MatchCode)); } + StringMatcher("Mnemonic", Cases, OS).Emit(Indent); +} + +/// emitMnemonicAliases - If the target has any MnemonicAlias<> definitions, +/// emit a function for them and return true, otherwise return false. +static bool emitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info, + CodeGenTarget &Target) { + // Ignore aliases when match-prefix is set. + if (!MatchPrefix.empty()) + return false; + + std::vector<Record*> Aliases = + Info.getRecords().getAllDerivedDefinitions("MnemonicAlias"); + if (Aliases.empty()) return false; + + OS << "static void applyMnemonicAliases(StringRef &Mnemonic, " + "unsigned Features, unsigned VariantID) {\n"; + OS << " switch (VariantID) {\n"; + unsigned VariantCount = Target.getAsmParserVariantCount(); + for (unsigned VC = 0; VC != VariantCount; ++VC) { + Record *AsmVariant = Target.getAsmParserVariant(VC); + int AsmParserVariantNo = AsmVariant->getValueAsInt("Variant"); + std::string AsmParserVariantName = AsmVariant->getValueAsString("Name"); + OS << " case " << AsmParserVariantNo << ":\n"; + emitMnemonicAliasVariant(OS, Info, Aliases, /*Indent=*/2, + AsmParserVariantName); + OS << " break;\n"; + } + OS << " }\n"; + + // Emit aliases that apply to all variants. + emitMnemonicAliasVariant(OS, Info, Aliases); - StringMatcher("Mnemonic", Cases, OS).Emit(); OS << "}\n\n"; return true; @@ -2674,7 +2690,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n"; // Generate the function that remaps for mnemonic aliases. - bool HasMnemonicAliases = emitMnemonicAliases(OS, Info); + bool HasMnemonicAliases = emitMnemonicAliases(OS, Info, Target); // Generate the convertToMCInst function to convert operands into an MCInst. // Also, generate the convertToMapAndConstraints function for MS-style inline @@ -2832,9 +2848,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (HasMnemonicAliases) { OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; - OS << " // FIXME : Add an entry in AsmParserVariant to check this.\n"; - OS << " if (!VariantID)\n"; - OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n"; + OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures, VariantID);\n\n"; } // Emit code to compute the class list for this operand vector. diff --git a/utils/TableGen/CodeGenSchedule.cpp b/utils/TableGen/CodeGenSchedule.cpp index c02f084..112ff65 100644 --- a/utils/TableGen/CodeGenSchedule.cpp +++ b/utils/TableGen/CodeGenSchedule.cpp @@ -1367,6 +1367,56 @@ void CodeGenSchedModels::inferFromRW(const IdxVec &OperWrites, inferFromTransitions(LastTransitions, FromClassIdx, *this); } +// Check if any processor resource group contains all resource records in +// SubUnits. +bool CodeGenSchedModels::hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM) { + for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) { + if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup")) + continue; + RecVec SuperUnits = + PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources"); + RecIter RI = SubUnits.begin(), RE = SubUnits.end(); + for ( ; RI != RE; ++RI) { + if (std::find(SuperUnits.begin(), SuperUnits.end(), *RI) + == SuperUnits.end()) { + break; + } + } + if (RI == RE) + return true; + } + return false; +} + +// Verify that overlapping groups have a common supergroup. +void CodeGenSchedModels::verifyProcResourceGroups(CodeGenProcModel &PM) { + for (unsigned i = 0, e = PM.ProcResourceDefs.size(); i < e; ++i) { + if (!PM.ProcResourceDefs[i]->isSubClassOf("ProcResGroup")) + continue; + RecVec CheckUnits = + PM.ProcResourceDefs[i]->getValueAsListOfDefs("Resources"); + for (unsigned j = i+1; j < e; ++j) { + if (!PM.ProcResourceDefs[j]->isSubClassOf("ProcResGroup")) + continue; + RecVec OtherUnits = + PM.ProcResourceDefs[j]->getValueAsListOfDefs("Resources"); + if (std::find_first_of(CheckUnits.begin(), CheckUnits.end(), + OtherUnits.begin(), OtherUnits.end()) + != CheckUnits.end()) { + // CheckUnits and OtherUnits overlap + OtherUnits.insert(OtherUnits.end(), CheckUnits.begin(), + CheckUnits.end()); + if (!hasSuperGroup(OtherUnits, PM)) { + PrintFatalError((PM.ProcResourceDefs[i])->getLoc(), + "proc resource group overlaps with " + + PM.ProcResourceDefs[j]->getName() + + " but no supergroup contains both."); + } + } + } + } +} + // Collect and sort WriteRes, ReadAdvance, and ProcResources. void CodeGenSchedModels::collectProcResources() { // Add any subtarget-specific SchedReadWrites that are directly associated @@ -1437,6 +1487,7 @@ void CodeGenSchedModels::collectProcResources() { dbgs() << (*RI)->getName() << " "; } dbgs() << '\n'); + verifyProcResourceGroups(PM); } } diff --git a/utils/TableGen/CodeGenSchedule.h b/utils/TableGen/CodeGenSchedule.h index e5b9118..2e0a149 100644 --- a/utils/TableGen/CodeGenSchedule.h +++ b/utils/TableGen/CodeGenSchedule.h @@ -380,6 +380,9 @@ private: void inferFromItinClass(Record *ItinClassDef, unsigned FromClassIdx); void inferFromInstRWs(unsigned SCIdx); + bool hasSuperGroup(RecVec &SubUnits, CodeGenProcModel &PM); + void verifyProcResourceGroups(CodeGenProcModel &PM); + void collectProcResources(); void collectItinProcResources(Record *ItinClassDef); diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index 98892e1..4918b1b 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -782,41 +782,46 @@ Record *SubtargetEmitter::FindReadAdvance(const CodeGenSchedRW &SchedRead, } // Expand an explicit list of processor resources into a full list of implied -// resource groups that cover them. -// -// FIXME: Effectively consider a super-resource a group that include all of its -// subresources to allow mixing and matching super-resources and groups. -// -// FIXME: Warn if two overlapping groups don't have a common supergroup. +// resource groups and super resources that cover them. void SubtargetEmitter::ExpandProcResources(RecVec &PRVec, std::vector<int64_t> &Cycles, - const CodeGenProcModel &ProcModel) { + const CodeGenProcModel &PM) { // Default to 1 resource cycle. Cycles.resize(PRVec.size(), 1); for (unsigned i = 0, e = PRVec.size(); i != e; ++i) { + Record *PRDef = PRVec[i]; RecVec SubResources; - if (PRVec[i]->isSubClassOf("ProcResGroup")) { - SubResources = PRVec[i]->getValueAsListOfDefs("Resources"); - std::sort(SubResources.begin(), SubResources.end(), LessRecord()); - } + if (PRDef->isSubClassOf("ProcResGroup")) + SubResources = PRDef->getValueAsListOfDefs("Resources"); else { - SubResources.push_back(PRVec[i]); + SubResources.push_back(PRDef); + PRDef = SchedModels.findProcResUnits(PRVec[i], PM); + for (Record *SubDef = PRDef; + SubDef->getValueInit("Super")->isComplete();) { + if (SubDef->isSubClassOf("ProcResGroup")) { + // Disallow this for simplicitly. + PrintFatalError(SubDef->getLoc(), "Processor resource group " + " cannot be a super resources."); + } + Record *SuperDef = + SchedModels.findProcResUnits(SubDef->getValueAsDef("Super"), PM); + PRVec.push_back(SuperDef); + Cycles.push_back(Cycles[i]); + SubDef = SuperDef; + } } - for (RecIter PRI = ProcModel.ProcResourceDefs.begin(), - PRE = ProcModel.ProcResourceDefs.end(); + for (RecIter PRI = PM.ProcResourceDefs.begin(), + PRE = PM.ProcResourceDefs.end(); PRI != PRE; ++PRI) { - if (*PRI == PRVec[i] || !(*PRI)->isSubClassOf("ProcResGroup")) + if (*PRI == PRDef || !(*PRI)->isSubClassOf("ProcResGroup")) continue; RecVec SuperResources = (*PRI)->getValueAsListOfDefs("Resources"); - std::sort(SuperResources.begin(), SuperResources.end(), LessRecord()); RecIter SubI = SubResources.begin(), SubE = SubResources.end(); - RecIter SuperI = SuperResources.begin(), SuperE = SuperResources.end(); - for ( ; SubI != SubE && SuperI != SuperE; ++SuperI) { - if (*SubI < *SuperI) + for( ; SubI != SubE; ++SubI) { + if (std::find(SuperResources.begin(), SuperResources.end(), *SubI) + == SuperResources.end()) { break; - else if (*SuperI < *SubI) - continue; - ++SubI; + } } if (SubI == SubE) { PRVec.push_back(*PRI); diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 61b9813..46f2052 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -29,23 +29,25 @@ using namespace llvm; MAP(C4, 36) \ MAP(C8, 37) \ MAP(C9, 38) \ - MAP(E8, 39) \ - MAP(F0, 40) \ - MAP(F8, 41) \ - MAP(F9, 42) \ - MAP(D0, 45) \ - MAP(D1, 46) \ - MAP(D4, 47) \ - MAP(D5, 48) \ - MAP(D6, 49) \ - MAP(D8, 50) \ - MAP(D9, 51) \ - MAP(DA, 52) \ - MAP(DB, 53) \ - MAP(DC, 54) \ - MAP(DD, 55) \ - MAP(DE, 56) \ - MAP(DF, 57) + MAP(CA, 39) \ + MAP(CB, 40) \ + MAP(E8, 41) \ + MAP(F0, 42) \ + MAP(F8, 45) \ + MAP(F9, 46) \ + MAP(D0, 47) \ + MAP(D1, 48) \ + MAP(D4, 49) \ + MAP(D5, 50) \ + MAP(D6, 51) \ + MAP(D8, 52) \ + MAP(D9, 53) \ + MAP(DA, 54) \ + MAP(DB, 55) \ + MAP(DC, 56) \ + MAP(DD, 57) \ + MAP(DE, 58) \ + MAP(DF, 59) // A clone of X86 since we can't depend on something that is generated. namespace X86Local { diff --git a/utils/git-svn/git-svnrevert b/utils/git-svn/git-svnrevert new file mode 100755 index 0000000..06a9c44 --- /dev/null +++ b/utils/git-svn/git-svnrevert @@ -0,0 +1,52 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "Invalid arguments!" + echo "$0 <commit to revert>" + exit 1 +fi + +if [ -n "$(git status -uno -s --porcelain)" ]; then + echo "You have unstashed changes. Please stash and then revert." + git status -uno + exit 1 +fi + +COMMIT=$1 + +SVN_REVISION=$(git svn find-rev "$COMMIT") +if [ $? -ne 0 ]; then + echo "Error! Could not find an svn revision for commit $COMMIT!" + exit 1 +fi + +# Grab the one line message for our revert commit message. +ONE_LINE_MSG=$(git log --oneline $COMMIT -1 | cut -f2- -d " ") + +# Revert the commit. +git revert --no-commit $COMMIT 2>/dev/null +if [ $? -ne 0 ]; then + echo "Error! Failed to revert commit $COMMIT. Resetting to head." + git reset --hard HEAD + exit 1 +fi + +# Create a template in our .git directory. +TEMPLATE="`git rev-parse --git-dir`/git-svn-revert-template" +cat > $TEMPLATE <<EOF +Revert "$ONE_LINE_MSG" + +This reverts commit r$SVN_REVISION. +EOF + +# Begin the commit but give our user an opportunity to edit it. +git commit --file="$TEMPLATE" --edit +if [ $? -ne 0 ]; then + echo "Error! Failed to commit reverting commit for commit $COMMIT. Reverting to head." + git reset --hard HEAD + rm -rf $TEMPLATE + exit 1 +fi + +rm -rf $TEMPLATE + diff --git a/utils/git-svn/git-svnup b/utils/git-svn/git-svnup new file mode 100755 index 0000000..3321f6b --- /dev/null +++ b/utils/git-svn/git-svnup @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ -n "`git status -uno -s --porcelain`" ]; then + echo "You have unstashed changes. Can not update repository..." + git status -uno + exit 1 +fi + +git fetch +OLD_BRANCH=$(git rev-parse --abbrev-ref HEAD) +git checkout master 2> /dev/null +git svn rebase -l +git checkout $OLD_BRANCH 2> /dev/null + +exit 0 diff --git a/utils/lit/lit/discovery.py b/utils/lit/lit/discovery.py index c869a67..64a9510 100644 --- a/utils/lit/lit/discovery.py +++ b/utils/lit/lit/discovery.py @@ -137,7 +137,7 @@ def getTestsInSuite(ts, path_in_suite, litConfig, # Search subdirectories. for filename in os.listdir(source_path): # FIXME: This doesn't belong here? - if filename in ('Output', '.svn') or filename in lc.excludes: + if filename in ('Output', '.svn', '.git') or filename in lc.excludes: continue # Ignore non-directories. @@ -147,20 +147,31 @@ def getTestsInSuite(ts, path_in_suite, litConfig, # Check for nested test suites, first in the execpath in case there is a # site configuration and then in the source path. - file_execpath = ts.getExecPath(path_in_suite + (filename,)) + subpath = path_in_suite + (filename,) + file_execpath = ts.getExecPath(subpath) if dirContainsTestSuite(file_execpath, litConfig): - sub_ts, subiter = getTests(file_execpath, litConfig, - testSuiteCache, localConfigCache) + sub_ts, subpath_in_suite = getTestSuite(file_execpath, litConfig, + testSuiteCache) elif dirContainsTestSuite(file_sourcepath, litConfig): - sub_ts, subiter = getTests(file_sourcepath, litConfig, - testSuiteCache, localConfigCache) + sub_ts, subpath_in_suite = getTestSuite(file_sourcepath, litConfig, + testSuiteCache) else: - # Otherwise, continue loading from inside this test suite. - subiter = getTestsInSuite(ts, path_in_suite + (filename,), - litConfig, testSuiteCache, - localConfigCache) sub_ts = None + # If the this directory recursively maps back to the current test suite, + # disregard it (this can happen if the exec root is located inside the + # current test suite, for example). + if sub_ts is ts: + continue + + # Otherwise, load from the nested test suite, if present. + if sub_ts is not None: + subiter = getTestsInSuite(sub_ts, subpath_in_suite, litConfig, + testSuiteCache, localConfigCache) + else: + subiter = getTestsInSuite(ts, subpath, litConfig, testSuiteCache, + localConfigCache) + N = 0 for res in subiter: N += 1 diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index da961ee..de97a8e 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -219,7 +219,7 @@ def main(builtinParameters = {}): group.add_option("", "--shuffle", dest="shuffle", help="Run tests in random order", action="store_true", default=False) - group.add_option("", "--filter", dest="filter", metavar="EXPRESSION", + group.add_option("", "--filter", dest="filter", metavar="REGEX", help=("Only run tests with paths matching the given " "regular expression"), action="store", default=None) diff --git a/utils/lit/tests/Inputs/discovery/lit.cfg b/utils/lit/tests/Inputs/discovery/lit.cfg index 3513bff..4049ab1 100644 --- a/utils/lit/tests/Inputs/discovery/lit.cfg +++ b/utils/lit/tests/Inputs/discovery/lit.cfg @@ -1,5 +1,10 @@ config.name = 'top-level-suite' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() -config.test_source_root = None -config.test_exec_root = None + +# We intentionally don't set the source root or exec root directories here, +# because this suite gets reused for testing the exec root behavior (in +# ../exec-discovery). +# +#config.test_source_root = None +#config.test_exec_root = None diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg b/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg new file mode 100644 index 0000000..342b2fd --- /dev/null +++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.cfg @@ -0,0 +1,7 @@ +# Verify that the site configuration was loaded. +if config.test_source_root is None or config.test_exec_root is None: + lit.fatal("No site specific configuration") + +config.name = 'exec-discovery-in-tree-suite' +config.suffixes = ['.txt'] +config.test_format = lit.formats.ShTest() diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg b/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg new file mode 100644 index 0000000..de9a3d0c --- /dev/null +++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg @@ -0,0 +1,4 @@ +import os +config.test_exec_root = os.path.dirname(__file__) +config.test_source_root = os.path.dirname(config.test_exec_root) +lit.load_config(config, os.path.join(config.test_source_root, "lit.cfg"))
\ No newline at end of file diff --git a/utils/lit/tests/Inputs/exec-discovery-in-tree/test-one.txt b/utils/lit/tests/Inputs/exec-discovery-in-tree/test-one.txt new file mode 100644 index 0000000..b80b60b --- /dev/null +++ b/utils/lit/tests/Inputs/exec-discovery-in-tree/test-one.txt @@ -0,0 +1 @@ +# RUN: true diff --git a/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg b/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg new file mode 100644 index 0000000..796569a --- /dev/null +++ b/utils/lit/tests/Inputs/exec-discovery/lit.site.cfg @@ -0,0 +1,5 @@ +# Load the discovery suite, but with a separate exec root. +import os +config.test_exec_root = os.path.dirname(__file__) +config.test_source_root = os.path.join(os.path.dirname(config.test_exec_root), "discovery") +lit.load_config(config, os.path.join(config.test_source_root, "lit.cfg")) diff --git a/utils/lit/tests/Inputs/progress-bar/lit.cfg b/utils/lit/tests/Inputs/progress-bar/lit.cfg new file mode 100644 index 0000000..4878b65 --- /dev/null +++ b/utils/lit/tests/Inputs/progress-bar/lit.cfg @@ -0,0 +1,5 @@ +config.name = 'shtest-shell' +config.suffixes = ['.txt'] +config.test_format = lit.formats.ShTest() +config.test_source_root = None +config.test_exec_root = None diff --git a/utils/lit/tests/Inputs/progress-bar/test-1.txt b/utils/lit/tests/Inputs/progress-bar/test-1.txt new file mode 100644 index 0000000..49932c3 --- /dev/null +++ b/utils/lit/tests/Inputs/progress-bar/test-1.txt @@ -0,0 +1 @@ +# RUN: false diff --git a/utils/lit/tests/Inputs/progress-bar/test-2.txt b/utils/lit/tests/Inputs/progress-bar/test-2.txt new file mode 100644 index 0000000..49932c3 --- /dev/null +++ b/utils/lit/tests/Inputs/progress-bar/test-2.txt @@ -0,0 +1 @@ +# RUN: false diff --git a/utils/lit/tests/Inputs/progress-bar/test-3.txt b/utils/lit/tests/Inputs/progress-bar/test-3.txt new file mode 100644 index 0000000..49932c3 --- /dev/null +++ b/utils/lit/tests/Inputs/progress-bar/test-3.txt @@ -0,0 +1 @@ +# RUN: false diff --git a/utils/lit/tests/Inputs/progress-bar/test-4.txt b/utils/lit/tests/Inputs/progress-bar/test-4.txt new file mode 100644 index 0000000..49932c3 --- /dev/null +++ b/utils/lit/tests/Inputs/progress-bar/test-4.txt @@ -0,0 +1 @@ +# RUN: false diff --git a/utils/lit/tests/discovery.py b/utils/lit/tests/discovery.py index 54b99d3..56d9dd0 100644 --- a/utils/lit/tests/discovery.py +++ b/utils/lit/tests/discovery.py @@ -5,17 +5,17 @@ # RUN: FileCheck --check-prefix=CHECK-BASIC-OUT < %t.out %s # RUN: FileCheck --check-prefix=CHECK-BASIC-ERR < %t.err %s # -# CHECK-BASIC-ERR: loading suite config '{{.*}}/tests/Inputs/discovery/lit.cfg' -# CHECK-BASIC-ERR: loading local config '{{.*}}/tests/Inputs/discovery/subdir/lit.local.cfg' -# CHECK-BASIC-ERR: loading suite config '{{.*}}/tests/Inputs/discovery/subsuite/lit.cfg' +# CHECK-BASIC-ERR: loading suite config '{{.*}}/discovery/lit.cfg' +# CHECK-BASIC-ERR: loading local config '{{.*}}/discovery/subdir/lit.local.cfg' +# CHECK-BASIC-ERR: loading suite config '{{.*}}/discovery/subsuite/lit.cfg' # # CHECK-BASIC-OUT: -- Test Suites -- # CHECK-BASIC-OUT: sub-suite - 2 tests -# CHECK-BASIC-OUT: Source Root: -# CHECK-BASIC-OUT: Exec Root : +# CHECK-BASIC-OUT: Source Root: {{.*/discovery/subsuite$}} +# CHECK-BASIC-OUT: Exec Root : {{.*/discovery/subsuite$}} # CHECK-BASIC-OUT: top-level-suite - 3 tests -# CHECK-BASIC-OUT: Source Root: -# CHECK-BASIC-OUT: Exec Root : +# CHECK-BASIC-OUT: Source Root: {{.*/discovery$}} +# CHECK-BASIC-OUT: Exec Root : {{.*/discovery$}} # # CHECK-BASIC-OUT: -- Testing: 5 tests, 1 threads -- # CHECK-BASIC-OUT: PASS: sub-suite :: test-one @@ -23,3 +23,74 @@ # CHECK-BASIC-OUT: PASS: top-level-suite :: subdir/test-three # CHECK-BASIC-OUT: PASS: top-level-suite :: test-one # CHECK-BASIC-OUT: PASS: top-level-suite :: test-two + + +# Check discovery when exact test names are given. +# +# RUN: %{lit} \ +# RUN: %{inputs}/discovery/subdir/test-three.py \ +# RUN: %{inputs}/discovery/subsuite/test-one.txt \ +# RUN: -j 1 --no-execute --show-suites -v > %t.out +# RUN: FileCheck --check-prefix=CHECK-EXACT-TEST < %t.out %s +# +# CHECK-EXACT-TEST: -- Testing: 2 tests, 1 threads -- +# CHECK-EXACT-TEST: PASS: sub-suite :: test-one +# CHECK-EXACT-TEST: PASS: top-level-suite :: subdir/test-three + + +# Check discovery when using an exec path. +# +# RUN: %{lit} %{inputs}/exec-discovery \ +# RUN: -j 1 --debug --no-execute --show-suites -v > %t.out 2> %t.err +# RUN: FileCheck --check-prefix=CHECK-ASEXEC-OUT < %t.out %s +# RUN: FileCheck --check-prefix=CHECK-ASEXEC-ERR < %t.err %s +# +# CHECK-ASEXEC-ERR: loading suite config '{{.*}}/exec-discovery/lit.site.cfg' +# CHECK-ASEXEC-ERR: load_config from '{{.*}}/discovery/lit.cfg' +# CHECK-ASEXEC-ERR: loaded config '{{.*}}/discovery/lit.cfg' +# CHECK-ASEXEC-ERR: loaded config '{{.*}}/exec-discovery/lit.site.cfg' +# CHECK-ASEXEC-ERR: loading local config '{{.*}}/discovery/subdir/lit.local.cfg' +# CHECK-ASEXEC-ERR: loading suite config '{{.*}}/discovery/subsuite/lit.cfg' +# +# CHECK-ASEXEC-OUT: -- Test Suites -- +# CHECK-ASEXEC-OUT: sub-suite - 2 tests +# CHECK-ASEXEC-OUT: Source Root: {{.*/discovery/subsuite$}} +# CHECK-ASEXEC-OUT: Exec Root : {{.*/discovery/subsuite$}} +# CHECK-ASEXEC-OUT: top-level-suite - 3 tests +# CHECK-ASEXEC-OUT: Source Root: {{.*/discovery$}} +# CHECK-ASEXEC-OUT: Exec Root : {{.*/exec-discovery$}} +# +# CHECK-ASEXEC-OUT: -- Testing: 5 tests, 1 threads -- +# CHECK-ASEXEC-OUT: PASS: sub-suite :: test-one +# CHECK-ASEXEC-OUT: PASS: sub-suite :: test-two +# CHECK-ASEXEC-OUT: PASS: top-level-suite :: subdir/test-three +# CHECK-ASEXEC-OUT: PASS: top-level-suite :: test-one +# CHECK-ASEXEC-OUT: PASS: top-level-suite :: test-two + + +# Check discovery when exact test names are given. +# +# FIXME: Note that using a path into a subsuite doesn't work correctly here. +# +# RUN: %{lit} \ +# RUN: %{inputs}/exec-discovery/subdir/test-three.py \ +# RUN: -j 1 --no-execute --show-suites -v > %t.out +# RUN: FileCheck --check-prefix=CHECK-ASEXEC-EXACT-TEST < %t.out %s +# +# CHECK-ASEXEC-EXACT-TEST: -- Testing: 1 tests, 1 threads -- +# CHECK-ASEXEC-EXACT-TEST: PASS: top-level-suite :: subdir/test-three + + +# Check that we don't recurse infinitely when loading an site specific test +# suite located inside the test source root. +# +# RUN: %{lit} \ +# RUN: %{inputs}/exec-discovery-in-tree/obj/ \ +# RUN: -j 1 --no-execute --show-suites -v > %t.out +# RUN: FileCheck --check-prefix=CHECK-ASEXEC-INTREE < %t.out %s +# +# CHECK-ASEXEC-INTREE: exec-discovery-in-tree-suite - 1 tests +# CHECK-ASEXEC-INTREE-NEXT: Source Root: {{.*/exec-discovery-in-tree$}} +# CHECK-ASEXEC-INTREE-NEXT: Exec Root : {{.*/exec-discovery-in-tree/obj$}} +# CHECK-ASEXEC-INTREE-NEXT: -- Testing: 1 tests, 1 threads -- +# CHECK-ASEXEC-INTREE-NEXT: PASS: exec-discovery-in-tree-suite :: test-one diff --git a/utils/lit/tests/progress-bar.py b/utils/lit/tests/progress-bar.py new file mode 100644 index 0000000..d046748 --- /dev/null +++ b/utils/lit/tests/progress-bar.py @@ -0,0 +1,13 @@ +# Check the simple progress bar. +# +# RUN: not %{lit} -j 1 -s %{inputs}/progress-bar > %t.out +# RUN: FileCheck < %t.out %s +# +# CHECK: Testing: 0 .. 10.. 20 +# CHECK: FAIL: shtest-shell :: test-1.txt (1 of 4) +# CHECK: Testing: 0 .. 10.. 20.. 30.. 40.. +# CHECK: FAIL: shtest-shell :: test-2.txt (2 of 4) +# CHECK: Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70 +# CHECK: FAIL: shtest-shell :: test-3.txt (3 of 4) +# CHECK: Testing: 0 .. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. +# CHECK: FAIL: shtest-shell :: test-4.txt (4 of 4) diff --git a/utils/release/tag.sh b/utils/release/tag.sh index 399d5c5..c327174 100755 --- a/utils/release/tag.sh +++ b/utils/release/tag.sh @@ -32,7 +32,7 @@ function usage() { function tag_version() { set -x - for proj in llvm cfe dragonegg test-suite compiler-rt ; do + for proj in llvm cfe dragonegg test-suite compiler-rt libcxx clang-tools-extra ; do if svn ls $base_url/$proj/branches/release_$release > /dev/null 2>&1 ; then if [ $rebranch = "no" ]; then continue @@ -49,7 +49,7 @@ function tag_version() { function tag_release_candidate() { set -x - for proj in llvm cfe dragonegg test-suite compiler-rt ; do + for proj in llvm cfe dragonegg test-suite compiler-rt libcxx clang-tools-extra ; do if ! svn ls $base_url/$proj/tags/RELEASE_$release > /dev/null 2>&1 ; then svn mkdir -m "Creating release directory for release_$release." $base_url/$proj/tags/RELEASE_$release fi diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index a62e829..86200fd 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -35,7 +35,7 @@ do_objc="yes" do_64bit="yes" do_debug="no" do_asserts="no" -do_compare="yes" +do_compare="no" BuildDir="`pwd`" function usage() { diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp index ce32b73..5387512 100644 --- a/utils/unittest/UnitTestMain/TestMain.cpp +++ b/utils/unittest/UnitTestMain/TestMain.cpp @@ -20,11 +20,16 @@ # endif #endif +const char *TestMainArgv0; + int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); testing::InitGoogleTest(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv); + // Make it easy for a test to re-execute itself by saving argv[0]. + TestMainArgv0 = argv[0]; + # if defined(LLVM_ON_WIN32) // Disable all of the possible ways Windows conspires to make automated // testing impossible. diff --git a/utils/yaml2obj/CMakeLists.txt b/utils/yaml2obj/CMakeLists.txt deleted file mode 100644 index f8b1197..0000000 --- a/utils/yaml2obj/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_llvm_utility(yaml2obj - yaml2obj.cpp - ) - -target_link_libraries(yaml2obj LLVMSupport) diff --git a/utils/yaml2obj/Makefile b/utils/yaml2obj/Makefile deleted file mode 100644 index e746d85..0000000 --- a/utils/yaml2obj/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -##===- utils/yaml2obj/Makefile ----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../.. -TOOLNAME = yaml2obj -USEDLIBS = LLVMSupport.a - -# This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 - -# Don't install this utility -NO_INSTALL = 1 - -include $(LEVEL)/Makefile.common diff --git a/utils/yaml2obj/yaml2obj.cpp b/utils/yaml2obj/yaml2obj.cpp deleted file mode 100644 index 17b65ae..0000000 --- a/utils/yaml2obj/yaml2obj.cpp +++ /dev/null @@ -1,706 +0,0 @@ -//===- yaml2obj - Convert YAML to a binary object file --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This program takes a YAML description of an object file and outputs the -// binary equivalent. -// -// This is used for writing tests that require binary files. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/COFF.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include <vector> - -using namespace llvm; - -static cl::opt<std::string> - Input(cl::Positional, cl::desc("<input>"), cl::init("-")); - -template<class T> -typename llvm::enable_if_c<std::numeric_limits<T>::is_integer, bool>::type -getAs(const llvm::yaml::ScalarNode *SN, T &Result) { - SmallString<4> Storage; - StringRef Value = SN->getValue(Storage); - if (Value.getAsInteger(0, Result)) - return false; - return true; -} - -// Given a container with begin and end with ::value_type of a character type. -// Iterate through pairs of characters in the the set of [a-fA-F0-9] ignoring -// all other characters. -struct hex_pair_iterator { - StringRef::const_iterator Current, End; - typedef SmallVector<char, 2> value_type; - value_type Pair; - bool IsDone; - - hex_pair_iterator(StringRef C) - : Current(C.begin()), End(C.end()), IsDone(false) { - // Initalize Pair. - ++*this; - } - - // End iterator. - hex_pair_iterator() : Current(), End(), IsDone(true) {} - - value_type operator *() const { - return Pair; - } - - hex_pair_iterator operator ++() { - // We're at the end of the input. - if (Current == End) { - IsDone = true; - return *this; - } - Pair = value_type(); - for (; Current != End && Pair.size() != 2; ++Current) { - // Is a valid hex digit. - if ((*Current >= '0' && *Current <= '9') || - (*Current >= 'a' && *Current <= 'f') || - (*Current >= 'A' && *Current <= 'F')) - Pair.push_back(*Current); - } - // Hit the end without getting 2 hex digits. Pair is invalid. - if (Pair.size() != 2) - IsDone = true; - return *this; - } - - bool operator ==(const hex_pair_iterator Other) { - return (IsDone == Other.IsDone) || - (Current == Other.Current && End == Other.End); - } - - bool operator !=(const hex_pair_iterator Other) { - return !(*this == Other); - } -}; - -template <class ContainerOut> -static bool hexStringToByteArray(StringRef Str, ContainerOut &Out) { - for (hex_pair_iterator I(Str), E; I != E; ++I) { - typename hex_pair_iterator::value_type Pair = *I; - typename ContainerOut::value_type Byte; - if (StringRef(Pair.data(), 2).getAsInteger(16, Byte)) - return false; - Out.push_back(Byte); - } - return true; -} - -// The structure of the yaml files is not an exact 1:1 match to COFF. In order -// to use yaml::IO, we use these structures which are closer to the source. -namespace COFFYAML { - struct Relocation { - uint32_t VirtualAddress; - uint32_t SymbolTableIndex; - COFF::RelocationTypeX86 Type; - }; - - struct Section { - std::vector<COFF::SectionCharacteristics> Characteristics; - StringRef SectionData; - std::vector<Relocation> Relocations; - StringRef Name; - }; - - struct Header { - COFF::MachineTypes Machine; - std::vector<COFF::Characteristics> Characteristics; - }; - - struct Symbol { - COFF::SymbolBaseType SimpleType; - uint8_t NumberOfAuxSymbols; - StringRef Name; - COFF::SymbolStorageClass StorageClass; - StringRef AuxillaryData; - COFF::SymbolComplexType ComplexType; - uint32_t Value; - uint16_t SectionNumber; - }; - - struct Object { - Header HeaderData; - std::vector<Section> Sections; - std::vector<Symbol> Symbols; - }; -} - -/// This parses a yaml stream that represents a COFF object file. -/// See docs/yaml2obj for the yaml scheema. -struct COFFParser { - COFFParser(COFFYAML::Object &Obj) : Obj(Obj) { - std::memset(&Header, 0, sizeof(Header)); - // A COFF string table always starts with a 4 byte size field. Offsets into - // it include this size, so allocate it now. - StringTable.append(4, 0); - } - - void parseHeader() { - Header.Machine = Obj.HeaderData.Machine; - - const std::vector<COFF::Characteristics> &Characteristics = - Obj.HeaderData.Characteristics; - for (std::vector<COFF::Characteristics>::const_iterator I = - Characteristics.begin(), E = Characteristics.end(); I != E; ++I) { - uint16_t Characteristic = *I; - Header.Characteristics |= Characteristic; - } - } - - bool parseSections() { - for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(), - e = Obj.Sections.end(); i != e; ++i) { - const COFFYAML::Section &YamlSection = *i; - Section Sec; - std::memset(&Sec.Header, 0, sizeof(Sec.Header)); - - // If the name is less than 8 bytes, store it in place, otherwise - // store it in the string table. - StringRef Name = YamlSection.Name; - std::fill_n(Sec.Header.Name, unsigned(COFF::NameSize), 0); - if (Name.size() <= COFF::NameSize) { - std::copy(Name.begin(), Name.end(), Sec.Header.Name); - } else { - // Add string to the string table and format the index for output. - unsigned Index = getStringIndex(Name); - std::string str = utostr(Index); - if (str.size() > 7) { - errs() << "String table got too large"; - return false; - } - Sec.Header.Name[0] = '/'; - std::copy(str.begin(), str.end(), Sec.Header.Name + 1); - } - - for (std::vector<COFF::SectionCharacteristics>::const_iterator i = - YamlSection.Characteristics.begin(), - e = YamlSection.Characteristics.end(); - i != e; ++i) { - uint32_t Characteristic = *i; - Sec.Header.Characteristics |= Characteristic; - } - - StringRef Data = YamlSection.SectionData; - if (!hexStringToByteArray(Data, Sec.Data)) { - errs() << "SectionData must be a collection of pairs of hex bytes"; - return false; - } - Sections.push_back(Sec); - } - return true; - } - - bool parseSymbols() { - for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(), - e = Obj.Symbols.end(); i != e; ++i) { - COFFYAML::Symbol YamlSymbol = *i; - Symbol Sym; - std::memset(&Sym.Header, 0, sizeof(Sym.Header)); - - // If the name is less than 8 bytes, store it in place, otherwise - // store it in the string table. - StringRef Name = YamlSymbol.Name; - std::fill_n(Sym.Header.Name, unsigned(COFF::NameSize), 0); - if (Name.size() <= COFF::NameSize) { - std::copy(Name.begin(), Name.end(), Sym.Header.Name); - } else { - // Add string to the string table and format the index for output. - unsigned Index = getStringIndex(Name); - *reinterpret_cast<support::aligned_ulittle32_t*>( - Sym.Header.Name + 4) = Index; - } - - Sym.Header.Value = YamlSymbol.Value; - Sym.Header.Type |= YamlSymbol.SimpleType; - Sym.Header.Type |= YamlSymbol.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT; - Sym.Header.StorageClass = YamlSymbol.StorageClass; - Sym.Header.SectionNumber = YamlSymbol.SectionNumber; - - StringRef Data = YamlSymbol.AuxillaryData; - if (!hexStringToByteArray(Data, Sym.AuxSymbols)) { - errs() << "AuxillaryData must be a collection of pairs of hex bytes"; - return false; - } - Symbols.push_back(Sym); - } - return true; - } - - bool parse() { - parseHeader(); - if (!parseSections()) - return false; - if (!parseSymbols()) - return false; - return true; - } - - unsigned getStringIndex(StringRef Str) { - StringMap<unsigned>::iterator i = StringTableMap.find(Str); - if (i == StringTableMap.end()) { - unsigned Index = StringTable.size(); - StringTable.append(Str.begin(), Str.end()); - StringTable.push_back(0); - StringTableMap[Str] = Index; - return Index; - } - return i->second; - } - - COFFYAML::Object &Obj; - COFF::header Header; - - struct Section { - COFF::section Header; - std::vector<uint8_t> Data; - std::vector<COFF::relocation> Relocations; - }; - - struct Symbol { - COFF::symbol Header; - std::vector<uint8_t> AuxSymbols; - }; - - std::vector<Section> Sections; - std::vector<Symbol> Symbols; - StringMap<unsigned> StringTableMap; - std::string StringTable; -}; - -// Take a CP and assign addresses and sizes to everything. Returns false if the -// layout is not valid to do. -static bool layoutCOFF(COFFParser &CP) { - uint32_t SectionTableStart = 0; - uint32_t SectionTableSize = 0; - - // The section table starts immediately after the header, including the - // optional header. - SectionTableStart = sizeof(COFF::header) + CP.Header.SizeOfOptionalHeader; - SectionTableSize = sizeof(COFF::section) * CP.Sections.size(); - - uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize; - - // Assign each section data address consecutively. - for (std::vector<COFFParser::Section>::iterator i = CP.Sections.begin(), - e = CP.Sections.end(); - i != e; ++i) { - if (!i->Data.empty()) { - i->Header.SizeOfRawData = i->Data.size(); - i->Header.PointerToRawData = CurrentSectionDataOffset; - CurrentSectionDataOffset += i->Header.SizeOfRawData; - // TODO: Handle alignment. - } else { - i->Header.SizeOfRawData = 0; - i->Header.PointerToRawData = 0; - } - } - - uint32_t SymbolTableStart = CurrentSectionDataOffset; - - // Calculate number of symbols. - uint32_t NumberOfSymbols = 0; - for (std::vector<COFFParser::Symbol>::iterator i = CP.Symbols.begin(), - e = CP.Symbols.end(); - i != e; ++i) { - if (i->AuxSymbols.size() % COFF::SymbolSize != 0) { - errs() << "AuxillaryData size not a multiple of symbol size!\n"; - return false; - } - i->Header.NumberOfAuxSymbols = i->AuxSymbols.size() / COFF::SymbolSize; - NumberOfSymbols += 1 + i->Header.NumberOfAuxSymbols; - } - - // Store all the allocated start addresses in the header. - CP.Header.NumberOfSections = CP.Sections.size(); - CP.Header.NumberOfSymbols = NumberOfSymbols; - CP.Header.PointerToSymbolTable = SymbolTableStart; - - *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0]) - = CP.StringTable.size(); - - return true; -} - -template <typename value_type> -struct binary_le_impl { - value_type Value; - binary_le_impl(value_type V) : Value(V) {} -}; - -template <typename value_type> -raw_ostream &operator <<( raw_ostream &OS - , const binary_le_impl<value_type> &BLE) { - char Buffer[sizeof(BLE.Value)]; - support::endian::write<value_type, support::little, support::unaligned>( - Buffer, BLE.Value); - OS.write(Buffer, sizeof(BLE.Value)); - return OS; -} - -template <typename value_type> -binary_le_impl<value_type> binary_le(value_type V) { - return binary_le_impl<value_type>(V); -} - -void writeCOFF(COFFParser &CP, raw_ostream &OS) { - OS << binary_le(CP.Header.Machine) - << binary_le(CP.Header.NumberOfSections) - << binary_le(CP.Header.TimeDateStamp) - << binary_le(CP.Header.PointerToSymbolTable) - << binary_le(CP.Header.NumberOfSymbols) - << binary_le(CP.Header.SizeOfOptionalHeader) - << binary_le(CP.Header.Characteristics); - - // Output section table. - for (std::vector<COFFParser::Section>::const_iterator i = CP.Sections.begin(), - e = CP.Sections.end(); - i != e; ++i) { - OS.write(i->Header.Name, COFF::NameSize); - OS << binary_le(i->Header.VirtualSize) - << binary_le(i->Header.VirtualAddress) - << binary_le(i->Header.SizeOfRawData) - << binary_le(i->Header.PointerToRawData) - << binary_le(i->Header.PointerToRelocations) - << binary_le(i->Header.PointerToLineNumbers) - << binary_le(i->Header.NumberOfRelocations) - << binary_le(i->Header.NumberOfLineNumbers) - << binary_le(i->Header.Characteristics); - } - - // Output section data. - for (std::vector<COFFParser::Section>::const_iterator i = CP.Sections.begin(), - e = CP.Sections.end(); - i != e; ++i) { - if (!i->Data.empty()) - OS.write(reinterpret_cast<const char*>(&i->Data[0]), i->Data.size()); - } - - // Output symbol table. - - for (std::vector<COFFParser::Symbol>::const_iterator i = CP.Symbols.begin(), - e = CP.Symbols.end(); - i != e; ++i) { - OS.write(i->Header.Name, COFF::NameSize); - OS << binary_le(i->Header.Value) - << binary_le(i->Header.SectionNumber) - << binary_le(i->Header.Type) - << binary_le(i->Header.StorageClass) - << binary_le(i->Header.NumberOfAuxSymbols); - if (!i->AuxSymbols.empty()) - OS.write( reinterpret_cast<const char*>(&i->AuxSymbols[0]) - , i->AuxSymbols.size()); - } - - // Output string table. - OS.write(&CP.StringTable[0], CP.StringTable.size()); -} - -LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Relocation) -LLVM_YAML_IS_SEQUENCE_VECTOR(COFF::SectionCharacteristics) -LLVM_YAML_IS_SEQUENCE_VECTOR(COFF::Characteristics) -LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Section) -LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Symbol) - -namespace llvm { -namespace yaml { -#define ECase(X) IO.enumCase(Value, #X, COFF::X); - -template <> -struct ScalarEnumerationTraits<COFF::SymbolComplexType> { - static void enumeration(IO &IO, COFF::SymbolComplexType &Value) { - ECase(IMAGE_SYM_DTYPE_NULL); - ECase(IMAGE_SYM_DTYPE_POINTER); - ECase(IMAGE_SYM_DTYPE_FUNCTION); - ECase(IMAGE_SYM_DTYPE_ARRAY); - } -}; - -// FIXME: We cannot use ScalarBitSetTraits because of -// IMAGE_SYM_CLASS_END_OF_FUNCTION which is -1. -template <> -struct ScalarEnumerationTraits<COFF::SymbolStorageClass> { - static void enumeration(IO &IO, COFF::SymbolStorageClass &Value) { - ECase(IMAGE_SYM_CLASS_END_OF_FUNCTION); - ECase(IMAGE_SYM_CLASS_NULL); - ECase(IMAGE_SYM_CLASS_AUTOMATIC); - ECase(IMAGE_SYM_CLASS_EXTERNAL); - ECase(IMAGE_SYM_CLASS_STATIC); - ECase(IMAGE_SYM_CLASS_REGISTER); - ECase(IMAGE_SYM_CLASS_EXTERNAL_DEF); - ECase(IMAGE_SYM_CLASS_LABEL); - ECase(IMAGE_SYM_CLASS_UNDEFINED_LABEL); - ECase(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT); - ECase(IMAGE_SYM_CLASS_ARGUMENT); - ECase(IMAGE_SYM_CLASS_STRUCT_TAG); - ECase(IMAGE_SYM_CLASS_MEMBER_OF_UNION); - ECase(IMAGE_SYM_CLASS_UNION_TAG); - ECase(IMAGE_SYM_CLASS_TYPE_DEFINITION); - ECase(IMAGE_SYM_CLASS_UNDEFINED_STATIC); - ECase(IMAGE_SYM_CLASS_ENUM_TAG); - ECase(IMAGE_SYM_CLASS_MEMBER_OF_ENUM); - ECase(IMAGE_SYM_CLASS_REGISTER_PARAM); - ECase(IMAGE_SYM_CLASS_BIT_FIELD); - ECase(IMAGE_SYM_CLASS_BLOCK); - ECase(IMAGE_SYM_CLASS_FUNCTION); - ECase(IMAGE_SYM_CLASS_END_OF_STRUCT); - ECase(IMAGE_SYM_CLASS_FILE); - ECase(IMAGE_SYM_CLASS_SECTION); - ECase(IMAGE_SYM_CLASS_WEAK_EXTERNAL); - ECase(IMAGE_SYM_CLASS_CLR_TOKEN); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::SymbolBaseType> { - static void enumeration(IO &IO, COFF::SymbolBaseType &Value) { - ECase(IMAGE_SYM_TYPE_NULL); - ECase(IMAGE_SYM_TYPE_VOID); - ECase(IMAGE_SYM_TYPE_CHAR); - ECase(IMAGE_SYM_TYPE_SHORT); - ECase(IMAGE_SYM_TYPE_INT); - ECase(IMAGE_SYM_TYPE_LONG); - ECase(IMAGE_SYM_TYPE_FLOAT); - ECase(IMAGE_SYM_TYPE_DOUBLE); - ECase(IMAGE_SYM_TYPE_STRUCT); - ECase(IMAGE_SYM_TYPE_UNION); - ECase(IMAGE_SYM_TYPE_ENUM); - ECase(IMAGE_SYM_TYPE_MOE); - ECase(IMAGE_SYM_TYPE_BYTE); - ECase(IMAGE_SYM_TYPE_WORD); - ECase(IMAGE_SYM_TYPE_UINT); - ECase(IMAGE_SYM_TYPE_DWORD); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::MachineTypes> { - static void enumeration(IO &IO, COFF::MachineTypes &Value) { - ECase(IMAGE_FILE_MACHINE_UNKNOWN); - ECase(IMAGE_FILE_MACHINE_AM33); - ECase(IMAGE_FILE_MACHINE_AMD64); - ECase(IMAGE_FILE_MACHINE_ARM); - ECase(IMAGE_FILE_MACHINE_ARMV7); - ECase(IMAGE_FILE_MACHINE_EBC); - ECase(IMAGE_FILE_MACHINE_I386); - ECase(IMAGE_FILE_MACHINE_IA64); - ECase(IMAGE_FILE_MACHINE_M32R); - ECase(IMAGE_FILE_MACHINE_MIPS16); - ECase(IMAGE_FILE_MACHINE_MIPSFPU); - ECase(IMAGE_FILE_MACHINE_MIPSFPU16); - ECase(IMAGE_FILE_MACHINE_POWERPC); - ECase(IMAGE_FILE_MACHINE_POWERPCFP); - ECase(IMAGE_FILE_MACHINE_R4000); - ECase(IMAGE_FILE_MACHINE_SH3); - ECase(IMAGE_FILE_MACHINE_SH3DSP); - ECase(IMAGE_FILE_MACHINE_SH4); - ECase(IMAGE_FILE_MACHINE_SH5); - ECase(IMAGE_FILE_MACHINE_THUMB); - ECase(IMAGE_FILE_MACHINE_WCEMIPSV2); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::Characteristics> { - static void enumeration(IO &IO, COFF::Characteristics &Value) { - ECase(IMAGE_FILE_RELOCS_STRIPPED); - ECase(IMAGE_FILE_EXECUTABLE_IMAGE); - ECase(IMAGE_FILE_LINE_NUMS_STRIPPED); - ECase(IMAGE_FILE_LOCAL_SYMS_STRIPPED); - ECase(IMAGE_FILE_AGGRESSIVE_WS_TRIM); - ECase(IMAGE_FILE_LARGE_ADDRESS_AWARE); - ECase(IMAGE_FILE_BYTES_REVERSED_LO); - ECase(IMAGE_FILE_32BIT_MACHINE); - ECase(IMAGE_FILE_DEBUG_STRIPPED); - ECase(IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP); - ECase(IMAGE_FILE_NET_RUN_FROM_SWAP); - ECase(IMAGE_FILE_SYSTEM); - ECase(IMAGE_FILE_DLL); - ECase(IMAGE_FILE_UP_SYSTEM_ONLY); - ECase(IMAGE_FILE_BYTES_REVERSED_HI); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::SectionCharacteristics> { - static void enumeration(IO &IO, COFF::SectionCharacteristics &Value) { - ECase(IMAGE_SCN_TYPE_NO_PAD); - ECase(IMAGE_SCN_CNT_CODE); - ECase(IMAGE_SCN_CNT_INITIALIZED_DATA); - ECase(IMAGE_SCN_CNT_UNINITIALIZED_DATA); - ECase(IMAGE_SCN_LNK_OTHER); - ECase(IMAGE_SCN_LNK_INFO); - ECase(IMAGE_SCN_LNK_REMOVE); - ECase(IMAGE_SCN_LNK_COMDAT); - ECase(IMAGE_SCN_GPREL); - ECase(IMAGE_SCN_MEM_PURGEABLE); - ECase(IMAGE_SCN_MEM_16BIT); - ECase(IMAGE_SCN_MEM_LOCKED); - ECase(IMAGE_SCN_MEM_PRELOAD); - ECase(IMAGE_SCN_ALIGN_1BYTES); - ECase(IMAGE_SCN_ALIGN_2BYTES); - ECase(IMAGE_SCN_ALIGN_4BYTES); - ECase(IMAGE_SCN_ALIGN_8BYTES); - ECase(IMAGE_SCN_ALIGN_16BYTES); - ECase(IMAGE_SCN_ALIGN_32BYTES); - ECase(IMAGE_SCN_ALIGN_64BYTES); - ECase(IMAGE_SCN_ALIGN_128BYTES); - ECase(IMAGE_SCN_ALIGN_256BYTES); - ECase(IMAGE_SCN_ALIGN_512BYTES); - ECase(IMAGE_SCN_ALIGN_1024BYTES); - ECase(IMAGE_SCN_ALIGN_2048BYTES); - ECase(IMAGE_SCN_ALIGN_4096BYTES); - ECase(IMAGE_SCN_ALIGN_8192BYTES); - ECase(IMAGE_SCN_LNK_NRELOC_OVFL); - ECase(IMAGE_SCN_MEM_DISCARDABLE); - ECase(IMAGE_SCN_MEM_NOT_CACHED); - ECase(IMAGE_SCN_MEM_NOT_PAGED); - ECase(IMAGE_SCN_MEM_SHARED); - ECase(IMAGE_SCN_MEM_EXECUTE); - ECase(IMAGE_SCN_MEM_READ); - ECase(IMAGE_SCN_MEM_WRITE); - } -}; - -template <> -struct ScalarEnumerationTraits<COFF::RelocationTypeX86> { - static void enumeration(IO &IO, COFF::RelocationTypeX86 &Value) { - ECase(IMAGE_REL_I386_ABSOLUTE); - ECase(IMAGE_REL_I386_DIR16); - ECase(IMAGE_REL_I386_REL16); - ECase(IMAGE_REL_I386_DIR32); - ECase(IMAGE_REL_I386_DIR32NB); - ECase(IMAGE_REL_I386_SEG12); - ECase(IMAGE_REL_I386_SECTION); - ECase(IMAGE_REL_I386_SECREL); - ECase(IMAGE_REL_I386_TOKEN); - ECase(IMAGE_REL_I386_SECREL7); - ECase(IMAGE_REL_I386_REL32); - ECase(IMAGE_REL_AMD64_ABSOLUTE); - ECase(IMAGE_REL_AMD64_ADDR64); - ECase(IMAGE_REL_AMD64_ADDR32); - ECase(IMAGE_REL_AMD64_ADDR32NB); - ECase(IMAGE_REL_AMD64_REL32); - ECase(IMAGE_REL_AMD64_REL32_1); - ECase(IMAGE_REL_AMD64_REL32_2); - ECase(IMAGE_REL_AMD64_REL32_3); - ECase(IMAGE_REL_AMD64_REL32_4); - ECase(IMAGE_REL_AMD64_REL32_5); - ECase(IMAGE_REL_AMD64_SECTION); - ECase(IMAGE_REL_AMD64_SECREL); - ECase(IMAGE_REL_AMD64_SECREL7); - ECase(IMAGE_REL_AMD64_TOKEN); - ECase(IMAGE_REL_AMD64_SREL32); - ECase(IMAGE_REL_AMD64_PAIR); - ECase(IMAGE_REL_AMD64_SSPAN32); - } -}; - -#undef ECase - -template <> -struct MappingTraits<COFFYAML::Symbol> { - static void mapping(IO &IO, COFFYAML::Symbol &S) { - IO.mapRequired("SimpleType", S.SimpleType); - IO.mapOptional("NumberOfAuxSymbols", S.NumberOfAuxSymbols); - IO.mapRequired("Name", S.Name); - IO.mapRequired("StorageClass", S.StorageClass); - IO.mapOptional("AuxillaryData", S.AuxillaryData); // FIXME: typo - IO.mapRequired("ComplexType", S.ComplexType); - IO.mapRequired("Value", S.Value); - IO.mapRequired("SectionNumber", S.SectionNumber); - } -}; - -template <> -struct MappingTraits<COFFYAML::Header> { - static void mapping(IO &IO, COFFYAML::Header &H) { - IO.mapRequired("Machine", H.Machine); - IO.mapOptional("Characteristics", H.Characteristics); - } -}; - -template <> -struct MappingTraits<COFFYAML::Relocation> { - static void mapping(IO &IO, COFFYAML::Relocation &Rel) { - IO.mapRequired("Type", Rel.Type); - IO.mapRequired("VirtualAddress", Rel.VirtualAddress); - IO.mapRequired("SymbolTableIndex", Rel.SymbolTableIndex); - } -}; - -template <> -struct MappingTraits<COFFYAML::Section> { - static void mapping(IO &IO, COFFYAML::Section &Sec) { - IO.mapOptional("Relocations", Sec.Relocations); - IO.mapRequired("SectionData", Sec.SectionData); - IO.mapRequired("Characteristics", Sec.Characteristics); - IO.mapRequired("Name", Sec.Name); - } -}; - -template <> -struct MappingTraits<COFFYAML::Object> { - static void mapping(IO &IO, COFFYAML::Object &Obj) { - IO.mapRequired("sections", Obj.Sections); - IO.mapRequired("header", Obj.HeaderData); - IO.mapRequired("symbols", Obj.Symbols); - } -}; -} // end namespace yaml -} // end namespace llvm - -int main(int argc, char **argv) { - cl::ParseCommandLineOptions(argc, argv); - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - OwningPtr<MemoryBuffer> Buf; - if (MemoryBuffer::getFileOrSTDIN(Input, Buf)) - return 1; - - yaml::Input YIn(Buf->getBuffer()); - COFFYAML::Object Doc; - YIn >> Doc; - if (YIn.error()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - - COFFParser CP(Doc); - if (!CP.parse()) { - errs() << "yaml2obj: Failed to parse YAML file!\n"; - return 1; - } - - if (!layoutCOFF(CP)) { - errs() << "yaml2obj: Failed to layout COFF file!\n"; - return 1; - } - writeCOFF(CP, outs()); -} |