aboutsummaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/LLVMBuild.txt4
-rw-r--r--utils/TableGen/AsmMatcherEmitter.cpp85
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/CodeGenRegisters.cpp146
-rw-r--r--utils/TableGen/CodeGenRegisters.h7
-rw-r--r--utils/TableGen/CodeGenTarget.cpp1
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.cpp512
-rw-r--r--utils/TableGen/DFAPacketizerEmitter.h54
-rw-r--r--utils/TableGen/EDEmitter.cpp12
-rw-r--r--utils/TableGen/LLVMBuild.txt1
-rw-r--r--utils/TableGen/SubtargetEmitter.cpp4
-rw-r--r--utils/TableGen/TableGen.cpp7
-rw-r--r--utils/buildit/GNUmakefile2
-rw-r--r--utils/lit/lit/TestRunner.py50
-rw-r--r--utils/llvm-build/llvmbuild/componentinfo.py37
-rw-r--r--utils/llvm-build/llvmbuild/main.py171
-rwxr-xr-xutils/release/tag.sh10
-rwxr-xr-xutils/release/test-release.sh50
-rw-r--r--utils/unittest/CMakeLists.txt8
-rw-r--r--utils/unittest/UnitTestMain/Makefile2
-rw-r--r--utils/unittest/googletest/Makefile2
21 files changed, 1003 insertions, 163 deletions
diff --git a/utils/LLVMBuild.txt b/utils/LLVMBuild.txt
index fc16720..382bfd3 100644
--- a/utils/LLVMBuild.txt
+++ b/utils/LLVMBuild.txt
@@ -15,6 +15,9 @@
;
;===------------------------------------------------------------------------===;
+[common]
+subdirectories = TableGen unittest
+
[component_0]
type = Group
name = BuildTools
@@ -24,4 +27,3 @@ parent = $ROOT
type = Group
name = UtilityTools
parent = $ROOT
-
diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp
index 01754c3..5ef0db9 100644
--- a/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/utils/TableGen/AsmMatcherEmitter.cpp
@@ -252,11 +252,6 @@ public:
switch (Kind) {
case Invalid:
assert(0 && "Invalid kind!");
- case Token:
- // Tokens are comparable by value.
- //
- // FIXME: Compare by enum value.
- return ValueName < RHS.ValueName;
default:
// This class precedes the RHS if it is a proper subset of the RHS.
@@ -737,7 +732,9 @@ void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) {
// The first token of the instruction is the mnemonic, which must be a
// simple string, not a $foo variable or a singleton register.
- assert(!AsmOperands.empty() && "Instruction has no tokens?");
+ if (AsmOperands.empty())
+ throw TGError(TheDef->getLoc(),
+ "Instruction '" + TheDef->getName() + "' has no tokens");
Mnemonic = AsmOperands[0].Token;
if (Mnemonic[0] == '$' || getSingletonRegisterForAsmOperand(0, Info))
throw TGError(TheDef->getLoc(),
@@ -1302,6 +1299,17 @@ void AsmMatcherInfo::BuildInfo() {
II->BuildAliasResultOperands();
}
+ // Process token alias definitions and set up the associated superclass
+ // information.
+ std::vector<Record*> AllTokenAliases =
+ Records.getAllDerivedDefinitions("TokenAlias");
+ for (unsigned i = 0, e = AllTokenAliases.size(); i != e; ++i) {
+ Record *Rec = AllTokenAliases[i];
+ ClassInfo *FromClass = getTokenClass(Rec->getValueAsString("FromToken"));
+ ClassInfo *ToClass = getTokenClass(Rec->getValueAsString("ToToken"));
+ FromClass->SuperClasses.push_back(ToClass);
+ }
+
// Reorder classes so that classes precede super classes.
std::sort(Classes.begin(), Classes.end(), less_ptr<ClassInfo>());
}
@@ -1663,7 +1671,7 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target,
/// EmitValidateOperandClass - Emit the function to validate an operand class.
static void EmitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
- OS << "static bool ValidateOperandClass(MCParsedAsmOperand *GOp, "
+ OS << "static bool validateOperandClass(MCParsedAsmOperand *GOp, "
<< "MatchClassKind Kind) {\n";
OS << " " << Info.Target.getName() << "Operand &Operand = *("
<< Info.Target.getName() << "Operand*)GOp;\n";
@@ -1674,7 +1682,8 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
// Check for Token operands first.
OS << " if (Operand.isToken())\n";
- OS << " return MatchTokenString(Operand.getToken()) == Kind;\n\n";
+ OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind);"
+ << "\n\n";
// Check for register operands, including sub-classes.
OS << " if (Operand.isReg()) {\n";
@@ -1688,7 +1697,7 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
<< it->first->getName() << ": OpKind = " << it->second->Name
<< "; break;\n";
OS << " }\n";
- OS << " return IsSubclass(OpKind, Kind);\n";
+ OS << " return isSubclass(OpKind, Kind);\n";
OS << " }\n\n";
// Check the user classes. We don't care what order since we're only
@@ -1715,8 +1724,8 @@ static void EmitValidateOperandClass(AsmMatcherInfo &Info,
static void EmitIsSubclass(CodeGenTarget &Target,
std::vector<ClassInfo*> &Infos,
raw_ostream &OS) {
- OS << "/// IsSubclass - Compute whether \\arg A is a subclass of \\arg B.\n";
- OS << "static bool IsSubclass(MatchClassKind A, MatchClassKind B) {\n";
+ OS << "/// isSubclass - Compute whether \\arg A is a subclass of \\arg B.\n";
+ OS << "static bool isSubclass(MatchClassKind A, MatchClassKind B) {\n";
OS << " if (A == B)\n";
OS << " return true;\n\n";
@@ -1727,32 +1736,30 @@ static void EmitIsSubclass(CodeGenTarget &Target,
ie = Infos.end(); it != ie; ++it) {
ClassInfo &A = **it;
- if (A.Kind != ClassInfo::Token) {
- std::vector<StringRef> SuperClasses;
- for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
- ie = Infos.end(); it != ie; ++it) {
- ClassInfo &B = **it;
-
- if (&A != &B && A.isSubsetOf(B))
- SuperClasses.push_back(B.Name);
- }
+ std::vector<StringRef> SuperClasses;
+ for (std::vector<ClassInfo*>::iterator it = Infos.begin(),
+ ie = Infos.end(); it != ie; ++it) {
+ ClassInfo &B = **it;
- if (SuperClasses.empty())
- continue;
+ if (&A != &B && A.isSubsetOf(B))
+ SuperClasses.push_back(B.Name);
+ }
- OS << "\n case " << A.Name << ":\n";
+ if (SuperClasses.empty())
+ continue;
- if (SuperClasses.size() == 1) {
- OS << " return B == " << SuperClasses.back() << ";\n";
- continue;
- }
+ OS << "\n case " << A.Name << ":\n";
- OS << " switch (B) {\n";
- OS << " default: return false;\n";
- for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
- OS << " case " << SuperClasses[i] << ": return true;\n";
- OS << " }\n";
+ if (SuperClasses.size() == 1) {
+ OS << " return B == " << SuperClasses.back() << ";\n";
+ continue;
}
+
+ OS << " switch (B) {\n";
+ OS << " default: return false;\n";
+ for (unsigned i = 0, e = SuperClasses.size(); i != e; ++i)
+ OS << " case " << SuperClasses[i] << ": return true;\n";
+ OS << " }\n";
}
OS << " }\n";
OS << "}\n\n";
@@ -1774,7 +1781,7 @@ static void EmitMatchTokenString(CodeGenTarget &Target,
"return " + CI.Name + ";"));
}
- OS << "static MatchClassKind MatchTokenString(StringRef Name) {\n";
+ OS << "static MatchClassKind matchTokenString(StringRef Name) {\n";
StringMatcher("Name", Matches, OS).Emit();
@@ -1912,7 +1919,7 @@ static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) {
Info.getRecords().getAllDerivedDefinitions("MnemonicAlias");
if (Aliases.empty()) return false;
- OS << "static void ApplyMnemonicAliases(StringRef &Mnemonic, "
+ OS << "static void applyMnemonicAliases(StringRef &Mnemonic, "
"unsigned Features) {\n";
// Keep track of all the aliases from a mnemonic. Use an std::map so that the
@@ -2061,7 +2068,7 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// the found operand class.
OS << Target.getName() << ClassName << "::OperandMatchResultTy "
<< Target.getName() << ClassName << "::\n"
- << "TryCustomParseOperand(SmallVectorImpl<MCParsedAsmOperand*>"
+ << "tryCustomParseOperand(SmallVectorImpl<MCParsedAsmOperand*>"
<< " &Operands,\n unsigned MCK) {\n\n"
<< " switch(MCK) {\n";
@@ -2127,7 +2134,7 @@ static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
// Emit call to the custom parser method
OS << " // call custom parse method to handle the operand\n";
OS << " OperandMatchResultTy Result = ";
- OS << "TryCustomParseOperand(Operands, it->Class);\n";
+ OS << "tryCustomParseOperand(Operands, it->Class);\n";
OS << " if (Result != MatchOperand_NoMatch)\n";
OS << " return Result;\n";
OS << " }\n\n";
@@ -2214,7 +2221,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
OS << " StringRef Mnemonic);\n";
- OS << " OperandMatchResultTy TryCustomParseOperand(\n";
+ OS << " OperandMatchResultTy tryCustomParseOperand(\n";
OS << " SmallVectorImpl<MCParsedAsmOperand*> &Operands,\n";
OS << " unsigned MCK);\n\n";
}
@@ -2361,7 +2368,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
if (HasMnemonicAliases) {
OS << " // Process all MnemonicAliases to remap the mnemonic.\n";
- OS << " ApplyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
+ OS << " applyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n";
}
// Emit code to compute the class list for this operand vector.
@@ -2403,7 +2410,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n";
OS << " break;\n";
OS << " }\n";
- OS << " if (ValidateOperandClass(Operands[i+1], "
+ OS << " if (validateOperandClass(Operands[i+1], "
"(MatchClassKind)it->Classes[i]))\n";
OS << " continue;\n";
OS << " // If this operand is broken for all of the instances of this\n";
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 9e87515..ac33f99 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -17,6 +17,7 @@ add_tablegen(llvm-tblgen LLVM
DAGISelMatcherGen.cpp
DAGISelMatcherOpt.cpp
DAGISelMatcher.cpp
+ DFAPacketizerEmitter.cpp
DisassemblerEmitter.cpp
EDEmitter.cpp
FastISelEmitter.cpp
diff --git a/utils/TableGen/CodeGenRegisters.cpp b/utils/TableGen/CodeGenRegisters.cpp
index 8de4615..3aadf50 100644
--- a/utils/TableGen/CodeGenRegisters.cpp
+++ b/utils/TableGen/CodeGenRegisters.cpp
@@ -582,6 +582,23 @@ void CodeGenRegBank::addToMaps(CodeGenRegisterClass *RC) {
Key2RC.insert(std::make_pair(K, RC));
}
+// Create a synthetic sub-class if it is missing.
+CodeGenRegisterClass*
+CodeGenRegBank::getOrCreateSubClass(const CodeGenRegisterClass *RC,
+ const CodeGenRegister::Set *Members,
+ StringRef Name) {
+ // Synthetic sub-class has the same size and alignment as RC.
+ CodeGenRegisterClass::Key K(Members, RC->SpillSize, RC->SpillAlignment);
+ RCKeyMap::const_iterator FoundI = Key2RC.find(K);
+ if (FoundI != Key2RC.end())
+ return FoundI->second;
+
+ // Sub-class doesn't exist, create a new one.
+ CodeGenRegisterClass *NewRC = new CodeGenRegisterClass(Name, K);
+ addToMaps(NewRC);
+ return NewRC;
+}
+
CodeGenRegisterClass *CodeGenRegBank::getRegClass(Record *Def) {
if (CodeGenRegisterClass *RC = Def2RC[Def])
return RC;
@@ -739,61 +756,102 @@ void CodeGenRegBank::computeDerivedInfo() {
computeComposites();
}
+//
+// Synthesize missing register class intersections.
+//
+// Make sure that sub-classes of RC exists such that getCommonSubClass(RC, X)
+// returns a maximal register class for all X.
+//
+void CodeGenRegBank::inferCommonSubClass(CodeGenRegisterClass *RC) {
+ for (unsigned rci = 0, rce = RegClasses.size(); rci != rce; ++rci) {
+ CodeGenRegisterClass *RC1 = RC;
+ CodeGenRegisterClass *RC2 = RegClasses[rci];
+ if (RC1 == RC2)
+ continue;
+
+ // Compute the set intersection of RC1 and RC2.
+ const CodeGenRegister::Set &Memb1 = RC1->getMembers();
+ const CodeGenRegister::Set &Memb2 = RC2->getMembers();
+ CodeGenRegister::Set Intersection;
+ std::set_intersection(Memb1.begin(), Memb1.end(),
+ Memb2.begin(), Memb2.end(),
+ std::inserter(Intersection, Intersection.begin()),
+ CodeGenRegister::Less());
+
+ // Skip disjoint class pairs.
+ if (Intersection.empty())
+ continue;
+
+ // If RC1 and RC2 have different spill sizes or alignments, use the
+ // larger size for sub-classing. If they are equal, prefer RC1.
+ if (RC2->SpillSize > RC1->SpillSize ||
+ (RC2->SpillSize == RC1->SpillSize &&
+ RC2->SpillAlignment > RC1->SpillAlignment))
+ std::swap(RC1, RC2);
+
+ getOrCreateSubClass(RC1, &Intersection,
+ RC1->getName() + "_and_" + RC2->getName());
+ }
+}
+
+//
+// Synthesize missing sub-classes for getSubClassWithSubReg().
+//
+// Make sure that the set of registers in RC with a given SubIdx sub-register
+// form a register class. Update RC->SubClassWithSubReg.
+//
+void CodeGenRegBank::inferSubClassWithSubReg(CodeGenRegisterClass *RC) {
+ // Map SubRegIndex to set of registers in RC supporting that SubRegIndex.
+ typedef std::map<Record*, CodeGenRegister::Set, LessRecord> SubReg2SetMap;
+
+ // Compute the set of registers supporting each SubRegIndex.
+ SubReg2SetMap SRSets;
+ for (CodeGenRegister::Set::const_iterator RI = RC->getMembers().begin(),
+ RE = RC->getMembers().end(); RI != RE; ++RI) {
+ const CodeGenRegister::SubRegMap &SRM = (*RI)->getSubRegs();
+ for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(),
+ E = SRM.end(); I != E; ++I)
+ SRSets[I->first].insert(*RI);
+ }
+
+ // Find matching classes for all SRSets entries. Iterate in SubRegIndex
+ // numerical order to visit synthetic indices last.
+ for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
+ Record *SubIdx = SubRegIndices[sri];
+ SubReg2SetMap::const_iterator I = SRSets.find(SubIdx);
+ // Unsupported SubRegIndex. Skip it.
+ if (I == SRSets.end())
+ continue;
+ // In most cases, all RC registers support the SubRegIndex.
+ if (I->second.size() == RC->getMembers().size()) {
+ RC->setSubClassWithSubReg(SubIdx, RC);
+ continue;
+ }
+ // This is a real subset. See if we have a matching class.
+ CodeGenRegisterClass *SubRC =
+ getOrCreateSubClass(RC, &I->second,
+ RC->getName() + "_with_" + I->first->getName());
+ RC->setSubClassWithSubReg(SubIdx, SubRC);
+ }
+}
+
+//
// Infer missing register classes.
//
-// For every register class RC, make sure that the set of registers in RC with
-// a given SubIxx sub-register form a register class.
void CodeGenRegBank::computeInferredRegisterClasses() {
// When this function is called, the register classes have not been sorted
// and assigned EnumValues yet. That means getSubClasses(),
// getSuperClasses(), and hasSubClass() functions are defunct.
- // Map SubRegIndex to register set.
- typedef std::map<Record*, CodeGenRegister::Set, LessRecord> SubReg2SetMap;
-
// Visit all register classes, including the ones being added by the loop.
for (unsigned rci = 0; rci != RegClasses.size(); ++rci) {
- CodeGenRegisterClass &RC = *RegClasses[rci];
-
- // Compute the set of registers supporting each SubRegIndex.
- SubReg2SetMap SRSets;
- for (CodeGenRegister::Set::const_iterator RI = RC.getMembers().begin(),
- RE = RC.getMembers().end(); RI != RE; ++RI) {
- const CodeGenRegister::SubRegMap &SRM = (*RI)->getSubRegs();
- for (CodeGenRegister::SubRegMap::const_iterator I = SRM.begin(),
- E = SRM.end(); I != E; ++I)
- SRSets[I->first].insert(*RI);
- }
+ CodeGenRegisterClass *RC = RegClasses[rci];
- // Find matching classes for all SRSets entries. Iterate in SubRegIndex
- // numerical order to visit synthetic indices last.
- for (unsigned sri = 0, sre = SubRegIndices.size(); sri != sre; ++sri) {
- Record *SubIdx = SubRegIndices[sri];
- SubReg2SetMap::const_iterator I = SRSets.find(SubIdx);
- // Unsupported SubRegIndex. Skip it.
- if (I == SRSets.end())
- continue;
- // In most cases, all RC registers support the SubRegIndex.
- if (I->second.size() == RC.getMembers().size()) {
- RC.setSubClassWithSubReg(SubIdx, &RC);
- continue;
- }
+ // Synthesize answers for getSubClassWithSubReg().
+ inferSubClassWithSubReg(RC);
- // This is a real subset. See if we have a matching class.
- CodeGenRegisterClass::Key K(&I->second, RC.SpillSize, RC.SpillAlignment);
- RCKeyMap::const_iterator FoundI = Key2RC.find(K);
- if (FoundI != Key2RC.end()) {
- RC.setSubClassWithSubReg(SubIdx, FoundI->second);
- continue;
- }
-
- // Class doesn't exist.
- CodeGenRegisterClass *NewRC =
- new CodeGenRegisterClass(RC.getName() + "_with_" +
- I->first->getName(), K);
- addToMaps(NewRC);
- RC.setSubClassWithSubReg(SubIdx, NewRC);
- }
+ // Synthesize answers for getCommonSubClass().
+ inferCommonSubClass(RC);
}
}
diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h
index 4fc34b0..c74cfd6 100644
--- a/utils/TableGen/CodeGenRegisters.h
+++ b/utils/TableGen/CodeGenRegisters.h
@@ -237,8 +237,15 @@ namespace llvm {
// Add RC to *2RC maps.
void addToMaps(CodeGenRegisterClass*);
+ // Create a synthetic sub-class if it is missing.
+ CodeGenRegisterClass *getOrCreateSubClass(const CodeGenRegisterClass *RC,
+ const CodeGenRegister::Set *Membs,
+ StringRef Name);
+
// Infer missing register classes.
void computeInferredRegisterClasses();
+ void inferCommonSubClass(CodeGenRegisterClass *RC);
+ void inferSubClassWithSubReg(CodeGenRegisterClass *RC);
// Composite SubRegIndex instances.
// Map (SubRegIndex, SubRegIndex) -> SubRegIndex.
diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp
index 6e1872e..c8d2b00 100644
--- a/utils/TableGen/CodeGenTarget.cpp
+++ b/utils/TableGen/CodeGenTarget.cpp
@@ -267,6 +267,7 @@ void CodeGenTarget::ComputeInstrsByEnum() const {
"DBG_VALUE",
"REG_SEQUENCE",
"COPY",
+ "BUNDLE",
0
};
const DenseMap<const Record*, CodeGenInstruction*> &Insts = getInstructions();
diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp
new file mode 100644
index 0000000..2862d0c
--- /dev/null
+++ b/utils/TableGen/DFAPacketizerEmitter.cpp
@@ -0,0 +1,512 @@
+//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine-----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class parses the Schedule.td file and produces an API that can be used
+// to reason about whether an instruction can be added to a packet on a VLIW
+// architecture. The class internally generates a deterministic finite
+// automaton (DFA) that models all possible mappings of machine instructions
+// to functional units as instructions are added to a packet.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/TableGen/Record.h"
+#include "CodeGenTarget.h"
+#include "DFAPacketizerEmitter.h"
+#include <list>
+
+using namespace llvm;
+
+//
+//
+// State represents the usage of machine resources if the packet contains
+// a set of instruction classes.
+//
+// Specifically, currentState is a set of bit-masks.
+// The nth bit in a bit-mask indicates whether the nth resource is being used
+// by this state. The set of bit-masks in a state represent the different
+// possible outcomes of transitioning to this state.
+// For example: consider a two resource architecture: resource L and resource M
+// with three instruction classes: L, M, and L_or_M.
+// From the initial state (currentState = 0x00), if we add instruction class
+// L_or_M we will transition to a state with currentState = [0x01, 0x10]. This
+// represents the possible resource states that can result from adding a L_or_M
+// instruction
+//
+// Another way of thinking about this transition is we are mapping a NDFA with
+// two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10].
+//
+//
+namespace {
+class State {
+ public:
+ static int currentStateNum;
+ int stateNum;
+ bool isInitial;
+ std::set<unsigned> stateInfo;
+
+ State();
+ State(const State &S);
+
+ //
+ // canAddInsnClass - Returns true if an instruction of type InsnClass is a
+ // valid transition from this state, i.e., can an instruction of type InsnClass
+ // be added to the packet represented by this state.
+ //
+ // PossibleStates is the set of valid resource states that ensue from valid
+ // transitions.
+ //
+ bool canAddInsnClass(unsigned InsnClass, std::set<unsigned> &PossibleStates);
+};
+} // End anonymous namespace.
+
+
+namespace {
+struct Transition {
+ public:
+ static int currentTransitionNum;
+ int transitionNum;
+ State *from;
+ unsigned input;
+ State *to;
+
+ Transition(State *from_, unsigned input_, State *to_);
+};
+} // End anonymous namespace.
+
+
+//
+// Comparators to keep set of states sorted.
+//
+namespace {
+struct ltState {
+ bool operator()(const State *s1, const State *s2) const;
+};
+} // End anonymous namespace.
+
+
+//
+// class DFA: deterministic finite automaton for processor resource tracking.
+//
+namespace {
+class DFA {
+public:
+ DFA();
+
+ // Set of states. Need to keep this sorted to emit the transition table.
+ std::set<State*, ltState> states;
+
+ // Map from a state to the list of transitions with that state as source.
+ std::map<State*, SmallVector<Transition*, 16>, ltState> stateTransitions;
+ State *currentState;
+
+ // Highest valued Input seen.
+ unsigned LargestInput;
+
+ //
+ // Modify the DFA.
+ //
+ void initialize();
+ void addState(State *);
+ void addTransition(Transition *);
+
+ //
+ // getTransition - Return the state when a transition is made from
+ // State From with Input I. If a transition is not found, return NULL.
+ //
+ State *getTransition(State *, unsigned);
+
+ //
+ // isValidTransition: Predicate that checks if there is a valid transition
+ // from state From on input InsnClass.
+ //
+ bool isValidTransition(State *From, unsigned InsnClass);
+
+ //
+ // writeTable: Print out a table representing the DFA.
+ //
+ void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName);
+};
+} // End anonymous namespace.
+
+
+//
+// Constructors for State, Transition, and DFA
+//
+State::State() :
+ stateNum(currentStateNum++), isInitial(false) {}
+
+
+State::State(const State &S) :
+ stateNum(currentStateNum++), isInitial(S.isInitial),
+ stateInfo(S.stateInfo) {}
+
+
+Transition::Transition(State *from_, unsigned input_, State *to_) :
+ transitionNum(currentTransitionNum++), from(from_), input(input_),
+ to(to_) {}
+
+
+DFA::DFA() :
+ LargestInput(0) {}
+
+
+bool ltState::operator()(const State *s1, const State *s2) const {
+ return (s1->stateNum < s2->stateNum);
+}
+
+
+//
+// canAddInsnClass - Returns true if an instruction of type InsnClass is a
+// valid transition from this state i.e., can an instruction of type InsnClass
+// be added to the packet represented by this state.
+//
+// PossibleStates is the set of valid resource states that ensue from valid
+// transitions.
+//
+bool State::canAddInsnClass(unsigned InsnClass,
+ std::set<unsigned> &PossibleStates) {
+ //
+ // Iterate over all resource states in currentState.
+ //
+ bool AddedState = false;
+
+ for (std::set<unsigned>::iterator SI = stateInfo.begin();
+ SI != stateInfo.end(); ++SI) {
+ unsigned thisState = *SI;
+
+ //
+ // Iterate over all possible resources used in InsnClass.
+ // For ex: for InsnClass = 0x11, all resources = {0x01, 0x10}.
+ //
+
+ DenseSet<unsigned> VisitedResourceStates;
+ for (unsigned int j = 0; j < sizeof(InsnClass) * 8; ++j) {
+ if ((0x1 << j) & InsnClass) {
+ //
+ // For each possible resource used in InsnClass, generate the
+ // resource state if that resource was used.
+ //
+ unsigned ResultingResourceState = thisState | (0x1 << j);
+ //
+ // Check if the resulting resource state can be accommodated in this
+ // packet.
+ // We compute ResultingResourceState OR thisState.
+ // If the result of the OR is different than thisState, it implies
+ // that there is at least one resource that can be used to schedule
+ // InsnClass in the current packet.
+ // Insert ResultingResourceState into PossibleStates only if we haven't
+ // processed ResultingResourceState before.
+ //
+ if ((ResultingResourceState != thisState) &&
+ (VisitedResourceStates.count(ResultingResourceState) == 0)) {
+ VisitedResourceStates.insert(ResultingResourceState);
+ PossibleStates.insert(ResultingResourceState);
+ AddedState = true;
+ }
+ }
+ }
+ }
+
+ return AddedState;
+}
+
+
+void DFA::initialize() {
+ currentState->isInitial = true;
+}
+
+
+void DFA::addState(State *S) {
+ assert(!states.count(S) && "State already exists");
+ states.insert(S);
+}
+
+
+void DFA::addTransition(Transition *T) {
+ // Update LargestInput.
+ if (T->input > LargestInput)
+ LargestInput = T->input;
+
+ // Add the new transition.
+ stateTransitions[T->from].push_back(T);
+}
+
+
+//
+// getTransition - Return the state when a transition is made from
+// State From with Input I. If a transition is not found, return NULL.
+//
+State *DFA::getTransition(State *From, unsigned I) {
+ // Do we have a transition from state From?
+ if (!stateTransitions.count(From))
+ return NULL;
+
+ // Do we have a transition from state From with Input I?
+ for (SmallVector<Transition*, 16>::iterator VI =
+ stateTransitions[From].begin();
+ VI != stateTransitions[From].end(); ++VI)
+ if ((*VI)->input == I)
+ return (*VI)->to;
+
+ return NULL;
+}
+
+
+bool DFA::isValidTransition(State *From, unsigned InsnClass) {
+ return (getTransition(From, InsnClass) != NULL);
+}
+
+
+int State::currentStateNum = 0;
+int Transition::currentTransitionNum = 0;
+
+DFAGen::DFAGen(RecordKeeper &R):
+ TargetName(CodeGenTarget(R).getName()),
+ allInsnClasses(), Records(R) {}
+
+
+//
+// writeTableAndAPI - Print out a table representing the DFA and the
+// associated API to create a DFA packetizer.
+//
+// Format:
+// DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
+// transitions.
+// DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for
+// the ith state.
+//
+//
+void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
+ std::set<State*, ltState>::iterator SI = states.begin();
+ // This table provides a map to the beginning of the transitions for State s
+ // in DFAStateInputTable.
+ std::vector<int> StateEntry(states.size());
+
+ OS << "namespace llvm {\n\n";
+ OS << "const int " << TargetName << "DFAStateInputTable[][2] = {\n";
+
+ // Tracks the total valid transitions encountered so far. It is used
+ // to construct the StateEntry table.
+ int ValidTransitions = 0;
+ for (unsigned i = 0; i < states.size(); ++i, ++SI) {
+ StateEntry[i] = ValidTransitions;
+ for (unsigned j = 0; j <= LargestInput; ++j) {
+ assert (((*SI)->stateNum == (int) i) && "Mismatch in state numbers");
+ if (!isValidTransition(*SI, j))
+ continue;
+
+ OS << "{" << j << ", "
+ << getTransition(*SI, j)->stateNum
+ << "}, ";
+ ++ValidTransitions;
+ }
+
+ // If there are no valid transitions from this stage, we need a sentinel
+ // transition.
+ if (ValidTransitions == StateEntry[i])
+ OS << "{-1, -1},";
+
+ OS << "\n";
+ }
+ OS << "};\n\n";
+ OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n";
+
+ // Multiply i by 2 since each entry in DFAStateInputTable is a set of
+ // two numbers.
+ for (unsigned i = 0; i < states.size(); ++i)
+ OS << StateEntry[i] << ", ";
+
+ OS << "\n};\n";
+ OS << "} // namespace\n";
+
+
+ //
+ // Emit DFA Packetizer tables if the target is a VLIW machine.
+ //
+ std::string SubTargetClassName = TargetName + "GenSubtargetInfo";
+ OS << "\n" << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
+ OS << "namespace llvm {\n";
+ OS << "DFAPacketizer *" << SubTargetClassName << "::"
+ << "createDFAPacketizer(const InstrItineraryData *IID) const {\n"
+ << " return new DFAPacketizer(IID, " << TargetName
+ << "DFAStateInputTable, " << TargetName << "DFAStateEntryTable);\n}\n\n";
+ OS << "} // End llvm namespace \n";
+}
+
+
+//
+// collectAllInsnClasses - Populate allInsnClasses which is a set of units
+// used in each stage.
+//
+void DFAGen::collectAllInsnClasses(const std::string &Name,
+ Record *ItinData,
+ unsigned &NStages,
+ raw_ostream &OS) {
+ // Collect processor itineraries.
+ std::vector<Record*> ProcItinList =
+ Records.getAllDerivedDefinitions("ProcessorItineraries");
+
+ // If just no itinerary then don't bother.
+ if (ProcItinList.size() < 2)
+ return;
+ std::map<std::string, unsigned> NameToBitsMap;
+
+ // Parse functional units for all the itineraries.
+ for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
+ Record *Proc = ProcItinList[i];
+ std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
+
+ // Convert macros to bits for each stage.
+ for (unsigned i = 0, N = FUs.size(); i < N; ++i)
+ NameToBitsMap[FUs[i]->getName()] = (unsigned) (1U << i);
+ }
+
+ const std::vector<Record*> &StageList =
+ ItinData->getValueAsListOfDefs("Stages");
+
+ // The number of stages.
+ NStages = StageList.size();
+
+ // For each unit.
+ unsigned UnitBitValue = 0;
+
+ // Compute the bitwise or of each unit used in this stage.
+ for (unsigned i = 0; i < NStages; ++i) {
+ const Record *Stage = StageList[i];
+
+ // Get unit list.
+ const std::vector<Record*> &UnitList =
+ Stage->getValueAsListOfDefs("Units");
+
+ for (unsigned j = 0, M = UnitList.size(); j < M; ++j) {
+ // Conduct bitwise or.
+ std::string UnitName = UnitList[j]->getName();
+ assert(NameToBitsMap.count(UnitName));
+ UnitBitValue |= NameToBitsMap[UnitName];
+ }
+
+ if (UnitBitValue != 0)
+ allInsnClasses.insert(UnitBitValue);
+ }
+}
+
+
+//
+// Run the worklist algorithm to generate the DFA.
+//
+void DFAGen::run(raw_ostream &OS) {
+ EmitSourceFileHeader("Target DFA Packetizer Tables", OS);
+
+ // Collect processor iteraries.
+ std::vector<Record*> ProcItinList =
+ Records.getAllDerivedDefinitions("ProcessorItineraries");
+
+ //
+ // Collect the instruction classes.
+ //
+ for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
+ Record *Proc = ProcItinList[i];
+
+ // Get processor itinerary name.
+ const std::string &Name = Proc->getName();
+
+ // Skip default.
+ if (Name == "NoItineraries")
+ continue;
+
+ // Sanity check for at least one instruction itinerary class.
+ unsigned NItinClasses =
+ Records.getAllDerivedDefinitions("InstrItinClass").size();
+ if (NItinClasses == 0)
+ return;
+
+ // Get itinerary data list.
+ std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
+
+ // Collect instruction classes for all itinerary data.
+ for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) {
+ Record *ItinData = ItinDataList[j];
+ unsigned NStages;
+ collectAllInsnClasses(Name, ItinData, NStages, OS);
+ }
+ }
+
+
+ //
+ // Run a worklist algorithm to generate the DFA.
+ //
+ DFA D;
+ State *Initial = new State;
+ Initial->isInitial = true;
+ Initial->stateInfo.insert(0x0);
+ D.addState(Initial);
+ SmallVector<State*, 32> WorkList;
+ std::map<std::set<unsigned>, State*> Visited;
+
+ WorkList.push_back(Initial);
+
+ //
+ // Worklist algorithm to create a DFA for processor resource tracking.
+ // C = {set of InsnClasses}
+ // Begin with initial node in worklist. Initial node does not have
+ // any consumed resources,
+ // ResourceState = 0x0
+ // Visited = {}
+ // While worklist != empty
+ // S = first element of worklist
+ // For every instruction class C
+ // if we can accommodate C in S:
+ // S' = state with resource states = {S Union C}
+ // Add a new transition: S x C -> S'
+ // If S' is not in Visited:
+ // Add S' to worklist
+ // Add S' to Visited
+ //
+ while (!WorkList.empty()) {
+ State *current = WorkList.pop_back_val();
+ for (DenseSet<unsigned>::iterator CI = allInsnClasses.begin(),
+ CE = allInsnClasses.end(); CI != CE; ++CI) {
+ unsigned InsnClass = *CI;
+
+ std::set<unsigned> NewStateResources;
+ //
+ // If we haven't already created a transition for this input
+ // and the state can accommodate this InsnClass, create a transition.
+ //
+ if (!D.getTransition(current, InsnClass) &&
+ current->canAddInsnClass(InsnClass, NewStateResources)) {
+ State *NewState = NULL;
+
+ //
+ // If we have seen this state before, then do not create a new state.
+ //
+ //
+ std::map<std::set<unsigned>, State*>::iterator VI;
+ if ((VI = Visited.find(NewStateResources)) != Visited.end())
+ NewState = VI->second;
+ else {
+ NewState = new State;
+ NewState->stateInfo = NewStateResources;
+ D.addState(NewState);
+ Visited[NewStateResources] = NewState;
+ WorkList.push_back(NewState);
+ }
+
+ Transition *NewTransition = new Transition(current, InsnClass,
+ NewState);
+ D.addTransition(NewTransition);
+ }
+ }
+ }
+
+ // Print out the table.
+ D.writeTableAndAPI(OS, TargetName);
+}
diff --git a/utils/TableGen/DFAPacketizerEmitter.h b/utils/TableGen/DFAPacketizerEmitter.h
new file mode 100644
index 0000000..8f47dde
--- /dev/null
+++ b/utils/TableGen/DFAPacketizerEmitter.h
@@ -0,0 +1,54 @@
+//===- DFAPacketizerEmitter.h - Packetization DFA for a VLIW machine-------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class parses the Schedule.td file and produces an API that can be used
+// to reason about whether an instruction can be added to a packet on a VLIW
+// architecture. The class internally generates a deterministic finite
+// automaton (DFA) that models all possible mappings of machine instructions
+// to functional units as instructions are added to a packet.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <map>
+#include <string>
+
+namespace llvm {
+//
+// class DFAGen: class that generates and prints out the DFA for resource
+// tracking.
+//
+class DFAGen : public TableGenBackend {
+private:
+ std::string TargetName;
+ //
+ // allInsnClasses is the set of all possible resources consumed by an
+ // InstrStage.
+ //
+ DenseSet<unsigned> allInsnClasses;
+ RecordKeeper &Records;
+
+public:
+ DFAGen(RecordKeeper &R);
+
+ //
+ // collectAllInsnClasses: Populate allInsnClasses which is a set of units
+ // used in each stage.
+ //
+ void collectAllInsnClasses(const std::string &Name,
+ Record *ItinData,
+ unsigned &NStages,
+ raw_ostream &OS);
+
+ void run(raw_ostream &OS);
+};
+}
diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp
index 1953dad..6c3cae2 100644
--- a/utils/TableGen/EDEmitter.cpp
+++ b/utils/TableGen/EDEmitter.cpp
@@ -576,6 +576,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
REG("VecListThreeD");
REG("VecListFourD");
REG("VecListTwoQ");
+ REG("VecListOneDAllLanes");
+ REG("VecListTwoDAllLanes");
IMM("i32imm");
IMM("i32imm_hilo16");
@@ -608,6 +610,14 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
IMM("nImmSplatI64");
IMM("nImmVMOVI32");
IMM("nImmVMOVF32");
+ IMM("imm8");
+ IMM("imm16");
+ IMM("imm32");
+ IMM("imm1_7");
+ IMM("imm1_15");
+ IMM("imm1_31");
+ IMM("imm0_1");
+ IMM("imm0_3");
IMM("imm0_7");
IMM("imm0_15");
IMM("imm0_255");
@@ -746,7 +756,7 @@ static void ARMPopulateOperands(
errs() << "Operand type: " << rec.getName() << '\n';
errs() << "Operand name: " << operandInfo.Name << '\n';
errs() << "Instruction name: " << inst.TheDef->getName() << '\n';
- llvm_unreachable("Unhandled type");
+ throw("Unhandled type in EDEmitter");
}
}
}
diff --git a/utils/TableGen/LLVMBuild.txt b/utils/TableGen/LLVMBuild.txt
index b2a8ac6..b0081eb 100644
--- a/utils/TableGen/LLVMBuild.txt
+++ b/utils/TableGen/LLVMBuild.txt
@@ -20,4 +20,3 @@ type = BuildTool
name = tblgen
parent = BuildTools
required_libraries = Support TableGen
-
diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp
index 3a6ff4e..34cd9a9 100644
--- a/utils/TableGen/SubtargetEmitter.cpp
+++ b/utils/TableGen/SubtargetEmitter.cpp
@@ -711,9 +711,13 @@ void SubtargetEmitter::run(raw_ostream &OS) {
std::string ClassName = Target + "GenSubtargetInfo";
OS << "namespace llvm {\n";
+ OS << "class DFAPacketizer;\n";
OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
<< " explicit " << ClassName << "(StringRef TT, StringRef CPU, "
<< "StringRef FS);\n"
+ << "public:\n"
+ << " DFAPacketizer *createDFAPacketizer(const InstrItineraryData *IID)"
+ << " const;\n"
<< "};\n";
OS << "} // End llvm namespace \n";
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 12ebc57..3899a41 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -16,6 +16,7 @@
#include "CallingConvEmitter.h"
#include "CodeEmitterGen.h"
#include "DAGISelEmitter.h"
+#include "DFAPacketizerEmitter.h"
#include "DisassemblerEmitter.h"
#include "EDEmitter.h"
#include "FastISelEmitter.h"
@@ -47,6 +48,7 @@ enum ActionType {
GenPseudoLowering,
GenCallingConv,
GenDAGISel,
+ GenDFAPacketizer,
GenFastISel,
GenSubtarget,
GenIntrinsic,
@@ -79,6 +81,8 @@ namespace {
"Generate assembly instruction matcher"),
clEnumValN(GenDAGISel, "gen-dag-isel",
"Generate a DAG instruction selector"),
+ clEnumValN(GenDFAPacketizer, "gen-dfa-packetizer",
+ "Generate DFA Packetizer for VLIW targets"),
clEnumValN(GenFastISel, "gen-fast-isel",
"Generate a \"fast\" instruction selector"),
clEnumValN(GenSubtarget, "gen-subtarget",
@@ -134,6 +138,9 @@ public:
case GenDAGISel:
DAGISelEmitter(Records).run(OS);
break;
+ case GenDFAPacketizer:
+ DFAGen(Records).run(OS);
+ break;
case GenFastISel:
FastISelEmitter(Records).run(OS);
break;
diff --git a/utils/buildit/GNUmakefile b/utils/buildit/GNUmakefile
index 470ee76..a362fa6 100644
--- a/utils/buildit/GNUmakefile
+++ b/utils/buildit/GNUmakefile
@@ -32,7 +32,7 @@ DSTROOT = $(OBJROOT)/../dst
#######################################################################
-PREFIX = /Developer/usr/local
+PREFIX = /usr/local
# Unless assertions are forced on in the GMAKE command line, disable them.
ifndef ENABLE_ASSERTIONS
diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py
index f5f7c19..4b2d626 100644
--- a/utils/lit/lit/TestRunner.py
+++ b/utils/lit/lit/TestRunner.py
@@ -23,6 +23,43 @@ kUseCloseFDs = not kIsWindows
# Use temporary files to replace /dev/null on Windows.
kAvoidDevNull = kIsWindows
+def RemoveForce(f):
+ try:
+ os.remove(f)
+ except OSError:
+ pass
+
+def WinRename(f_o, f_n):
+ import time
+ retry_cnt = 256
+ while (True):
+ try:
+ os.rename(f_o, f_n)
+ break
+ except WindowsError, (winerror, strerror):
+ retry_cnt = retry_cnt - 1
+ if retry_cnt <= 0:
+ raise
+ elif winerror == 32: # ERROR_SHARING_VIOLATION
+ time.sleep(0.01)
+ else:
+ raise
+
+def WinWaitReleased(f):
+ import random
+ t = "%s%06d" % (f, random.randint(0, 999999))
+ RemoveForce(t)
+ try:
+ WinRename(f, t) # rename
+ WinRename(t, f) # restore
+ except WindowsError, (winerror, strerror):
+ if winerror in (2, 3):
+ # 2: ERROR_FILE_NOT_FOUND
+ # 3: ERROR_PATH_NOT_FOUND
+ pass
+ else:
+ raise
+
def executeCommand(command, cwd=None, env=None):
p = subprocess.Popen(command, cwd=cwd,
stdin=subprocess.PIPE,
@@ -68,6 +105,7 @@ def executeShCmd(cmd, cfg, cwd, results):
input = subprocess.PIPE
stderrTempFiles = []
opened_files = []
+ written_files = []
named_temp_files = []
# To avoid deadlock, we use a single stderr stream for piped
# output. This is null until we have seen some output using
@@ -124,6 +162,8 @@ def executeShCmd(cmd, cfg, cwd, results):
if r[1] == 'a':
r[2].seek(0, 2)
opened_files.append(r[2])
+ if r[1] in 'aw':
+ written_files.append(r[0])
result = r[2]
final_redirects.append(result)
@@ -224,12 +264,14 @@ def executeShCmd(cmd, cfg, cwd, results):
else:
exitCode = res
+ # Make sure written_files is released by other (child) processes.
+ if (kIsWindows):
+ for f in written_files:
+ WinWaitReleased(f)
+
# Remove any named temporary files we created.
for f in named_temp_files:
- try:
- os.remove(f)
- except OSError:
- pass
+ RemoveForce(f)
if cmd.negate:
exitCode = not exitCode
diff --git a/utils/llvm-build/llvmbuild/componentinfo.py b/utils/llvm-build/llvmbuild/componentinfo.py
index b9a2d4f..230ae21 100644
--- a/utils/llvm-build/llvmbuild/componentinfo.py
+++ b/utils/llvm-build/llvmbuild/componentinfo.py
@@ -42,6 +42,13 @@ class ComponentInfo(object):
self.parent_instance = None
self.children = []
+ # The original source path.
+ self._source_path = None
+
+ # A flag to mark "special" components which have some amount of magic
+ # handling (generally based on command line options).
+ self._is_special_group = False
+
def set_parent_instance(self, parent):
assert parent.name == self.parent, "Unexpected parent!"
self.parent_instance = parent
@@ -138,6 +145,23 @@ class LibraryComponentInfo(ComponentInfo):
def get_library_name(self):
return self.library_name or self.name
+ def get_prefixed_library_name(self):
+ """
+ get_prefixed_library_name() -> str
+
+ Return the library name prefixed by the project name. This is generally
+ what the library name will be on disk.
+ """
+
+ basename = self.get_library_name()
+
+ # FIXME: We need to get the prefix information from an explicit project
+ # object, or something.
+ if basename in ('gtest', 'gtest_main'):
+ return basename
+
+ return 'LLVM%s' % basename
+
def get_llvmconfig_component_name(self):
return self.get_library_name().lower()
@@ -177,7 +201,7 @@ class LibraryGroupComponentInfo(ComponentInfo):
print >>result, 'type = %s' % self.type_name
print >>result, 'name = %s' % self.name
print >>result, 'parent = %s' % self.parent
- if self.required_libraries:
+ if self.required_libraries and not self._is_special_group:
print >>result, 'required_libraries = %s' % ' '.join(
self.required_libraries)
if self.add_to_library_groups:
@@ -357,6 +381,16 @@ def load_from_path(path, subpath):
parser = ConfigParser.RawConfigParser()
parser.read(path)
+ # Extract the common section.
+ if parser.has_section("common"):
+ common = IniFormatParser(parser.items("common"))
+ parser.remove_section("common")
+ else:
+ common = IniFormatParser({})
+
+ return common, _read_components_from_parser(parser, path, subpath)
+
+def _read_components_from_parser(parser, path, subpath):
# We load each section which starts with 'component' as a distinct component
# description (so multiple components can be described in one file).
for section in parser.sections():
@@ -390,4 +424,5 @@ def load_from_path(path, subpath):
fatal("unable to load component %r in %r: %s" % (
section, path, e.message))
+ info._source_path = path
yield info
diff --git a/utils/llvm-build/llvmbuild/main.py b/utils/llvm-build/llvmbuild/main.py
index 21cf392..36bca87 100644
--- a/utils/llvm-build/llvmbuild/main.py
+++ b/utils/llvm-build/llvmbuild/main.py
@@ -1,3 +1,4 @@
+import StringIO
import os
import sys
@@ -63,31 +64,25 @@ def make_install_dir(path):
class LLVMProjectInfo(object):
@staticmethod
def load_infos_from_path(llvmbuild_source_root):
- # FIXME: Implement a simple subpath file list cache, so we don't restat
- # directories we have already traversed.
+ def recurse(subpath):
+ # Load the LLVMBuild file.
+ llvmbuild_path = os.path.join(llvmbuild_source_root + subpath,
+ 'LLVMBuild.txt')
+ if not os.path.exists(llvmbuild_path):
+ fatal("missing LLVMBuild.txt file at: %r" % (llvmbuild_path,))
+
+ # Parse the components from it.
+ common,info_iter = componentinfo.load_from_path(llvmbuild_path,
+ subpath)
+ for info in info_iter:
+ yield info
- # First, discover all the LLVMBuild.txt files.
- #
- # FIXME: We would like to use followlinks=True here, but that isn't
- # compatible with Python 2.4. Instead, we will either have to special
- # case projects we would expect to possibly be linked to, or implement
- # our own walk that can follow links. For now, it doesn't matter since
- # we haven't picked up the LLVMBuild system in any other LLVM projects.
- for dirpath,dirnames,filenames in os.walk(llvmbuild_source_root):
- # If there is no LLVMBuild.txt file in a directory, we don't recurse
- # past it. This is a simple way to prune our search, although it
- # makes it easy for users to add LLVMBuild.txt files in places they
- # won't be seen.
- if 'LLVMBuild.txt' not in filenames:
- del dirnames[:]
- continue
+ # Recurse into the specified subdirectories.
+ for subdir in common.get_list("subdirectories"):
+ for item in recurse(os.path.join(subpath, subdir)):
+ yield item
- # Otherwise, load the LLVMBuild file in this directory.
- assert dirpath.startswith(llvmbuild_source_root)
- subpath = '/' + dirpath[len(llvmbuild_source_root)+1:]
- llvmbuild_path = os.path.join(dirpath, 'LLVMBuild.txt')
- for info in componentinfo.load_from_path(llvmbuild_path, subpath):
- yield info
+ return recurse("/")
@staticmethod
def load_from_path(source_root, llvmbuild_source_root):
@@ -213,14 +208,45 @@ class LLVMProjectInfo(object):
info_basedir[ci.subpath] = info_basedir.get(ci.subpath, []) + [ci]
+ # Compute the list of subdirectories to scan.
+ subpath_subdirs = {}
+ for ci in self.component_infos:
+ # Ignore root components.
+ if ci.subpath == '/':
+ continue
+
+ # Otherwise, append this subpath to the parent list.
+ parent_path = os.path.dirname(ci.subpath)
+ subpath_subdirs[parent_path] = parent_list = subpath_subdirs.get(
+ parent_path, set())
+ parent_list.add(os.path.basename(ci.subpath))
+
# Generate the build files.
for subpath, infos in info_basedir.items():
# Order the components by name to have a canonical ordering.
infos.sort(key = lambda ci: ci.name)
# Format the components into llvmbuild fragments.
- fragments = filter(None, [ci.get_llvmbuild_fragment()
- for ci in infos])
+ fragments = []
+
+ # Add the common fragments.
+ subdirectories = subpath_subdirs.get(subpath)
+ if subdirectories:
+ fragment = """\
+subdirectories = %s
+""" % (" ".join(sorted(subdirectories)),)
+ fragments.append(("common", fragment))
+
+ # Add the component fragments.
+ num_common_fragments = len(fragments)
+ for ci in infos:
+ fragment = ci.get_llvmbuild_fragment()
+ if fragment is None:
+ continue
+
+ name = "component_%d" % (len(fragments) - num_common_fragments)
+ fragments.append((name, fragment))
+
if not fragments:
continue
@@ -231,7 +257,22 @@ class LLVMProjectInfo(object):
if not os.path.exists(directory_path):
os.makedirs(directory_path)
- # Create the LLVMBuild file.
+ # In an effort to preserve comments (which aren't parsed), read in
+ # the original file and extract the comments. We only know how to
+ # associate comments that prefix a section name.
+ f = open(infos[0]._source_path)
+ comments_map = {}
+ comment_block = ""
+ for ln in f:
+ if ln.startswith(';'):
+ comment_block += ln
+ elif ln.startswith('[') and ln.endswith(']\n'):
+ comments_map[ln[1:-2]] = comment_block
+ else:
+ comment_block = ""
+ f.close()
+
+ # Create the LLVMBuild fil[e.
file_path = os.path.join(directory_path, 'LLVMBuild.txt')
f = open(file_path, "w")
@@ -259,10 +300,16 @@ class LLVMProjectInfo(object):
;===------------------------------------------------------------------------===;
""" % header_string
- for i,fragment in enumerate(fragments):
- print >>f, '[component_%d]' % i
+ # Write out each fragment.each component fragment.
+ for name,fragment in fragments:
+ comment = comments_map.get(name)
+ if comment is not None:
+ f.write(comment)
+ print >>f, "[%s]" % name
f.write(fragment)
- print >>f
+ if fragment is not fragments[-1][1]:
+ print >>f
+
f.close()
def write_library_table(self, output_path):
@@ -282,7 +329,7 @@ class LLVMProjectInfo(object):
# Get the library name, or None for LibraryGroups.
if c.type_name == 'Library':
- library_name = c.get_library_name()
+ library_name = c.get_prefixed_library_name()
else:
library_name = None
@@ -344,9 +391,7 @@ class LLVMProjectInfo(object):
if library_name is None:
library_name_as_cstr = '0'
else:
- # If we had a project level component, we could derive the
- # library prefix.
- library_name_as_cstr = '"libLLVM%s.a"' % library_name
+ library_name_as_cstr = '"lib%s.a"' % library_name
print >>f, ' { "%s", %s, { %s } },' % (
name, library_name_as_cstr,
', '.join('"%s"' % dep
@@ -354,6 +399,37 @@ class LLVMProjectInfo(object):
print >>f, '};'
f.close()
+ def get_required_libraries_for_component(self, ci, traverse_groups = False):
+ """
+ get_required_libraries_for_component(component_info) -> iter
+
+ Given a Library component info descriptor, return an iterator over all
+ of the directly required libraries for linking with this component. If
+ traverse_groups is True, then library and target groups will be
+ traversed to include their required libraries.
+ """
+
+ assert ci.type_name in ('Library', 'LibraryGroup', 'TargetGroup')
+
+ for name in ci.required_libraries:
+ # Get the dependency info.
+ dep = self.component_info_map[name]
+
+ # If it is a library, yield it.
+ if dep.type_name == 'Library':
+ yield dep
+ continue
+
+ # Otherwise if it is a group, yield or traverse depending on what
+ # was requested.
+ if dep.type_name in ('LibraryGroup', 'TargetGroup'):
+ if not traverse_groups:
+ yield dep
+ continue
+
+ for res in self.get_required_libraries_for_component(dep, True):
+ yield res
+
def get_fragment_dependencies(self):
"""
get_fragment_dependencies() -> iter
@@ -366,9 +442,15 @@ class LLVMProjectInfo(object):
# Construct a list of all the dependencies of the Makefile fragment
# itself. These include all the LLVMBuild files themselves, as well as
# all of our own sources.
+ #
+ # Many components may come from the same file, so we make sure to unique
+ # these.
+ build_paths = set()
for ci in self.component_infos:
- yield os.path.join(self.source_root, ci.subpath[1:],
- 'LLVMBuild.txt')
+ p = os.path.join(self.source_root, ci.subpath[1:], 'LLVMBuild.txt')
+ if p not in build_paths:
+ yield p
+ build_paths.add(p)
# Gather the list of necessary sources by just finding all loaded
# modules that are inside the LLVM source tree.
@@ -447,6 +529,24 @@ configure_file(\"%s\"
${CMAKE_CURRENT_BINARY_DIR}/DummyConfigureOutput)""" % (
cmake_quote_path(dep),)
+ # Write the properties we use to encode the required library dependency
+ # information in a form CMake can easily use directly.
+ print >>f, """
+# Explicit library dependency information.
+#
+# The following property assignments effectively create a map from component
+# names to required libraries, in a way that is easily accessed from CMake."""
+ for ci in self.ordered_component_infos:
+ # We only write the information for libraries currently.
+ if ci.type_name != 'Library':
+ continue
+
+ print >>f, """\
+set_property(GLOBAL PROPERTY LLVMBUILD_LIB_DEPS_%s %s)""" % (
+ ci.get_prefixed_library_name(), " ".join(sorted(
+ dep.get_prefixed_library_name()
+ for dep in self.get_required_libraries_for_component(ci))))
+
f.close()
def write_make_fragment(self, output_path):
@@ -590,6 +690,7 @@ def add_magic_target_components(parser, project, opts):
fatal("special component %r must have empty %r list" % (
name, 'add_to_library_groups'))
+ info._is_special_group = True
return info
info_map = dict((ci.name, ci) for ci in project.component_infos)
diff --git a/utils/release/tag.sh b/utils/release/tag.sh
index d2d9911..80da47a 100755
--- a/utils/release/tag.sh
+++ b/utils/release/tag.sh
@@ -25,6 +25,7 @@ function usage() {
echo " "
echo " -release <num> The version number of the release"
echo " -rc <num> The release candidate number"
+ echo " -final Tag final release candidate"
}
function tag_version() {
@@ -45,10 +46,10 @@ function tag_release_candidate() {
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
- if ! svn ls $base_url/$proj/tags/RELEASE_$release/rc$rc > /dev/null 2>&1 ; then
+ if ! svn ls $base_url/$proj/tags/RELEASE_$release/$rc > /dev/null 2>&1 ; then
svn copy -m "Creating release candidate $rc from release_$release branch" \
$base_url/$proj/branches/release_$release \
- $base_url/$proj/tags/RELEASE_$release/rc$rc
+ $base_url/$proj/tags/RELEASE_$release/$rc
fi
done
set +x
@@ -62,7 +63,10 @@ while [ $# -gt 0 ]; do
;;
-rc | --rc )
shift
- rc=$1
+ rc="rc$1"
+ ;;
+ -final | --final )
+ rc="final"
;;
-h | --help | -help )
usage
diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh
index c0f283d..6ec2861 100755
--- a/utils/release/test-release.sh
+++ b/utils/release/test-release.sh
@@ -42,6 +42,7 @@ function usage() {
echo ""
echo " -release X.Y The release number to test."
echo " -rc NUM The pre-release candidate number."
+ echo " -final The final release candidate."
echo " -j NUM Number of compile jobs to run. [default: 3]"
echo " -build-dir DIR Directory to perform testing in. [default: pwd]"
echo " -no-checkout Don't checkout the sources from SVN."
@@ -64,7 +65,10 @@ while [ $# -gt 0 ]; do
;;
-rc | --rc | -RC | --RC )
shift
- RC=$1
+ RC="rc$1"
+ ;;
+ -final | --final )
+ RC=final
;;
-j* )
NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`"
@@ -142,7 +146,7 @@ if [ -z "$NumJobs" ]; then
fi
# Go to the build directory (may be different from CWD)
-BuildDir=$BuildDir/rc$RC
+BuildDir=$BuildDir/$RC
mkdir -p $BuildDir
cd $BuildDir
@@ -177,7 +181,7 @@ function check_valid_urls() {
for proj in $projects ; do
echo "# Validating $proj SVN URL"
- if ! svn ls $Base_url/$proj/tags/RELEASE_$Release_no_dot/rc$RC > /dev/null 2>&1 ; then
+ if ! svn ls $Base_url/$proj/tags/RELEASE_$Release_no_dot/$RC > /dev/null 2>&1 ; then
echo "llvm $Release release candidate $RC doesn't exist!"
exit 1
fi
@@ -190,7 +194,7 @@ function export_sources() {
for proj in $projects ; do
echo "# Exporting $proj $Release-RC$RC sources"
- if ! svn export -q $Base_url/$proj/tags/RELEASE_$Release_no_dot/rc$RC $proj.src ; then
+ if ! svn export -q $Base_url/$proj/tags/RELEASE_$Release_no_dot/$RC $proj.src ; then
echo "error: failed to export $proj project"
exit 1
fi
@@ -238,7 +242,7 @@ function configure_llvmCore() {
echo "# Using C++ compiler: $cxx_compiler"
cd $ObjDir
- echo "# Configuring llvm $Release-rc$RC $Flavor"
+ echo "# Configuring llvm $Release-$RC $Flavor"
echo "# $BuildDir/llvm.src/configure --prefix=$InstallDir \
--enable-optimized=$Optimized \
--enable-assertions=$Assertions"
@@ -262,12 +266,12 @@ function build_llvmCore() {
fi
cd $ObjDir
- echo "# Compiling llvm $Release-rc$RC $Flavor"
+ echo "# Compiling llvm $Release-$RC $Flavor"
echo "# ${MAKE} -j $NumJobs VERBOSE=1 $ExtraOpts"
${MAKE} -j $NumJobs VERBOSE=1 $ExtraOpts \
2>&1 | tee $LogDir/llvm.make-Phase$Phase-$Flavor.log
- echo "# Installing llvm $Release-rc$RC $Flavor"
+ echo "# Installing llvm $Release-$RC $Flavor"
echo "# ${MAKE} install"
${MAKE} install \
2>&1 | tee $LogDir/llvm.install-Phase$Phase-$Flavor.log
@@ -285,7 +289,7 @@ function build_dragonegg() {
echo "# Targeted compiler: $gcc_compiler"
cd $DragonEggObjDir
- echo "# Compiling phase $Phase dragonegg $Release-rc$RC $Flavor"
+ echo "# Compiling phase $Phase dragonegg $Release-$RC $Flavor"
echo -n "# CXX=$cxx_compiler TOP_DIR=$TOP_DIR GCC=$gcc_compiler "
echo -n "LLVM_CONFIG=$LLVM_CONFIG ${MAKE} -f $TOP_DIR/Makefile "
echo "-j $NumJobs VERBOSE=1"
@@ -331,7 +335,7 @@ for Flavor in $Flavors ; do
echo ""
echo ""
echo "********************************************************************************"
- echo " Release: $Release-rc$RC"
+ echo " Release: $Release-$RC"
echo " Build: $Flavor"
echo " System Info: "
echo " `uname -a`"
@@ -341,21 +345,21 @@ for Flavor in $Flavors ; do
c_compiler="$CC"
cxx_compiler="$CXX"
- llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-rc$RC.obj
- llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-rc$RC.install
- dragonegg_phase1_objdir=$BuildDir/Phase1/$Flavor/DragonEgg-$Release-rc$RC.obj
+ llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.obj
+ llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.install
+ dragonegg_phase1_objdir=$BuildDir/Phase1/$Flavor/DragonEgg-$Release-$RC.obj
- llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-rc$RC.obj
- llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-rc$RC.install
- llvmCore_de_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-rc$RC.obj
- llvmCore_de_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-rc$RC.install
- dragonegg_phase2_objdir=$BuildDir/Phase2/$Flavor/DragonEgg-$Release-rc$RC.obj
+ llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.obj
+ llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.install
+ llvmCore_de_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj
+ llvmCore_de_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.install
+ dragonegg_phase2_objdir=$BuildDir/Phase2/$Flavor/DragonEgg-$Release-$RC.obj
- llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-rc$RC.obj
- llvmCore_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-rc$RC.install
- llvmCore_de_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-rc$RC.obj
- llvmCore_de_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-rc$RC.install
- dragonegg_phase3_objdir=$BuildDir/Phase3/$Flavor/DragonEgg-$Release-rc$RC.obj
+ llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.obj
+ llvmCore_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.install
+ llvmCore_de_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj
+ llvmCore_de_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.install
+ dragonegg_phase3_objdir=$BuildDir/Phase3/$Flavor/DragonEgg-$Release-$RC.obj
rm -rf $llvmCore_phase1_objdir
rm -rf $llvmCore_phase1_installdir
@@ -494,7 +498,7 @@ for Flavor in $Flavors ; do
test_llvmCore 1 $Flavor $llvmCore_phase1_objdir
fi
done
-) 2>&1 | tee $LogDir/testing.$Release-rc$RC.log
+) 2>&1 | tee $LogDir/testing.$Release-$RC.log
set +e
diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt
index d882de2..73491f0 100644
--- a/utils/unittest/CMakeLists.txt
+++ b/utils/unittest/CMakeLists.txt
@@ -40,11 +40,3 @@ add_llvm_library(gtest
add_llvm_library(gtest_main
UnitTestMain/TestMain.cpp
)
-
-add_llvm_library_dependencies(gtest
- LLVMSupport
- )
-
-add_llvm_library_dependencies(gtest_main
- gtest
- )
diff --git a/utils/unittest/UnitTestMain/Makefile b/utils/unittest/UnitTestMain/Makefile
index 3082779..7bcb724 100644
--- a/utils/unittest/UnitTestMain/Makefile
+++ b/utils/unittest/UnitTestMain/Makefile
@@ -11,7 +11,7 @@ LEVEL = ../../..
include $(LEVEL)/Makefile.config
-LIBRARYNAME = UnitTestMain
+LIBRARYNAME = gtest_main
BUILD_ARCHIVE = 1
REQUIRES_RTTI = 1
diff --git a/utils/unittest/googletest/Makefile b/utils/unittest/googletest/Makefile
index 21b29ff..22c8f36 100644
--- a/utils/unittest/googletest/Makefile
+++ b/utils/unittest/googletest/Makefile
@@ -11,7 +11,7 @@ LEVEL := ../../..
include $(LEVEL)/Makefile.config
-LIBRARYNAME = GoogleTest
+LIBRARYNAME = gtest
BUILD_ARCHIVE = 1
REQUIRES_RTTI = 1