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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
//===- gencode.cpp - Functions for generating executable files -----------===//
//
// This file contains functions for generating executable files once linking
// has finished. This includes generating a shell script to run the JIT or
// a native executable derived from the bytecode.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/Linker.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "Support/SystemUtils.h"
#include "gccld.h"
//
// Function: GenerateBytecode ()
//
// Description:
// This function generates a bytecode file from the specified module.
//
// Inputs:
// M - The module for which bytecode should be generated.
// Strip - Flags whether symbols should be stripped from the output.
// Internalize - Flags whether all symbols should be marked internal.
// Out - Pointer to file stream to which to write the output.
//
// Outputs:
// None.
//
// Return value:
// 0 - No error.
// 1 - Error.
//
int
GenerateBytecode (Module * M,
bool Strip,
bool Internalize,
std::ostream * Out)
{
// In addition to just linking the input from GCC, we also want to spiff it up
// a little bit. Do this now.
PassManager Passes;
// Add an appropriate TargetData instance for this module...
Passes.add(new TargetData("gccld", M));
// Linking modules together can lead to duplicated global constants, only keep
// one copy of each constant...
//
Passes.add(createConstantMergePass());
// If the -s command line option was specified, strip the symbols out of the
// resulting program to make it smaller. -s is a GCC option that we are
// supporting.
//
if (Strip)
Passes.add(createSymbolStrippingPass());
// Often if the programmer does not specify proper prototypes for the
// functions they are calling, they end up calling a vararg version of the
// function that does not get a body filled in (the real function has typed
// arguments). This pass merges the two functions.
//
Passes.add(createFunctionResolvingPass());
if (Internalize) {
// Now that composite has been compiled, scan through the module, looking
// for a main function. If main is defined, mark all other functions
// internal.
//
Passes.add(createInternalizePass());
}
// Remove unused arguments from functions...
//
Passes.add(createDeadArgEliminationPass());
// The FuncResolve pass may leave cruft around if functions were prototyped
// differently than they were defined. Remove this cruft.
//
Passes.add(createInstructionCombiningPass());
// Delete basic blocks, which optimization passes may have killed...
//
Passes.add(createCFGSimplificationPass());
// Now that we have optimized the program, discard unreachable functions...
//
Passes.add(createGlobalDCEPass());
// Add the pass that writes bytecode to the output file...
Passes.add(new WriteBytecodePass(Out));
// Run our queue of passes all at once now, efficiently.
Passes.run(*M);
return 0;
}
//
// Function: GenerateAssembly ()
//
// Description:
// This function generates a native assembly language source file from the
// specified bytecode file.
//
// Inputs:
// InputFilename - The name of the output bytecode file.
// OutputFilename - The name of the file to generate.
// llc - The pathname to use for LLC.
// envp - The environment to use when running LLC.
//
// Outputs:
// None.
//
// Return value:
// 0 - Success
// 1 - Failure
//
int
GenerateAssembly (const std::string & OutputFilename,
const std::string & InputFilename,
const std::string & llc,
char ** const envp)
{
//
// Run LLC to convert the bytecode file into assembly code.
//
const char * cmd[8];
cmd[0] = llc.c_str();
cmd[1] = "-f";
cmd[2] = "-o";
cmd[3] = OutputFilename.c_str();
cmd[4] = InputFilename.c_str();
cmd[5] = NULL;
return (ExecWait (cmd, envp));
}
//
// Function: GenerateNative ()
//
// Description:
// This function generates a native assembly language source file from the
// specified assembly source file.
//
// Inputs:
// InputFilename - The name of the output bytecode file.
// OutputFilename - The name of the file to generate.
// Libraries - The list of libraries with which to link.
// LibPaths - The list of directories in which to find libraries.
// gcc - The pathname to use for GGC.
// envp - A copy of the process's current environment.
//
// Outputs:
// None.
//
// Return value:
// 0 - Success
// 1 - Failure
//
int
GenerateNative (const std::string & OutputFilename,
const std::string & InputFilename,
const std::vector<std::string> & Libraries,
const std::vector<std::string> & LibPaths,
const std::string & gcc,
char ** const envp)
{
//
// Remove these environment variables from the environment of the
// programs that we will execute. It appears that GCC sets these
// environment variables so that the programs it uses can configure
// themselves identically.
//
// However, when we invoke GCC below, we want it to use its normal
// configuration. Hence, we must sanitize it's environment.
//
char ** clean_env = CopyEnv (envp);
if (clean_env == NULL)
{
return 1;
}
RemoveEnv ("LIBRARY_PATH", clean_env);
RemoveEnv ("COLLECT_GCC_OPTIONS", clean_env);
RemoveEnv ("GCC_EXEC_PREFIX", clean_env);
RemoveEnv ("COMPILER_PATH", clean_env);
RemoveEnv ("COLLECT_GCC", clean_env);
std::vector<const char *> cmd;
//
// Run GCC to assemble and link the program into native code.
//
// Note:
// We can't just assemble and link the file with the system assembler
// and linker because we don't know where to put the _start symbol.
// GCC mysteriously knows how to do it.
//
cmd.push_back (gcc.c_str());
cmd.push_back ("-o");
cmd.push_back (OutputFilename.c_str());
cmd.push_back (InputFilename.c_str());
//
// JTC:
// Adding the library paths creates a problem for native generation. If we
// include the search paths from llvmgcc, then we'll be telling normal gcc
// to look inside of llvmgcc's library directories for libraries. This is
// bad because those libraries hold only bytecode files (not native object
// files). In the end, we attempt to link the bytecode libgcc into a native
// program.
//
#ifdef ndef
//
// Add in the library path options.
//
for (unsigned index=0; index < LibPaths.size(); index++)
{
cmd.push_back ("-L");
cmd.push_back (LibPaths[index].c_str());
}
#endif
//
// Add in the libraries to link.
//
std::vector<std::string> Libs (Libraries);
for (unsigned index = 0; index < Libs.size(); index++)
{
Libs[index] = "-l" + Libs[index];
cmd.push_back (Libs[index].c_str());
}
cmd.push_back (NULL);
//
// Run the compiler to assembly and link together the program.
//
return (ExecWait (&(cmd[0]), clean_env));
}
|