brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · 798b34b Raw
216 lines · cpp
1//==-- handle_llvm.cpp - Helper function for Clang fuzzers -----------------==//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Implements HandleLLVM for use by the Clang fuzzers. First runs a loop10// vectorizer optimization pass over the given IR code. Then mimics lli on both11// versions to JIT the generated code and execute it. Currently, functions are 12// executed on dummy inputs.13//14//===----------------------------------------------------------------------===//15 16#include "handle_llvm.h"17#include "input_arrays.h"18 19#include "llvm/Analysis/TargetLibraryInfo.h"20#include "llvm/Analysis/TargetTransformInfo.h"21#include "llvm/CodeGen/CommandFlags.h"22#include "llvm/CodeGen/MachineModuleInfo.h"23#include "llvm/CodeGen/TargetPassConfig.h"24#include "llvm/ExecutionEngine/JITEventListener.h"25#include "llvm/ExecutionEngine/JITSymbol.h"26#include "llvm/ExecutionEngine/MCJIT.h"27#include "llvm/ExecutionEngine/ObjectCache.h"28#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"29#include "llvm/ExecutionEngine/SectionMemoryManager.h"30#include "llvm/IR/IRPrintingPasses.h"31#include "llvm/IR/LLVMContext.h"32#include "llvm/IR/Module.h"33#include "llvm/IR/Verifier.h"34#include "llvm/IRPrinter/IRPrintingPasses.h"35#include "llvm/IRReader/IRReader.h"36#include "llvm/MC/TargetRegistry.h"37#include "llvm/Passes/OptimizationLevel.h"38#include "llvm/Passes/PassBuilder.h"39#include "llvm/Support/MemoryBuffer.h"40#include "llvm/Support/SourceMgr.h"41#include "llvm/Support/TargetSelect.h"42#include "llvm/Target/TargetMachine.h"43#include "llvm/TargetParser/Triple.h"44 45using namespace llvm;46 47// Define a type for the functions that are compiled and executed48typedef void (*LLVMFunc)(int*, int*, int*, int);49 50// Helper function to parse command line args and find the optimization level51static CodeGenOptLevel getOptLevel(const std::vector<const char *> &ExtraArgs) {52  // Find the optimization level from the command line args53  CodeGenOptLevel OLvl = CodeGenOptLevel::Default;54  for (auto &A : ExtraArgs) {55    if (A[0] == '-' && A[1] == 'O') {56      if (auto Level = CodeGenOpt::parseLevel(A[2])) {57        OLvl = *Level;58      } else {59        errs() << "error: opt level must be between 0 and 3.\n";60        std::exit(1);61      }62    }63  }64  return OLvl;65}66 67static void ErrorAndExit(std::string message) {68  errs()<< "ERROR: " << message << "\n";69  std::exit(1);70}71 72// Helper function to add optimization passes to the TargetMachine at the 73// specified optimization level, OptLevel74static void RunOptimizationPasses(raw_ostream &OS, Module &M,75                                  CodeGenOptLevel OptLevel) {76  llvm::OptimizationLevel OL;77  switch (OptLevel) {78  case CodeGenOptLevel::None:79    OL = OptimizationLevel::O0;80    break;81  case CodeGenOptLevel::Less:82    OL = OptimizationLevel::O1;83    break;84  case CodeGenOptLevel::Default:85    OL = OptimizationLevel::O2;86    break;87  case CodeGenOptLevel::Aggressive:88    OL = OptimizationLevel::O3;89    break;90  }91 92  LoopAnalysisManager LAM;93  FunctionAnalysisManager FAM;94  CGSCCAnalysisManager CGAM;95  ModuleAnalysisManager MAM;96 97  PassBuilder PB;98 99  PB.registerModuleAnalyses(MAM);100  PB.registerCGSCCAnalyses(CGAM);101  PB.registerFunctionAnalyses(FAM);102  PB.registerLoopAnalyses(LAM);103  PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);104 105  ModulePassManager MPM = PB.buildPerModuleDefaultPipeline(OL);106  MPM.addPass(PrintModulePass(OS));107 108  MPM.run(M, MAM);109}110 111// Mimics the opt tool to run an optimization pass over the provided IR112static std::string OptLLVM(const std::string &IR, CodeGenOptLevel OLvl) {113  // Create a module that will run the optimization passes114  SMDiagnostic Err;115  LLVMContext Context;116  std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);117  if (!M || verifyModule(*M, &errs()))118    ErrorAndExit("Could not parse IR");119 120  Triple ModuleTriple(M->getTargetTriple());121  const TargetOptions Options =122      codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple);123  std::string E;124  const Target *TheTarget =125      TargetRegistry::lookupTarget(codegen::getMArch(), ModuleTriple, E);126  if (!TheTarget)127    ErrorAndExit(E);128 129  std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(130      M->getTargetTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(),131      Options, codegen::getExplicitRelocModel(),132      codegen::getExplicitCodeModel(), OLvl));133  if (!TM)134    ErrorAndExit("Could not create target machine");135 136  codegen::setFunctionAttributes(codegen::getCPUStr(),137                                 codegen::getFeaturesStr(), *M);138 139  // Add a pass that writes the optimized IR to an output stream140  std::string outString;141  raw_string_ostream OS(outString);142  RunOptimizationPasses(OS, *M, OLvl);143 144  return outString;145}146 147// Takes a function and runs it on a set of inputs148// First determines whether f is the optimized or unoptimized function149static void RunFuncOnInputs(LLVMFunc f, int Arr[kNumArrays][kArraySize]) {150  for (int i = 0; i < kNumArrays / 3; i++)151    f(Arr[i], Arr[i + (kNumArrays / 3)], Arr[i + (2 * kNumArrays / 3)],152      kArraySize);153}154 155// Takes a string of IR and compiles it using LLVM's JIT Engine156static void CreateAndRunJITFunc(const std::string &IR, CodeGenOptLevel OLvl) {157  SMDiagnostic Err;158  LLVMContext Context;159  std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);160  if (!M)161    ErrorAndExit("Could not parse IR");162 163  Function *EntryFunc = M->getFunction("foo");164  if (!EntryFunc)165    ErrorAndExit("Function not found in module");166 167  std::string ErrorMsg;168  Triple ModuleTriple(M->getTargetTriple());169 170  EngineBuilder builder(std::move(M));171  builder.setMArch(codegen::getMArch());172  builder.setMCPU(codegen::getCPUStr());173  builder.setMAttrs(codegen::getFeatureList());174  builder.setErrorStr(&ErrorMsg);175  builder.setEngineKind(EngineKind::JIT);176  builder.setMCJITMemoryManager(std::make_unique<SectionMemoryManager>());177  builder.setOptLevel(OLvl);178  builder.setTargetOptions(179      codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple));180 181  std::unique_ptr<ExecutionEngine> EE(builder.create());182  if (!EE)183    ErrorAndExit("Could not create execution engine");184 185  EE->finalizeObject();186  EE->runStaticConstructorsDestructors(false);187 188  LLVMFunc f = reinterpret_cast<LLVMFunc>(EE->getPointerToFunction(EntryFunc));189 190  // Figure out if we are running the optimized func or the unoptimized func191  RunFuncOnInputs(f, (OLvl == CodeGenOptLevel::None) ? UnoptArrays : OptArrays);192 193  EE->runStaticConstructorsDestructors(true);194}195 196// Main fuzz target called by ExampleClangLLVMProtoFuzzer.cpp197// Mimics the lli tool to JIT the LLVM IR code and execute it198void clang_fuzzer::HandleLLVM(const std::string &IR,199                              const std::vector<const char *> &ExtraArgs) {200  // Populate OptArrays and UnoptArrays with the arrays from InputArrays201  memcpy(OptArrays, InputArrays, kTotalSize);202  memcpy(UnoptArrays, InputArrays, kTotalSize);203 204  // Parse ExtraArgs to set the optimization level205  CodeGenOptLevel OLvl = getOptLevel(ExtraArgs);206 207  // First we optimize the IR by running a loop vectorizer pass208  std::string OptIR = OptLLVM(IR, OLvl);209 210  CreateAndRunJITFunc(OptIR, OLvl);211  CreateAndRunJITFunc(IR, CodeGenOptLevel::None);212 213  if (memcmp(OptArrays, UnoptArrays, kTotalSize))214    ErrorAndExit("!!!BUG!!!");215}216