1e5f4a9ffSEmmett Neyman //==-- handle_llvm.cpp - Helper function for Clang fuzzers -----------------==//
2e5f4a9ffSEmmett Neyman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5f4a9ffSEmmett Neyman //
7e5f4a9ffSEmmett Neyman //===----------------------------------------------------------------------===//
8e5f4a9ffSEmmett Neyman //
9e5581242SEmmett Neyman // Implements HandleLLVM for use by the Clang fuzzers. First runs a loop
10e5581242SEmmett Neyman // vectorizer optimization pass over the given IR code. Then mimics lli on both
11e5581242SEmmett Neyman // versions to JIT the generated code and execute it. Currently, functions are
12e5581242SEmmett Neyman // executed on dummy inputs.
13e5f4a9ffSEmmett Neyman //
14e5f4a9ffSEmmett Neyman //===----------------------------------------------------------------------===//
15e5f4a9ffSEmmett Neyman
16e5f4a9ffSEmmett Neyman #include "handle_llvm.h"
172655b038SEmmett Neyman #include "input_arrays.h"
18e5f4a9ffSEmmett Neyman
19e5f4a9ffSEmmett Neyman #include "llvm/Analysis/TargetLibraryInfo.h"
20e5581242SEmmett Neyman #include "llvm/Analysis/TargetTransformInfo.h"
21ac1d23edSserge-sans-paille #include "llvm/CodeGen/CommandFlags.h"
22e5f4a9ffSEmmett Neyman #include "llvm/CodeGen/MachineModuleInfo.h"
23e5581242SEmmett Neyman #include "llvm/CodeGen/TargetPassConfig.h"
24e5581242SEmmett Neyman #include "llvm/ExecutionEngine/JITEventListener.h"
25e5581242SEmmett Neyman #include "llvm/ExecutionEngine/JITSymbol.h"
26e5581242SEmmett Neyman #include "llvm/ExecutionEngine/MCJIT.h"
27e5581242SEmmett Neyman #include "llvm/ExecutionEngine/ObjectCache.h"
28e5581242SEmmett Neyman #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
29e5581242SEmmett Neyman #include "llvm/ExecutionEngine/SectionMemoryManager.h"
30e5581242SEmmett Neyman #include "llvm/IR/IRPrintingPasses.h"
31ac1d23edSserge-sans-paille #include "llvm/IR/LLVMContext.h"
32e5f4a9ffSEmmett Neyman #include "llvm/IR/Module.h"
33e5f4a9ffSEmmett Neyman #include "llvm/IR/Verifier.h"
3466b1f6bbSArthur Eubanks #include "llvm/IRPrinter/IRPrintingPasses.h"
35e5f4a9ffSEmmett Neyman #include "llvm/IRReader/IRReader.h"
3689b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
3766b1f6bbSArthur Eubanks #include "llvm/Passes/OptimizationLevel.h"
3866b1f6bbSArthur Eubanks #include "llvm/Passes/PassBuilder.h"
39e5f4a9ffSEmmett Neyman #include "llvm/Support/MemoryBuffer.h"
40e5f4a9ffSEmmett Neyman #include "llvm/Support/SourceMgr.h"
41e5581242SEmmett Neyman #include "llvm/Support/TargetSelect.h"
42e5f4a9ffSEmmett Neyman #include "llvm/Target/TargetMachine.h"
4362c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h"
44e5f4a9ffSEmmett Neyman
45e5f4a9ffSEmmett Neyman using namespace llvm;
46e5f4a9ffSEmmett Neyman
472655b038SEmmett Neyman // Define a type for the functions that are compiled and executed
482655b038SEmmett Neyman typedef void (*LLVMFunc)(int*, int*, int*, int);
492655b038SEmmett Neyman
50e5581242SEmmett Neyman // Helper function to parse command line args and find the optimization level
getOptLevel(const std::vector<const char * > & ExtraArgs)51*0a1aa6cdSArthur Eubanks static CodeGenOptLevel getOptLevel(const std::vector<const char *> &ExtraArgs) {
52e5f4a9ffSEmmett Neyman // Find the optimization level from the command line args
53*0a1aa6cdSArthur Eubanks CodeGenOptLevel OLvl = CodeGenOptLevel::Default;
54e5f4a9ffSEmmett Neyman for (auto &A : ExtraArgs) {
55e5f4a9ffSEmmett Neyman if (A[0] == '-' && A[1] == 'O') {
5625c0ea2aSScott Linder if (auto Level = CodeGenOpt::parseLevel(A[2])) {
5725c0ea2aSScott Linder OLvl = *Level;
5825c0ea2aSScott Linder } else {
59e5f4a9ffSEmmett Neyman errs() << "error: opt level must be between 0 and 3.\n";
60e5f4a9ffSEmmett Neyman std::exit(1);
61e5f4a9ffSEmmett Neyman }
62e5f4a9ffSEmmett Neyman }
63e5f4a9ffSEmmett Neyman }
6466b1f6bbSArthur Eubanks return OLvl;
65e5f4a9ffSEmmett Neyman }
66e5f4a9ffSEmmett Neyman
ErrorAndExit(std::string message)672655b038SEmmett Neyman static void ErrorAndExit(std::string message) {
68e5581242SEmmett Neyman errs()<< "ERROR: " << message << "\n";
69e5581242SEmmett Neyman std::exit(1);
70e5581242SEmmett Neyman }
71e5581242SEmmett Neyman
72e5581242SEmmett Neyman // Helper function to add optimization passes to the TargetMachine at the
73e5581242SEmmett Neyman // specified optimization level, OptLevel
RunOptimizationPasses(raw_ostream & OS,Module & M,CodeGenOptLevel OptLevel)7466b1f6bbSArthur Eubanks static void RunOptimizationPasses(raw_ostream &OS, Module &M,
75*0a1aa6cdSArthur Eubanks CodeGenOptLevel OptLevel) {
7666b1f6bbSArthur Eubanks llvm::OptimizationLevel OL;
7766b1f6bbSArthur Eubanks switch (OptLevel) {
78*0a1aa6cdSArthur Eubanks case CodeGenOptLevel::None:
7966b1f6bbSArthur Eubanks OL = OptimizationLevel::O0;
8066b1f6bbSArthur Eubanks break;
81*0a1aa6cdSArthur Eubanks case CodeGenOptLevel::Less:
8266b1f6bbSArthur Eubanks OL = OptimizationLevel::O1;
8366b1f6bbSArthur Eubanks break;
84*0a1aa6cdSArthur Eubanks case CodeGenOptLevel::Default:
8566b1f6bbSArthur Eubanks OL = OptimizationLevel::O2;
8666b1f6bbSArthur Eubanks break;
87*0a1aa6cdSArthur Eubanks case CodeGenOptLevel::Aggressive:
8866b1f6bbSArthur Eubanks OL = OptimizationLevel::O3;
8966b1f6bbSArthur Eubanks break;
9066b1f6bbSArthur Eubanks }
9166b1f6bbSArthur Eubanks
9266b1f6bbSArthur Eubanks LoopAnalysisManager LAM;
9366b1f6bbSArthur Eubanks FunctionAnalysisManager FAM;
9466b1f6bbSArthur Eubanks CGSCCAnalysisManager CGAM;
9566b1f6bbSArthur Eubanks ModuleAnalysisManager MAM;
9666b1f6bbSArthur Eubanks
9766b1f6bbSArthur Eubanks PassBuilder PB;
9866b1f6bbSArthur Eubanks
9966b1f6bbSArthur Eubanks PB.registerModuleAnalyses(MAM);
10066b1f6bbSArthur Eubanks PB.registerCGSCCAnalyses(CGAM);
10166b1f6bbSArthur Eubanks PB.registerFunctionAnalyses(FAM);
10266b1f6bbSArthur Eubanks PB.registerLoopAnalyses(LAM);
10366b1f6bbSArthur Eubanks PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
10466b1f6bbSArthur Eubanks
105a8f6b576SNikita Popov ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(OL);
10666b1f6bbSArthur Eubanks MPM.addPass(PrintModulePass(OS));
10766b1f6bbSArthur Eubanks
10866b1f6bbSArthur Eubanks MPM.run(M, MAM);
109e5581242SEmmett Neyman }
110e5581242SEmmett Neyman
111e5581242SEmmett Neyman // Mimics the opt tool to run an optimization pass over the provided IR
OptLLVM(const std::string & IR,CodeGenOptLevel OLvl)112*0a1aa6cdSArthur Eubanks static std::string OptLLVM(const std::string &IR, CodeGenOptLevel OLvl) {
113e5581242SEmmett Neyman // Create a module that will run the optimization passes
114e5581242SEmmett Neyman SMDiagnostic Err;
115e5581242SEmmett Neyman LLVMContext Context;
116e5581242SEmmett Neyman std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);
117e5581242SEmmett Neyman if (!M || verifyModule(*M, &errs()))
118e5581242SEmmett Neyman ErrorAndExit("Could not parse IR");
119e5581242SEmmett Neyman
120a60d168dSEmmett Neyman Triple ModuleTriple(M->getTargetTriple());
121f85bcc21Sjasonliu const TargetOptions Options =
122f85bcc21Sjasonliu codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple);
123a60d168dSEmmett Neyman std::string E;
124ac1d23edSserge-sans-paille const Target *TheTarget =
125ac1d23edSserge-sans-paille TargetRegistry::lookupTarget(codegen::getMArch(), ModuleTriple, E);
1261756d679SElla Ma if (!TheTarget)
1271756d679SElla Ma ErrorAndExit(E);
1281756d679SElla Ma
1291756d679SElla Ma std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
130ac1d23edSserge-sans-paille M->getTargetTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(),
131ac1d23edSserge-sans-paille Options, codegen::getExplicitRelocModel(),
1321756d679SElla Ma codegen::getExplicitCodeModel(), OLvl));
1331756d679SElla Ma if (!TM)
1341756d679SElla Ma ErrorAndExit("Could not create target machine");
1351756d679SElla Ma
136ac1d23edSserge-sans-paille codegen::setFunctionAttributes(codegen::getCPUStr(),
137ac1d23edSserge-sans-paille codegen::getFeaturesStr(), *M);
138e5581242SEmmett Neyman
139e5581242SEmmett Neyman // Add a pass that writes the optimized IR to an output stream
140e5581242SEmmett Neyman std::string outString;
141e5581242SEmmett Neyman raw_string_ostream OS(outString);
14266b1f6bbSArthur Eubanks RunOptimizationPasses(OS, *M, OLvl);
143e5581242SEmmett Neyman
1445336befeSLogan Smith return outString;
145e5581242SEmmett Neyman }
146e5581242SEmmett Neyman
1472655b038SEmmett Neyman // Takes a function and runs it on a set of inputs
1482655b038SEmmett Neyman // First determines whether f is the optimized or unoptimized function
RunFuncOnInputs(LLVMFunc f,int Arr[kNumArrays][kArraySize])1492655b038SEmmett Neyman static void RunFuncOnInputs(LLVMFunc f, int Arr[kNumArrays][kArraySize]) {
1502655b038SEmmett Neyman for (int i = 0; i < kNumArrays / 3; i++)
1512655b038SEmmett Neyman f(Arr[i], Arr[i + (kNumArrays / 3)], Arr[i + (2 * kNumArrays / 3)],
1522655b038SEmmett Neyman kArraySize);
1532655b038SEmmett Neyman }
1542655b038SEmmett Neyman
1552655b038SEmmett Neyman // Takes a string of IR and compiles it using LLVM's JIT Engine
CreateAndRunJITFunc(const std::string & IR,CodeGenOptLevel OLvl)156*0a1aa6cdSArthur Eubanks static void CreateAndRunJITFunc(const std::string &IR, CodeGenOptLevel OLvl) {
157e5581242SEmmett Neyman SMDiagnostic Err;
158e5581242SEmmett Neyman LLVMContext Context;
1592655b038SEmmett Neyman std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);
160e5581242SEmmett Neyman if (!M)
161e5581242SEmmett Neyman ErrorAndExit("Could not parse IR");
162e5581242SEmmett Neyman
163e5581242SEmmett Neyman Function *EntryFunc = M->getFunction("foo");
164e5581242SEmmett Neyman if (!EntryFunc)
165e5581242SEmmett Neyman ErrorAndExit("Function not found in module");
166e5581242SEmmett Neyman
167e5581242SEmmett Neyman std::string ErrorMsg;
168e4991867SSimon Pilgrim Triple ModuleTriple(M->getTargetTriple());
169e4991867SSimon Pilgrim
170e5581242SEmmett Neyman EngineBuilder builder(std::move(M));
171ac1d23edSserge-sans-paille builder.setMArch(codegen::getMArch());
172ac1d23edSserge-sans-paille builder.setMCPU(codegen::getCPUStr());
173ac1d23edSserge-sans-paille builder.setMAttrs(codegen::getFeatureList());
174e5581242SEmmett Neyman builder.setErrorStr(&ErrorMsg);
175e5581242SEmmett Neyman builder.setEngineKind(EngineKind::JIT);
1762b3d49b6SJonas Devlieghere builder.setMCJITMemoryManager(std::make_unique<SectionMemoryManager>());
177e5581242SEmmett Neyman builder.setOptLevel(OLvl);
178f85bcc21Sjasonliu builder.setTargetOptions(
179f85bcc21Sjasonliu codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple));
180e5581242SEmmett Neyman
181e5581242SEmmett Neyman std::unique_ptr<ExecutionEngine> EE(builder.create());
182e5581242SEmmett Neyman if (!EE)
183e5581242SEmmett Neyman ErrorAndExit("Could not create execution engine");
184e5581242SEmmett Neyman
185e5581242SEmmett Neyman EE->finalizeObject();
186e5581242SEmmett Neyman EE->runStaticConstructorsDestructors(false);
187e5581242SEmmett Neyman
1882655b038SEmmett Neyman LLVMFunc f = reinterpret_cast<LLVMFunc>(EE->getPointerToFunction(EntryFunc));
189e5581242SEmmett Neyman
1902655b038SEmmett Neyman // Figure out if we are running the optimized func or the unoptimized func
191*0a1aa6cdSArthur Eubanks RunFuncOnInputs(f, (OLvl == CodeGenOptLevel::None) ? UnoptArrays : OptArrays);
192e5581242SEmmett Neyman
193e5581242SEmmett Neyman EE->runStaticConstructorsDestructors(true);
194e5581242SEmmett Neyman }
195e5581242SEmmett Neyman
196e5581242SEmmett Neyman // Main fuzz target called by ExampleClangLLVMProtoFuzzer.cpp
197e5581242SEmmett Neyman // Mimics the lli tool to JIT the LLVM IR code and execute it
HandleLLVM(const std::string & IR,const std::vector<const char * > & ExtraArgs)198e5581242SEmmett Neyman void clang_fuzzer::HandleLLVM(const std::string &IR,
199e5f4a9ffSEmmett Neyman const std::vector<const char *> &ExtraArgs) {
2002655b038SEmmett Neyman // Populate OptArrays and UnoptArrays with the arrays from InputArrays
2012655b038SEmmett Neyman memcpy(OptArrays, InputArrays, kTotalSize);
2022655b038SEmmett Neyman memcpy(UnoptArrays, InputArrays, kTotalSize);
2032655b038SEmmett Neyman
204e5f4a9ffSEmmett Neyman // Parse ExtraArgs to set the optimization level
205*0a1aa6cdSArthur Eubanks CodeGenOptLevel OLvl = getOptLevel(ExtraArgs);
206e5f4a9ffSEmmett Neyman
207e5581242SEmmett Neyman // First we optimize the IR by running a loop vectorizer pass
208e5581242SEmmett Neyman std::string OptIR = OptLLVM(IR, OLvl);
209e5f4a9ffSEmmett Neyman
2102655b038SEmmett Neyman CreateAndRunJITFunc(OptIR, OLvl);
211*0a1aa6cdSArthur Eubanks CreateAndRunJITFunc(IR, CodeGenOptLevel::None);
2122655b038SEmmett Neyman
2132655b038SEmmett Neyman if (memcmp(OptArrays, UnoptArrays, kTotalSize))
2142655b038SEmmett Neyman ErrorAndExit("!!!BUG!!!");
215e5f4a9ffSEmmett Neyman }
216