diff --git a/test/LLVMC/together1.c b/test/LLVMC/together.c similarity index 100% rename from test/LLVMC/together1.c rename to test/LLVMC/together.c diff --git a/test/LLVMC/together.cpp b/test/LLVMC/together.cpp index 62ff821154d..97df1937524 100644 --- a/test/LLVMC/together.cpp +++ b/test/LLVMC/together.cpp @@ -1,6 +1,5 @@ // Check that we can compile files of different types together. -// TOFIX: compiling files with same names should work. -// RUN: llvmc2 %s %p/together1.c -o %t +// RUN: llvmc2 %s %p/together.c -o %t // RUN: ./%t | grep hello extern "C" void test(); diff --git a/tools/llvmc2/Action.cpp b/tools/llvmc2/Action.cpp index fdbfb886113..3d61d37368f 100644 --- a/tools/llvmc2/Action.cpp +++ b/tools/llvmc2/Action.cpp @@ -34,6 +34,7 @@ namespace { if (!prog.canExecute()) throw std::runtime_error("Program '" + name + "' is not executable."); + // Build the command line vector and redirects. const sys::Path* redirects[3] = {0,0,0}; sys::Path stdout_redirect; @@ -54,6 +55,7 @@ namespace { } argv.push_back(0); // null terminate list. + // Invoke the program. return sys::Program::ExecuteAndWait(prog, &argv[0], 0, &redirects[0]); } diff --git a/tools/llvmc2/CompilationGraph.cpp b/tools/llvmc2/CompilationGraph.cpp index 817e0fb4c6b..ed03f5856ec 100644 --- a/tools/llvmc2/CompilationGraph.cpp +++ b/tools/llvmc2/CompilationGraph.cpp @@ -121,42 +121,50 @@ void CompilationGraph::insertEdge(const std::string& A, Edge* E) { B.IncrInEdges(); } +// Make a temporary file named like BaseName-RandomDigits.Suffix +sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, + const std::string& Suffix) { + sys::Path Out = TempDir; + Out.appendComponent(BaseName); + Out.appendSuffix(Suffix); + Out.makeUnique(true, NULL); + Out.eraseFromDisk(); + return Out; +} + // Pass input file through the chain until we bump into a Join node or // a node that says that it is the last. -const JoinTool* -CompilationGraph::PassThroughGraph (sys::Path& In, - const Node* StartNode, - const sys::Path& TempDir) const { +void CompilationGraph::PassThroughGraph (const sys::Path& InFile, + const Node* StartNode, + const sys::Path& TempDir) const { bool Last = false; + sys::Path In = InFile; const Node* CurNode = StartNode; - JoinTool* ret = 0; while(!Last) { sys::Path Out; Tool* CurTool = CurNode->ToolPtr.getPtr(); if (CurTool->IsJoin()) { - ret = &dynamic_cast(*CurTool); - ret->AddToJoinList(In); + JoinTool& JT = dynamic_cast(*CurTool); + JT.AddToJoinList(In); break; } - // Is this the last tool? + // Since toolchains do not have to end with a Join node, we should + // check if this Node is the last. if (!CurNode->HasChildren() || CurTool->IsLast()) { - // Check if the first tool is also the last - if (Out.empty()) + if (!OutputFilename.empty()) { + Out.set(OutputFilename); + } + else { Out.set(In.getBasename()); - else - Out.appendComponent(In.getBasename()); - Out.appendSuffix(CurTool->OutputSuffix()); + Out.appendSuffix(CurTool->OutputSuffix()); + } Last = true; } else { - Out = TempDir; - Out.appendComponent(In.getBasename()); - Out.appendSuffix(CurTool->OutputSuffix()); - Out.makeUnique(true, NULL); - Out.eraseFromDisk(); + Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix()); } if (CurTool->GenerateAction(In, Out).Execute() != 0) @@ -166,8 +174,6 @@ CompilationGraph::PassThroughGraph (sys::Path& In, CurNode->Name())->ToolName()); In = Out; Out.clear(); } - - return ret; } // Sort the nodes in topological order. @@ -215,7 +221,6 @@ const Node* CompilationGraph::FindToolChain(const sys::Path& In) const { return &getNode(ChooseEdge(TV)->ToolName()); } -// TOFIX: merge some parts with PassThroughGraph. // Build the targets. Command-line options are passed through // temporary variables. int CompilationGraph::Build (const sys::Path& TempDir) { @@ -243,10 +248,12 @@ int CompilationGraph::Build (const sys::Path& TempDir) { JoinTool* JT = &dynamic_cast(*CurNode->ToolPtr.getPtr()); bool IsLast = false; - // Has files pending? + // Are there any files to be joined? if (JT->JoinListEmpty()) continue; + // Is this the last tool in the chain? + // NOTE: we can process several chains in parallel. if (!CurNode->HasChildren() || JT->IsLast()) { if (OutputFilename.empty()) { Out.set("a"); @@ -257,11 +264,7 @@ int CompilationGraph::Build (const sys::Path& TempDir) { IsLast = true; } else { - Out = TempDir; - Out.appendComponent("tmp"); - Out.appendSuffix(JT->OutputSuffix()); - Out.makeUnique(true, NULL); - Out.eraseFromDisk(); + Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix()); } if (JT->GenerateAction(Out).Execute() != 0) diff --git a/tools/llvmc2/CompilationGraph.h b/tools/llvmc2/CompilationGraph.h index 7d949e6d4f4..72cde9a9e24 100644 --- a/tools/llvmc2/CompilationGraph.h +++ b/tools/llvmc2/CompilationGraph.h @@ -28,7 +28,7 @@ namespace llvmc { - // An edge in the graph. + // An edge of the compilation graph. class Edge : public llvm::RefCountedBaseVPTR { public: Edge(const std::string& T) : ToolName_(T) {} @@ -41,7 +41,7 @@ namespace llvmc { std::string ToolName_; }; - // Edges with no properties are instances of this class. + // Edges that have no properties are instances of this class. class SimpleEdge : public Edge { public: SimpleEdge(const std::string& T) : Edge(T) {} @@ -49,8 +49,9 @@ namespace llvmc { bool isDefault() const { return true;} }; - // A node in the graph. + // A node of the compilation graph. struct Node { + // A Node holds a list of the outward edges. typedef llvm::SmallVector, 3> container_type; typedef container_type::iterator iterator; typedef container_type::const_iterator const_iterator; @@ -74,10 +75,9 @@ namespace llvmc { void AddEdge(Edge* E) { OutEdges.push_back(llvm::IntrusiveRefCntPtr(E)); } - // Inward edge counter. Used by Build() to implement topological - // sort. - // TOTHINK: Move the counter back into Tool classes? Makes us more - // const-correct. + // Inward edge counter. Used to implement topological sort. + // TOTHINK: Move the mutable counter back into Tool classes? Makes + // us more const-correct. void IncrInEdges() { ++InEdges; } void DecrInEdges() { --InEdges; } bool HasNoInEdges() const { return InEdges == 0; } @@ -85,11 +85,12 @@ namespace llvmc { // Needed to implement NodeChildIterator/GraphTraits CompilationGraph* OwningGraph; // The corresponding Tool. - // WARNING: For the root node, ToolPtr is NULL. + // WARNING: ToolPtr can be NULL (for the root node). llvm::IntrusiveRefCntPtr ToolPtr; // Links to children. container_type OutEdges; - // Number of parents. Used for topological sorting. + // Inward edge counter. Updated in + // CompilationGraph::insertEdge(). Used for topological sorting. unsigned InEdges; }; @@ -99,8 +100,9 @@ namespace llvmc { class CompilationGraph { // Main data structure. typedef llvm::StringMap nodes_map_type; - // These are used to map from language names-> tools. (We can have - // several tools associated with each language name.) + // These are used to map from language names to tools. (We can + // have several tools associated with each language name, hence + // the need for a vector of Edges.) typedef llvm::SmallVector, 3> tools_vector_type; typedef llvm::StringMap tools_map_type; @@ -159,9 +161,8 @@ namespace llvmc { const tools_vector_type& getToolsVector(const std::string& LangName) const; // Pass the input file through the toolchain. - const JoinTool* PassThroughGraph (llvm::sys::Path& In, - const Node* StartNode, - const llvm::sys::Path& TempDir) const; + void PassThroughGraph (const llvm::sys::Path& In, const Node* StartNode, + const llvm::sys::Path& TempDir) const; // Find head of the toolchain corresponding to the given file. const Node* FindToolChain(const llvm::sys::Path& In) const; diff --git a/tools/llvmc2/Example.td b/tools/llvmc2/Example.td index 82d9da1515d..57629904d18 100644 --- a/tools/llvmc2/Example.td +++ b/tools/llvmc2/Example.td @@ -32,5 +32,7 @@ def CompilationGraph : CompilationGraph<[ Edge, Edge, - Edge + Edge, + + Edge ]>; diff --git a/tools/llvmc2/Tools.td b/tools/llvmc2/Tools.td index 67104ec2c73..64c59ffdeaf 100644 --- a/tools/llvmc2/Tools.td +++ b/tools/llvmc2/Tools.td @@ -11,19 +11,21 @@ // //===----------------------------------------------------------------------===// -// Open issue: should we use DAG lists in Tool specifications +// TOTHINK: Open issue: should we use DAG lists in Tool specifications // or change to something like + // def LLVMGccC : < Tool< // [ InLanguage<"c">, // PrefixListOption<"Wl", [UnpackValues, PropertyName, ...]> // ...] ? + // DAG lists look more aesthetically pleasing to me. def llvm_gcc_c : Tool< [(in_language "c"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "llvm-gcc -c $INFILE -o $OUTFILE -emit-llvm"), + (cmd_line "llvm-gcc -c -x c $INFILE -o $OUTFILE -emit-llvm"), (sink) ]>; @@ -31,7 +33,7 @@ def llvm_gcc_cpp : Tool< [(in_language "c++"), (out_language "llvm-bitcode"), (output_suffix "bc"), - (cmd_line "llvm-g++ -c $INFILE -o $OUTFILE -emit-llvm"), + (cmd_line "llvm-g++ -c -x c++ $INFILE -o $OUTFILE -emit-llvm"), (sink) ]>; @@ -61,7 +63,8 @@ def llvm_gcc_assembler : Tool< [(in_language "assembler"), (out_language "object-code"), (output_suffix "o"), - (cmd_line "llvm-gcc -c $INFILE -o $OUTFILE"), + (cmd_line "llvm-gcc -c -x assembler $INFILE -o $OUTFILE"), + (switch_option "c", (stop_compilation)), (prefix_list_option "Wa", (unpack_values), (help "pass options to assembler")) ]>; @@ -85,4 +88,5 @@ def LanguageMap : LanguageMap< LangToSuffixes<"llvm-assembler", ["ll"]>, LangToSuffixes<"llvm-bitcode", ["bc"]>, LangToSuffixes<"object-code", ["o"]>, - LangToSuffixes<"executable", ["out"]>]>; + LangToSuffixes<"executable", ["out"]> + ]>;