aboutsummaryrefslogtreecommitdiffstats
path: root/tools/gccas/gccas.cpp
blob: c59b6ebe6a421f06d7cde86377a96bb637b859a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//===----------------------------------------------------------------------===//
// LLVM 'GCCAS' UTILITY 
//
//  This utility is designed to be used by the GCC frontend for creating
// bytecode files from it's intermediate llvm assembly.  The requirements for
// this utility are thus slightly different than that of the standard as util.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/Transforms/RaisePointerReferences.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Target/TargetData.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>
using std::cerr;

// FIXME: This should eventually be parameterized...
static TargetData TD("opt target");

static cl::opt<string>
InputFilename(cl::Positional, cl::desc("<input llvm assembly>"), cl::Required);

static cl::opt<string> 
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<int>
RunNPasses("stopAfterNPasses",
           cl::desc("Only run the first N passes of gccas"), cl::Hidden,
           cl::value_desc("# passes"));

static cl::opt<bool> 
StopAtLevelRaise("stopraise", cl::desc("Stop optimization before level raise"),
                 cl::Hidden);

static cl::opt<bool>   
Verify("verify", cl::desc("Verify each pass result"));


static inline void addPass(PassManager &PM, Pass *P) {
  static int NumPassesCreated = 0;
  
  // If we haven't already created the number of passes that was requested...
  if (RunNPasses == 0 || RunNPasses > NumPassesCreated) {
    // Add the pass to the pass manager...
    PM.add(P);

    // If we are verifying all of the intermediate steps, add the verifier...
    if (Verify) PM.add(createVerifierPass());

    // Keep track of how many passes we made for -stopAfterNPasses
    ++NumPassesCreated;
  }
}


void AddConfiguredTransformationPasses(PassManager &PM) {
  if (Verify) PM.add(createVerifierPass());

  addPass(PM, createFunctionResolvingPass());     // Resolve (...) functions
  addPass(PM, createDeadTypeEliminationPass());   // Eliminate dead types
  addPass(PM, createConstantMergePass());         // Merge dup global constants
  addPass(PM, createDeadInstEliminationPass());   // Remove Dead code/vars
  addPass(PM, createRaiseAllocationsPass());      // call %malloc -> malloc inst
  addPass(PM, createIndVarSimplifyPass());        // Simplify indvars

  // Level raise is eternally buggy/in need of enhancements.  Allow
  // transformation to stop right before it runs.
  if (StopAtLevelRaise) return;

  addPass(PM, createRaisePointerReferencesPass(TD));// Eliminate casts
  addPass(PM, createPromoteMemoryToRegister());   // Promote alloca's to regs
  // Disabling until this is fixed -- Vikram, 7/7/02.
  // addPass(PM, createReassociatePass());           // Reassociate expressions
  addPass(PM, createInstructionCombiningPass());  // Combine silly seq's
  addPass(PM, createDeadInstEliminationPass());   // Kill InstCombine remnants
  addPass(PM, createLICMPass());                  // Hoist loop invariants
  addPass(PM, createGCSEPass());                  // Remove common subexprs
  addPass(PM, createSCCPPass());                  // Constant prop with SCCP

  // Run instcombine after redundancy elimination to exploit opportunities
  // opened up by them.
  addPass(PM, createInstructionCombiningPass());
  addPass(PM, createAggressiveDCEPass());          // SSA based 'Agressive DCE'
  addPass(PM, createCFGSimplificationPass());      // Merge & remove BBs
}


int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm .s -> .o assembler for GCC\n");

  std::auto_ptr<Module> M;
  try {
    // Parse the file now...
    M.reset(ParseAssemblyFile(InputFilename));
  } catch (const ParseException &E) {
    cerr << E.getMessage() << "\n";
    return 1;
  }

  if (M.get() == 0) {
    cerr << "assembly didn't read correctly.\n";
    return 1;
  }
  
  if (OutputFilename == "") {   // Didn't specify an output filename?
    std::string IFN = InputFilename;
    int Len = IFN.length();
    if (IFN[Len-2] == '.' && IFN[Len-1] == 's') {   // Source ends in .s?
      OutputFilename = std::string(IFN.begin(), IFN.end()-2);
    } else {
      OutputFilename = IFN;   // Append a .o to it
    }
    OutputFilename += ".o";
  }

  std::ofstream Out(OutputFilename.c_str(), std::ios::out);
  if (!Out.good()) {
    cerr << "Error opening " << OutputFilename << "!\n";
    return 1;
  }

  // Make sure that the Out file gets unlink'd from the disk if we get a SIGINT
  RemoveFileOnSignal(OutputFilename);

  // In addition to just parsing the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Add all of the transformation passes to the pass manager to do the cleanup
  // and optimization of the GCC output.
  //
  AddConfiguredTransformationPasses(Passes);

  // Write bytecode to file...
  Passes.add(new WriteBytecodePass(&Out));

  // Run our queue of passes all at once now, efficiently.
  Passes.run(*M.get());
  return 0;
}