xref: /llvm-project/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp (revision 37da4e3d80d7136121e74e2b8d23afb14ae7ab69)
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