fix infinite recursion if a global's initializer references the global
[oota-llvm.git] / tools / lto2 / LTOCodeGenerator.cpp
index 795aca01f566baa1d8e48c1b6a96e146d5c39aad..13ba0db0f6da2a0f2f6417a522efb3d69abc97dd 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+#include "LTOModule.h"
+#include "LTOCodeGenerator.h"
+
+
 #include "llvm/Module.h"
 #include "llvm/PassManager.h"
 #include "llvm/Linker.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/ModuleProvider.h"
 #include "llvm/Bitcode/ReaderWriter.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/SystemUtils.h"
 #include "llvm/Support/Mangler.h"
 #include "llvm/Support/MemoryBuffer.h"
-#include "llvm/System/Program.h"
 #include "llvm/System/Signals.h"
 #include "llvm/Analysis/Passes.h"
 #include "llvm/Analysis/LoopPass.h"
 #include "llvm/Analysis/Verifier.h"
+#include "llvm/Analysis/LoadValueNumbering.h"
 #include "llvm/CodeGen/FileWriters.h"
-#include "llvm/Target/SubtargetFeature.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetAsmInfo.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Scalar.h"
-#include "llvm/Analysis/LoadValueNumbering.h"
-#include "llvm/Support/MathExtras.h"
 #include "llvm/Config/config.h"
 
-#include "LTOModule.h"
-#include "LTOCodeGenerator.h"
 
 #include <fstream>
 #include <unistd.h>
@@ -68,14 +65,16 @@ const char* LTOCodeGenerator::getVersionString()
 LTOCodeGenerator::LTOCodeGenerator() 
     : _linker("LinkTimeOptimizer", "ld-temp.o"), _target(NULL),
       _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false),
-      _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC)
+      _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC),
+      _nativeObjectFile(NULL)
 {
 
 }
 
 LTOCodeGenerator::~LTOCodeGenerator()
 {
-    // FIXME
+    delete _target;
+    delete _nativeObjectFile;
 }
 
 
@@ -151,9 +150,9 @@ bool LTOCodeGenerator::writeMergedModules(const char* path, std::string& errMsg)
 }
 
 
-void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg)
+const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg)
 {
-    // make unqiue temp .s file to put generated assembly code
+    // make unique temp .s file to put generated assembly code
     sys::Path uniqueAsmPath("lto-llvm.s");
     if ( uniqueAsmPath.createTemporaryFileOnDisk(true, &errMsg) )
         return NULL;
@@ -169,7 +168,7 @@ void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg)
         return NULL;
     }
     
-    // make unqiue temp .o file to put generated object file
+    // make unique temp .o file to put generated object file
     sys::PathWithStatus uniqueObjPath("lto-llvm.o");
     if ( uniqueObjPath.createTemporaryFileOnDisk(true, &errMsg) ) {
         if ( uniqueAsmPath.exists() )
@@ -179,46 +178,26 @@ void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg)
     sys::RemoveFileOnSignal(uniqueObjPath);
 
     // assemble the assembly code
-    void* buffer = NULL;
+    const std::string& uniqueObjStr = uniqueObjPath.toString();
     bool asmResult = this->assemble(uniqueAsmPath.toString(), 
-                                            uniqueObjPath.toString(), errMsg);
+                                                        uniqueObjStr, errMsg);
     if ( !asmResult ) {
+        // remove old buffer if compile() called twice
+        delete _nativeObjectFile;
+        
         // read .o file into memory buffer
-        const sys::FileStatus* objStatus;
-        objStatus = uniqueObjPath.getFileStatus(false, &errMsg);
-        if ( objStatus != NULL ) {
-            *length = objStatus->getSize();
-            // use malloc() because caller will own this buffer and free() it 
-            buffer = ::malloc(*length);
-            if ( buffer != NULL ) {
-                int fd = ::open(uniqueObjPath.c_str(), O_RDONLY, 0);
-                if ( fd != -1 ) {
-                    // read object file contents into buffer
-                    if ( ::read(fd, buffer, *length) != (ssize_t)*length ) {
-                        errMsg = "error reading object file";
-                        free(buffer);
-                        buffer = NULL;
-                    }
-                    close(fd);
-                }
-                else {
-                    errMsg = "error opening object file";
-                    free(buffer);
-                    buffer = NULL;
-                }
-            }
-            else {
-                errMsg = "error mallocing space for object file";
-            }
-        }
-        else {
-            errMsg = "error stat'ing object file";
-        }
+        _nativeObjectFile = MemoryBuffer::getFile(uniqueObjStr.c_str(),&errMsg);
     }
-    // clean up temp files
+
+    // remove temp files
     uniqueAsmPath.eraseFromDisk();
     uniqueObjPath.eraseFromDisk();
-    return buffer;
+
+    // return buffer, unless error
+    if ( _nativeObjectFile == NULL )
+        return NULL;
+    *length = _nativeObjectFile->getBufferSize();
+    return _nativeObjectFile->getBufferStart();
 }
 
 
@@ -361,6 +340,11 @@ bool LTOCodeGenerator::generateAssemblyCode(std::ostream& out, std::string& errM
     // Add an appropriate TargetData instance for this module...
     passes.add(new TargetData(*_target->getTargetData()));
     
+    // Propagate constants at call sites into the functions they call.  This
+    // opens opportunities for globalopt (and inlining) by substituting function
+    // pointers passed as arguments to direct uses of functions.  
+    passes.add(createIPSCCPPass());
+
     // Now that we internalized some globals, see if we can hack on them!
     passes.add(createGlobalOptimizerPass());
 
@@ -371,18 +355,17 @@ bool LTOCodeGenerator::generateAssemblyCode(std::ostream& out, std::string& errM
     // If the -s command line option was specified, strip the symbols out of the
     // resulting program to make it smaller.  -s is a GLD option that we are
     // supporting.
-    if( !llvm::ExceptionHandling ) {
-        // FIXME : This causes multiple nameless _.eh symbols on 
-        // darwin when EH is ON.
-        passes.add(createStripSymbolsPass());
-    }
+    passes.add(createStripSymbolsPass());
     
-    // Propagate constants at call sites into the functions they call.
-    passes.add(createIPConstantPropagationPass());
-
     // Remove unused arguments from functions...
     passes.add(createDeadArgEliminationPass());
 
+    // Reduce the code after globalopt and ipsccp.  Both can open up significant
+    // simplification opportunities, and both can propagate functions through
+    // function pointers.  When this happens, we often have to resolve varargs
+    // calls, etc, so let instcombine do this.
+    passes.add(createInstructionCombiningPass());
+
     passes.add(createFunctionInliningPass()); // Inline small functions
 
     passes.add(createPruneEHPass());            // Remove dead EH info
@@ -395,20 +378,22 @@ bool LTOCodeGenerator::generateAssemblyCode(std::ostream& out, std::string& errM
 
     // The IPO passes may leave cruft around.  Clean up after them.
     passes.add(createInstructionCombiningPass());
-
+    passes.add(createJumpThreadingPass());        // Thread jumps.
     passes.add(createScalarReplAggregatesPass()); // Break up allocas
 
     // Run a few AA driven optimizations here and now, to cleanup the code.
     passes.add(createGlobalsModRefPass());      // IP alias analysis
 
     passes.add(createLICMPass());               // Hoist loop invariants
-    passes.add(createLoadValueNumberingPass()); // GVN for load instrs
-    passes.add(createGCSEPass());               // Remove common subexprs
+    passes.add(createGVNPass());               // Remove common subexprs
+    passes.add(createMemCpyOptPass());  // Remove dead memcpy's
     passes.add(createDeadStoreEliminationPass()); // Nuke dead stores
 
     // Cleanup and simplify the code after the scalar optimizations.
     passes.add(createInstructionCombiningPass());
 
+    passes.add(createJumpThreadingPass());        // Thread jumps.
+
     // Delete basic blocks, which optimization passes may have killed...
     passes.add(createCFGSimplificationPass());