1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | #include "handle_llvm.h" |
17 | #include "input_arrays.h" |
18 | |
19 | #include "llvm/ADT/Triple.h" |
20 | #include "llvm/Analysis/TargetLibraryInfo.h" |
21 | #include "llvm/Analysis/TargetTransformInfo.h" |
22 | #include "llvm/CodeGen/CommandFlags.inc" |
23 | #include "llvm/CodeGen/MachineModuleInfo.h" |
24 | #include "llvm/CodeGen/TargetPassConfig.h" |
25 | #include "llvm/ExecutionEngine/JITEventListener.h" |
26 | #include "llvm/ExecutionEngine/JITSymbol.h" |
27 | #include "llvm/ExecutionEngine/MCJIT.h" |
28 | #include "llvm/ExecutionEngine/ObjectCache.h" |
29 | #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" |
30 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" |
31 | #include "llvm/IR/IRPrintingPasses.h" |
32 | #include "llvm/IR/LegacyPassManager.h" |
33 | #include "llvm/IR/LegacyPassNameParser.h" |
34 | #include "llvm/IR/LLVMContext.h" |
35 | #include "llvm/IR/Module.h" |
36 | #include "llvm/IR/Verifier.h" |
37 | #include "llvm/IRReader/IRReader.h" |
38 | #include "llvm/Pass.h" |
39 | #include "llvm/PassRegistry.h" |
40 | #include "llvm/Support/MemoryBuffer.h" |
41 | #include "llvm/Support/SourceMgr.h" |
42 | #include "llvm/Support/TargetRegistry.h" |
43 | #include "llvm/Support/TargetSelect.h" |
44 | #include "llvm/Target/TargetMachine.h" |
45 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" |
46 | #include "llvm/Transforms/IPO.h" |
47 | #include "llvm/Transforms/Vectorize.h" |
48 | |
49 | using namespace llvm; |
50 | |
51 | |
52 | typedef void (*LLVMFunc)(int*, int*, int*, int); |
53 | |
54 | |
55 | static void getOptLevel(const std::vector<const char *> &, |
56 | CodeGenOpt::Level &OLvl) { |
57 | |
58 | OLvl = CodeGenOpt::Default; |
59 | for (auto &A : ExtraArgs) { |
60 | if (A[0] == '-' && A[1] == 'O') { |
61 | switch(A[2]) { |
62 | case '0': OLvl = CodeGenOpt::None; break; |
63 | case '1': OLvl = CodeGenOpt::Less; break; |
64 | case '2': OLvl = CodeGenOpt::Default; break; |
65 | case '3': OLvl = CodeGenOpt::Aggressive; break; |
66 | default: |
67 | errs() << "error: opt level must be between 0 and 3.\n"; |
68 | std::exit(1); |
69 | } |
70 | } |
71 | } |
72 | } |
73 | |
74 | static void ErrorAndExit(std::string message) { |
75 | errs()<< "ERROR: " << message << "\n"; |
76 | std::exit(1); |
77 | } |
78 | |
79 | |
80 | |
81 | static void AddOptimizationPasses(legacy::PassManagerBase &MPM, |
82 | CodeGenOpt::Level OptLevel, |
83 | unsigned SizeLevel) { |
84 | |
85 | PassManagerBuilder Builder; |
86 | Builder.OptLevel = OptLevel; |
87 | Builder.SizeLevel = SizeLevel; |
88 | Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false); |
89 | Builder.LoopVectorize = true; |
90 | Builder.populateModulePassManager(MPM); |
91 | } |
92 | |
93 | |
94 | static std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) { |
95 | |
96 | SMDiagnostic Err; |
97 | LLVMContext Context; |
98 | std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context); |
99 | if (!M || verifyModule(*M, &errs())) |
100 | ErrorAndExit("Could not parse IR"); |
101 | |
102 | Triple ModuleTriple(M->getTargetTriple()); |
103 | const TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); |
104 | std::string E; |
105 | const Target *TheTarget = TargetRegistry::lookupTarget(MArch, ModuleTriple, E); |
106 | TargetMachine *Machine = |
107 | TheTarget->createTargetMachine(M->getTargetTriple(), getCPUStr(), |
108 | getFeaturesStr(), Options, getRelocModel(), |
109 | getCodeModel(), OLvl); |
110 | std::unique_ptr<TargetMachine> TM(Machine); |
111 | setFunctionAttributes(getCPUStr(), getFeaturesStr(), *M); |
112 | |
113 | legacy::PassManager Passes; |
114 | |
115 | Passes.add(new TargetLibraryInfoWrapperPass(ModuleTriple)); |
116 | Passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); |
117 | |
118 | LLVMTargetMachine <M = static_cast<LLVMTargetMachine &>(*TM); |
119 | Passes.add(LTM.createPassConfig(Passes)); |
120 | |
121 | Passes.add(createVerifierPass()); |
122 | |
123 | AddOptimizationPasses(Passes, OLvl, 0); |
124 | |
125 | |
126 | std::string outString; |
127 | raw_string_ostream OS(outString); |
128 | Passes.add(createPrintModulePass(OS, "", false)); |
129 | |
130 | Passes.run(*M); |
131 | |
132 | return OS.str(); |
133 | } |
134 | |
135 | |
136 | |
137 | static void RunFuncOnInputs(LLVMFunc f, int Arr[kNumArrays][kArraySize]) { |
138 | for (int i = 0; i < kNumArrays / 3; i++) |
139 | f(Arr[i], Arr[i + (kNumArrays / 3)], Arr[i + (2 * kNumArrays / 3)], |
140 | kArraySize); |
141 | } |
142 | |
143 | |
144 | static void CreateAndRunJITFunc(const std::string &IR, CodeGenOpt::Level OLvl) { |
145 | SMDiagnostic Err; |
146 | LLVMContext Context; |
147 | std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context); |
148 | if (!M) |
149 | ErrorAndExit("Could not parse IR"); |
150 | |
151 | Function *EntryFunc = M->getFunction("foo"); |
152 | if (!EntryFunc) |
153 | ErrorAndExit("Function not found in module"); |
154 | |
155 | std::string ErrorMsg; |
156 | EngineBuilder builder(std::move(M)); |
157 | builder.setMArch(MArch); |
158 | builder.setMCPU(getCPUStr()); |
159 | builder.setMAttrs(getFeatureList()); |
160 | builder.setErrorStr(&ErrorMsg); |
161 | builder.setEngineKind(EngineKind::JIT); |
162 | builder.setUseOrcMCJITReplacement(false); |
163 | builder.setMCJITMemoryManager(make_unique<SectionMemoryManager>()); |
164 | builder.setOptLevel(OLvl); |
165 | builder.setTargetOptions(InitTargetOptionsFromCodeGenFlags()); |
166 | |
167 | std::unique_ptr<ExecutionEngine> EE(builder.create()); |
168 | if (!EE) |
169 | ErrorAndExit("Could not create execution engine"); |
170 | |
171 | EE->finalizeObject(); |
172 | EE->runStaticConstructorsDestructors(false); |
173 | |
174 | #if defined(__GNUC__) && !defined(__clang) && \ |
175 | ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | #pragma GCC diagnostic push |
184 | #pragma GCC diagnostic ignored "-Wpedantic" |
185 | #endif |
186 | LLVMFunc f = reinterpret_cast<LLVMFunc>(EE->getPointerToFunction(EntryFunc)); |
187 | #if defined(__GNUC__) && !defined(__clang) && \ |
188 | ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9)) |
189 | #pragma GCC diagnostic pop |
190 | #endif |
191 | |
192 | |
193 | RunFuncOnInputs(f, (OLvl == CodeGenOpt::None) ? UnoptArrays : OptArrays); |
194 | |
195 | EE->runStaticConstructorsDestructors(true); |
196 | } |
197 | |
198 | |
199 | |
200 | void clang_fuzzer::HandleLLVM(const std::string &IR, |
201 | const std::vector<const char *> &) { |
202 | |
203 | memcpy(OptArrays, InputArrays, kTotalSize); |
204 | memcpy(UnoptArrays, InputArrays, kTotalSize); |
205 | |
206 | |
207 | CodeGenOpt::Level OLvl; |
208 | getOptLevel(ExtraArgs, OLvl); |
209 | |
210 | |
211 | std::string OptIR = OptLLVM(IR, OLvl); |
212 | |
213 | CreateAndRunJITFunc(OptIR, OLvl); |
214 | CreateAndRunJITFunc(IR, CodeGenOpt::None); |
215 | |
216 | if (memcmp(OptArrays, UnoptArrays, kTotalSize)) |
217 | ErrorAndExit("!!!BUG!!!"); |
218 | |
219 | return; |
220 | } |
221 | |