//===- SandboxIRBench.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // These tests measure the performance of some core SandboxIR functions and // compare them against LLVM IR. // //===----------------------------------------------------------------------===// #include "benchmark/benchmark.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Module.h" #include "llvm/SandboxIR/SandboxIR.h" #include "llvm/Support/SourceMgr.h" #include #include using namespace llvm; static std::unique_ptr parseIR(LLVMContext &C, const char *IR) { SMDiagnostic Err; std::unique_ptr M = parseAssemblyString(IR, Err, C); if (!M) Err.print("SandboxIRBench", errs()); return M; } enum class IR { LLVM, SBox, }; // Traits to get llvm::BasicBlock/sandboxir::BasicBlock from IR::LLVM/IR::SBox. template struct TypeSelect {}; template <> struct TypeSelect { using BasicBlock = llvm::BasicBlock; }; template <> struct TypeSelect { using BasicBlock = sandboxir::BasicBlock; }; template static typename TypeSelect::BasicBlock * genIR(std::unique_ptr &LLVMM, LLVMContext &LLVMCtx, sandboxir::Context &Ctx, std::function GenerateIRStr, unsigned NumInstrs = 0u) { std::string IRStr = GenerateIRStr(NumInstrs); LLVMM = parseIR(LLVMCtx, IRStr.c_str()); llvm::Function *LLVMF = &*LLVMM->getFunction("foo"); llvm::BasicBlock *LLVMBB = &*LLVMF->begin(); sandboxir::Function *F = Ctx.createFunction(LLVMF); sandboxir::BasicBlock *BB = &*F->begin(); if constexpr (IRTy == IR::LLVM) return LLVMBB; else return BB; } static std::string generateBBWalkIR(unsigned Size) { std::stringstream SS; SS << "define void @foo(i32 %v1, i32 %v2) {\n"; for (auto Cnt : seq(0, Size)) SS << " %add" << Cnt << " = add i32 %v1, %v2\n"; SS << "ret void"; SS << "}"; return SS.str(); } template static void BBWalk(benchmark::State &State) { LLVMContext LLVMCtx; sandboxir::Context Ctx(LLVMCtx); unsigned NumInstrs = State.range(0); std::unique_ptr LLVMM; auto *BB = genIR(LLVMM, LLVMCtx, Ctx, generateBBWalkIR, NumInstrs); for (auto _ : State) { // Walk LLVM Instructions. for (auto &I : *BB) benchmark::DoNotOptimize(I); } } static std::string generateGetTypeIR(unsigned Size) { return R"IR( define void @foo(i32 %v1, i32 %v2) { %add = add i32 %v1, %v2 ret void } )IR"; } template static void GetType(benchmark::State &State) { LLVMContext LLVMCtx; sandboxir::Context Ctx(LLVMCtx); std::unique_ptr LLVMM; auto *BB = genIR(LLVMM, LLVMCtx, Ctx, generateGetTypeIR); auto *I = &*BB->begin(); for (auto _ : State) benchmark::DoNotOptimize(I->getType()); } static std::string generateRAUWIR(unsigned Size) { std::stringstream SS; SS << "define void @foo(i32 %v1, i32 %v2) {\n"; SS << " %def1 = add i32 %v1, %v2\n"; SS << " %def2 = add i32 %v1, %v2\n"; for (auto Cnt : seq(0, Size)) SS << " %add" << Cnt << " = add i32 %def1, %def1\n"; SS << "ret void"; SS << "}"; return SS.str(); } template static void RAUW(benchmark::State &State) { LLVMContext LLVMCtx; sandboxir::Context Ctx(LLVMCtx); std::unique_ptr LLVMM; unsigned NumInstrs = State.range(0); auto *BB = genIR(LLVMM, LLVMCtx, Ctx, generateRAUWIR, NumInstrs); auto It = BB->begin(); auto *Def1 = &*It++; auto *Def2 = &*It++; for (auto _ : State) { Def1->replaceAllUsesWith(Def2); Def2->replaceAllUsesWith(Def1); } } BENCHMARK(GetType); BENCHMARK(GetType); BENCHMARK(BBWalk)->Args({1024}); BENCHMARK(BBWalk)->Args({1024}); BENCHMARK(RAUW)->Args({512}); BENCHMARK(RAUW)->Args({512}); BENCHMARK_MAIN();