Update LLVM binary drops and scripts to the latest version from SVN
[WebKit-https.git] / Tools / ReducedFTL / ReducedFTL.c
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 /*
27  * Simple tool that takes some LLVM bitcode as input and "JITs" it, in the
28  * same way that the FTL would use LLVM to JIT the IR that it generates.
29  * This is meant for use as a reduction when communicating to LLVMers
30  * about bugs, and for quick "what-if" testing to see how our optimization
31  * pipeline performs. Because of its use as a reduction, this tool is
32  * intentionally standalone and it would be great if it continues to fit
33  * in one file.
34  */
35
36 #include <getopt.h>
37 #include <inttypes.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/mman.h>
43 #include <sys/time.h>
44 #include <unistd.h>
45
46 #include <llvm-c/Analysis.h>
47 #include <llvm-c/BitReader.h>
48 #include <llvm-c/Core.h>
49 #include <llvm-c/Disassembler.h>
50 #include <llvm-c/ExecutionEngine.h>
51 #include <llvm-c/Target.h>
52 #include <llvm-c/Transforms/PassManagerBuilder.h>
53 #include <llvm-c/Transforms/Scalar.h>
54
55 static void usage()
56 {
57     printf("Usage: ReducedFTL <file1> [<file2> ...]\n");
58     printf("\n");
59     printf("Options:\n");
60     printf("--verbose        Display more information, including module dumps.\n");
61     printf("--timing         Measure the time it takes to compile.\n");
62     printf("--disassemble    Disassemble all of the generated code at the end.\n");
63     printf("--mode <mode>    Set the optimization mode (either \"simple\" or \"opt\").\n");
64     printf("--contexts <arg> Set the number of contexts (either \"one\" or \"many\").\n");
65     printf("--help           Print this message.\n");
66     printf("\n");
67     printf("Unless you specify one of --verbose, --timing, or --disassemble, you will\n");
68     printf("not see any output.\n");
69     exit(1);
70 }
71
72 static double currentTime()
73 {
74     struct timeval now;
75     gettimeofday(&now, 0);
76     return now.tv_sec + now.tv_usec / 1000000.0;
77 }
78
79 struct MemorySection {
80     uint8_t *start;
81     size_t size;
82     struct MemorySection *next;
83 };
84
85 static struct MemorySection* sectionHead;
86
87 static uint8_t *mmAllocateCodeSection(
88     void *opaqueState, uintptr_t size, unsigned alignment, unsigned sectionID)
89 {
90     size_t pageSize = getpagesize();
91     
92     uint8_t *start = mmap(
93         0, (size + pageSize - 1) & ~pageSize, 
94         PROT_WRITE | PROT_READ | PROT_EXEC,
95         MAP_ANON | MAP_PRIVATE, -1, 0);
96     if (start == (uint8_t*)-1) {
97         fprintf(stderr, "Unable to allocate %" PRIuPTR " bytes of executable memory.\n", size);
98         exit(1);
99     }
100     
101     struct MemorySection *section = malloc(sizeof(struct MemorySection));
102     section->start = start;
103     section->size = size;
104     section->next = sectionHead;
105     sectionHead = section;
106
107     return start;
108 }
109
110 static uint8_t *mmAllocateDataSection(
111     void *opaqueState, uintptr_t size, unsigned alignment, unsigned sectionID,
112     LLVMBool isReadOnly)
113 {
114     return mmAllocateCodeSection(opaqueState, size, alignment, sectionID);
115 }
116
117 static LLVMBool mmApplyPermissions(void *opaque, char **message)
118 {
119     return 0;
120 }
121
122 static void mmDestroy(void *opaque)
123 {
124 }
125
126 static const char *symbolLookupCallback(
127     void *opaque, uint64_t referenceValue, uint64_t *referenceType, uint64_t referencePC,
128     const char **referenceName)
129 {
130     static char symbolString[20];
131     
132     switch (*referenceType) {
133     case LLVMDisassembler_ReferenceType_InOut_None:
134         return 0;
135     case LLVMDisassembler_ReferenceType_In_Branch:
136         *referenceName = 0;
137         *referenceType = LLVMDisassembler_ReferenceType_InOut_None;
138         snprintf(
139             symbolString, sizeof(symbolString), "0x%lx",
140             (unsigned long)referenceValue);
141         return symbolString;
142     default:
143         fprintf(stderr, "Unexpected reference type!\n");
144         exit(1);
145         return 0;
146     }
147 }
148
149 void webkit_osr_exit()
150 {
151     abort();
152 }
153
154 int main(int c, char **v)
155 {
156     LLVMContextRef *contexts;
157     LLVMModuleRef *modules;
158     char *error;
159     const char *mode = "opt";
160     const char **filenames;
161     unsigned numFiles;
162     unsigned i;
163     bool moreOptions;
164     static int verboseFlag = 0;
165     static int timingFlag = 0;
166     static int disassembleFlag = 0;
167     bool manyContexts = true;
168     double beforeAll;
169     
170     if (c == 1)
171         usage();
172     
173     moreOptions = true;
174     while (moreOptions) {
175         static struct option longOptions[] = {
176             {"verbose", no_argument, &verboseFlag, 1},
177             {"timing", no_argument, &timingFlag, 1},
178             {"disassemble", no_argument, &disassembleFlag, 1},
179             {"mode", required_argument, 0, 0},
180             {"contexts", required_argument, 0, 0},
181             {"help", no_argument, 0, 0}
182         };
183         
184         int optionIndex;
185         int optionValue;
186         
187         optionValue = getopt_long(c, v, "", longOptions, &optionIndex);
188         
189         switch (optionValue) {
190         case -1:
191             moreOptions = false;
192             break;
193             
194         case 0: {
195             const char* thisOption = longOptions[optionIndex].name;
196             if (!strcmp(thisOption, "help"))
197                 usage();
198             if (!strcmp(thisOption, "contexts")) {
199                 if (!strcasecmp(optarg, "one"))
200                     manyContexts = false;
201                 else if (!strcasecmp(optarg, "many"))
202                     manyContexts = true;
203                 else {
204                     fprintf(stderr, "Invalid argument for --contexts.\n");
205                     exit(1);
206                 }
207                 break;
208             }
209             if (!strcmp(thisOption, "mode")) {
210                 mode = strdup(optarg);
211                 break;
212             }
213             break;
214         }
215             
216         case '?':
217             exit(0);
218             break;
219             
220         default:
221             printf("optionValue = %d\n", optionValue);
222             abort();
223             break;
224         }
225     }
226     
227     LLVMLinkInMCJIT();
228     LLVMInitializeNativeTarget();
229     LLVMInitializeX86AsmPrinter();
230     LLVMInitializeX86Disassembler();
231
232     filenames = (const char **)(v + optind);
233     numFiles = c - optind;
234     
235     contexts = malloc(sizeof(LLVMContextRef) * numFiles);
236     modules = malloc(sizeof(LLVMModuleRef) * numFiles);
237     
238     if (manyContexts) {
239         for (i = 0; i < numFiles; ++i)
240             contexts[i] = LLVMContextCreate();
241     } else {
242         LLVMContextRef context = LLVMContextCreate();
243         for (i = 0; i < numFiles; ++i)
244             contexts[i] = context;
245     }
246     
247     for (i = 0; i < numFiles; ++i) {
248         LLVMMemoryBufferRef buffer;
249         const char* filename = filenames[i];
250         
251         if (LLVMCreateMemoryBufferWithContentsOfFile(filename, &buffer, &error)) {
252             fprintf(stderr, "Error reading file %s: %s\n", filename, error);
253             exit(1);
254         }
255         
256         if (LLVMParseBitcodeInContext(contexts[i], buffer, modules + i, &error)) {
257             fprintf(stderr, "Error parsing file %s: %s\n", filename, error);
258             exit(1);
259         }
260         
261         LLVMDisposeMemoryBuffer(buffer);
262         
263         if (verboseFlag) {
264             printf("Module #%u (%s) after parsing:\n", i, filename);
265             LLVMDumpModule(modules[i]);
266         }
267     }
268
269     if (verboseFlag)
270         printf("Generating code for modules...\n");
271     
272     if (timingFlag)
273         beforeAll = currentTime();
274     for (i = 0; i < numFiles; ++i) {
275         LLVMModuleRef module;
276         LLVMExecutionEngineRef engine;
277         struct LLVMMCJITCompilerOptions options;
278         LLVMValueRef value;
279         LLVMPassManagerRef functionPasses = 0;
280         LLVMPassManagerRef modulePasses = 0;
281         
282         double before;
283         
284         if (timingFlag)
285             before = currentTime();
286         
287         module = modules[i];
288
289         LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
290         options.OptLevel = 2;
291         options.EnableFastISel = 0;
292         options.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
293             0, mmAllocateCodeSection, mmAllocateDataSection, mmApplyPermissions, mmDestroy);
294     
295         if (LLVMCreateMCJITCompilerForModule(&engine, module, &options, sizeof(options), &error)) {
296             fprintf(stderr, "Error building MCJIT: %s\n", error);
297             exit(1);
298         }
299     
300         if (!strcasecmp(mode, "simple")) {
301             modulePasses = LLVMCreatePassManager();
302             LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), modulePasses);
303             LLVMAddConstantPropagationPass(modulePasses);
304             LLVMAddInstructionCombiningPass(modulePasses);
305             LLVMAddPromoteMemoryToRegisterPass(modulePasses);
306             LLVMAddBasicAliasAnalysisPass(modulePasses);
307             LLVMAddTypeBasedAliasAnalysisPass(modulePasses);
308             LLVMAddGVNPass(modulePasses);
309             LLVMAddCFGSimplificationPass(modulePasses);
310             LLVMRunPassManager(modulePasses, module);
311         } else if (!strcasecmp(mode, "opt")) {
312             LLVMPassManagerBuilderRef passBuilder;
313
314             passBuilder = LLVMPassManagerBuilderCreate();
315             LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
316             LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
317         
318             functionPasses = LLVMCreateFunctionPassManagerForModule(module);
319             modulePasses = LLVMCreatePassManager();
320         
321             LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), modulePasses);
322         
323             LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder, functionPasses);
324             LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
325         
326             LLVMPassManagerBuilderDispose(passBuilder);
327         
328             LLVMInitializeFunctionPassManager(functionPasses);
329             for (value = LLVMGetFirstFunction(module); value; value = LLVMGetNextFunction(value))
330                 LLVMRunFunctionPassManager(functionPasses, value);
331             LLVMFinalizeFunctionPassManager(functionPasses);
332         
333             LLVMRunPassManager(modulePasses, module);
334         } else {
335             fprintf(stderr, "Bad optimization mode: %s.\n", mode);
336             fprintf(stderr, "Valid modes are: \"simple\" or \"opt\".\n");
337             exit(1);
338         }
339
340         if (verboseFlag) {
341             printf("Module #%d (%s) after optimization:\n", i, filenames[i]);
342             LLVMDumpModule(module);
343         }
344     
345         for (value = LLVMGetFirstFunction(module); value; value = LLVMGetNextFunction(value)) {
346             if (LLVMIsDeclaration(value))
347                 continue;
348             LLVMGetPointerToGlobal(engine, value);
349         }
350
351         if (functionPasses)
352             LLVMDisposePassManager(functionPasses);
353         if (modulePasses)
354             LLVMDisposePassManager(modulePasses);
355     
356         LLVMDisposeExecutionEngine(engine);
357         
358         if (timingFlag) {
359             double after = currentTime();
360             printf("Module #%d (%s) took %lf ms.\n", i, filenames[i], (after - before) * 1000);
361         }
362     }
363     if (timingFlag) {
364         double after = currentTime();
365         printf("Compilation took a total of %lf ms.\n", (after - beforeAll) * 1000);
366     }
367     
368     if (disassembleFlag) {
369         LLVMDisasmContextRef disassembler;
370         struct MemorySection *section;
371         
372         disassembler = LLVMCreateDisasm("x86_64-apple-darwin", 0, 0, 0, symbolLookupCallback);
373         if (!disassembler) {
374             fprintf(stderr, "Error building disassembler.\n");
375             exit(1);
376         }
377     
378         for (section = sectionHead; section; section = section->next) {
379             printf("Disassembly for section %p:\n", section);
380         
381             char pcString[20];
382             char instructionString[1000];
383             uint8_t *pc;
384             uint8_t *end;
385         
386             pc = section->start;
387             end = pc + section->size;
388         
389             while (pc < end) {
390                 snprintf(
391                     pcString, sizeof(pcString), "0x%lx",
392                     (unsigned long)(uintptr_t)pc);
393             
394                 size_t instructionSize = LLVMDisasmInstruction(
395                     disassembler, pc, end - pc, (uintptr_t)pc,
396                     instructionString, sizeof(instructionString));
397             
398                 if (!instructionSize)
399                     snprintf(instructionString, sizeof(instructionString), ".byte 0x%02x", *pc++);
400                 else
401                     pc += instructionSize;
402             
403                 printf("    %16s: %s\n", pcString, instructionString);
404             }
405         }
406     }
407     
408     return 0;
409 }
410