15e25291bSvporpo //===- SandboxIRBench.cpp -------------------------------------------------===// 25e25291bSvporpo // 35e25291bSvporpo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45e25291bSvporpo // See https://llvm.org/LICENSE.txt for license information. 55e25291bSvporpo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65e25291bSvporpo // 75e25291bSvporpo //===----------------------------------------------------------------------===// 85e25291bSvporpo // 95e25291bSvporpo // These tests measure the performance of some core SandboxIR functions and 105e25291bSvporpo // compare them against LLVM IR. 115e25291bSvporpo // 125e25291bSvporpo //===----------------------------------------------------------------------===// 135e25291bSvporpo 145e25291bSvporpo #include "benchmark/benchmark.h" 155e25291bSvporpo #include "llvm/AsmParser/Parser.h" 165e25291bSvporpo #include "llvm/IR/BasicBlock.h" 175e25291bSvporpo #include "llvm/IR/DataLayout.h" 185e25291bSvporpo #include "llvm/IR/Function.h" 195e25291bSvporpo #include "llvm/IR/Instruction.h" 205e25291bSvporpo #include "llvm/IR/Module.h" 21*e22b07e7Svporpo #include "llvm/SandboxIR/Function.h" 22eba106d4Svporpo #include "llvm/SandboxIR/Instruction.h" 23eba106d4Svporpo #include "llvm/SandboxIR/Module.h" 245e25291bSvporpo #include "llvm/Support/SourceMgr.h" 255e25291bSvporpo #include <memory> 2680c47ad3SJustin Bogner #include <sstream> 275e25291bSvporpo 285e25291bSvporpo using namespace llvm; 295e25291bSvporpo 305e25291bSvporpo static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 315e25291bSvporpo SMDiagnostic Err; 325e25291bSvporpo std::unique_ptr<Module> M = parseAssemblyString(IR, Err, C); 335e25291bSvporpo if (!M) 345e25291bSvporpo Err.print("SandboxIRBench", errs()); 355e25291bSvporpo return M; 365e25291bSvporpo } 375e25291bSvporpo 385e25291bSvporpo enum class IR { 390cfa5abdSvporpo LLVM, ///> LLVM IR 400cfa5abdSvporpo SBoxNoTracking, ///> Sandbox IR with tracking disabled 410cfa5abdSvporpo SBoxTracking, ///> Sandbox IR with tracking enabled 425e25291bSvporpo }; 435e25291bSvporpo // Traits to get llvm::BasicBlock/sandboxir::BasicBlock from IR::LLVM/IR::SBox. 445e25291bSvporpo template <IR IRTy> struct TypeSelect {}; 455e25291bSvporpo template <> struct TypeSelect<IR::LLVM> { 465e25291bSvporpo using BasicBlock = llvm::BasicBlock; 475e25291bSvporpo }; 480cfa5abdSvporpo template <> struct TypeSelect<IR::SBoxNoTracking> { 490cfa5abdSvporpo using BasicBlock = sandboxir::BasicBlock; 500cfa5abdSvporpo }; 510cfa5abdSvporpo template <> struct TypeSelect<IR::SBoxTracking> { 525e25291bSvporpo using BasicBlock = sandboxir::BasicBlock; 535e25291bSvporpo }; 545e25291bSvporpo 555e25291bSvporpo template <IR IRTy> 565e25291bSvporpo static typename TypeSelect<IRTy>::BasicBlock * 575e25291bSvporpo genIR(std::unique_ptr<llvm::Module> &LLVMM, LLVMContext &LLVMCtx, 585e25291bSvporpo sandboxir::Context &Ctx, 595e25291bSvporpo std::function<std::string(unsigned)> GenerateIRStr, 605e25291bSvporpo unsigned NumInstrs = 0u) { 615e25291bSvporpo std::string IRStr = GenerateIRStr(NumInstrs); 625e25291bSvporpo LLVMM = parseIR(LLVMCtx, IRStr.c_str()); 635e25291bSvporpo llvm::Function *LLVMF = &*LLVMM->getFunction("foo"); 645e25291bSvporpo llvm::BasicBlock *LLVMBB = &*LLVMF->begin(); 655e25291bSvporpo 665e25291bSvporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 675e25291bSvporpo sandboxir::BasicBlock *BB = &*F->begin(); 680cfa5abdSvporpo // Start tracking if we are testing with tracking enabled. 690cfa5abdSvporpo if constexpr (IRTy == IR::SBoxTracking) 700cfa5abdSvporpo Ctx.save(); 710cfa5abdSvporpo 725e25291bSvporpo if constexpr (IRTy == IR::LLVM) 735e25291bSvporpo return LLVMBB; 745e25291bSvporpo else 755e25291bSvporpo return BB; 765e25291bSvporpo } 775e25291bSvporpo 780cfa5abdSvporpo template <IR IRTy> static void finalize(sandboxir::Context &Ctx) { 790cfa5abdSvporpo // Accept changes if we are tracking. 800cfa5abdSvporpo if constexpr (IRTy == IR::SBoxTracking) 810cfa5abdSvporpo Ctx.accept(); 820cfa5abdSvporpo } 830cfa5abdSvporpo 845e25291bSvporpo static std::string generateBBWalkIR(unsigned Size) { 855e25291bSvporpo std::stringstream SS; 865e25291bSvporpo SS << "define void @foo(i32 %v1, i32 %v2) {\n"; 875e25291bSvporpo for (auto Cnt : seq<unsigned>(0, Size)) 885e25291bSvporpo SS << " %add" << Cnt << " = add i32 %v1, %v2\n"; 895e25291bSvporpo SS << "ret void"; 905e25291bSvporpo SS << "}"; 915e25291bSvporpo return SS.str(); 925e25291bSvporpo } 935e25291bSvporpo 9431d48372Svporpo template <IR IRTy> static void SBoxIRCreation(benchmark::State &State) { 9531d48372Svporpo static_assert(IRTy != IR::LLVM, "Expected SBoxTracking or SBoxNoTracking"); 9631d48372Svporpo LLVMContext LLVMCtx; 9731d48372Svporpo unsigned NumInstrs = State.range(0); 9831d48372Svporpo std::unique_ptr<llvm::Module> LLVMM; 9931d48372Svporpo std::string IRStr = generateBBWalkIR(NumInstrs); 10031d48372Svporpo LLVMM = parseIR(LLVMCtx, IRStr.c_str()); 10131d48372Svporpo llvm::Function *LLVMF = &*LLVMM->getFunction("foo"); 10231d48372Svporpo 10331d48372Svporpo for (auto _ : State) { 10431d48372Svporpo State.PauseTiming(); 10531d48372Svporpo sandboxir::Context Ctx(LLVMCtx); 10631d48372Svporpo if constexpr (IRTy == IR::SBoxTracking) 10731d48372Svporpo Ctx.save(); 10831d48372Svporpo State.ResumeTiming(); 10931d48372Svporpo 11031d48372Svporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 11131d48372Svporpo benchmark::DoNotOptimize(F); 11231d48372Svporpo State.PauseTiming(); 11331d48372Svporpo if constexpr (IRTy == IR::SBoxTracking) 11431d48372Svporpo Ctx.accept(); 11531d48372Svporpo State.ResumeTiming(); 11631d48372Svporpo } 11731d48372Svporpo } 11831d48372Svporpo 1195e25291bSvporpo template <IR IRTy> static void BBWalk(benchmark::State &State) { 1205e25291bSvporpo LLVMContext LLVMCtx; 1215e25291bSvporpo sandboxir::Context Ctx(LLVMCtx); 1225e25291bSvporpo unsigned NumInstrs = State.range(0); 1235e25291bSvporpo std::unique_ptr<llvm::Module> LLVMM; 1245e25291bSvporpo auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateBBWalkIR, NumInstrs); 1255e25291bSvporpo for (auto _ : State) { 1265e25291bSvporpo // Walk LLVM Instructions. 1275e25291bSvporpo for (auto &I : *BB) 1285e25291bSvporpo benchmark::DoNotOptimize(I); 1295e25291bSvporpo } 1305e25291bSvporpo } 1315e25291bSvporpo 1325e25291bSvporpo static std::string generateGetTypeIR(unsigned Size) { 1335e25291bSvporpo return R"IR( 1345e25291bSvporpo define void @foo(i32 %v1, i32 %v2) { 1355e25291bSvporpo %add = add i32 %v1, %v2 1365e25291bSvporpo ret void 1375e25291bSvporpo } 1385e25291bSvporpo )IR"; 1395e25291bSvporpo } 1405e25291bSvporpo 1415e25291bSvporpo template <IR IRTy> static void GetType(benchmark::State &State) { 1425e25291bSvporpo LLVMContext LLVMCtx; 1435e25291bSvporpo sandboxir::Context Ctx(LLVMCtx); 1445e25291bSvporpo std::unique_ptr<llvm::Module> LLVMM; 1455e25291bSvporpo auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateGetTypeIR); 1465e25291bSvporpo auto *I = &*BB->begin(); 1475e25291bSvporpo for (auto _ : State) 1485e25291bSvporpo benchmark::DoNotOptimize(I->getType()); 1495e25291bSvporpo } 1505e25291bSvporpo 151362da640Svporpo static std::string generateRAUWIR(unsigned Size) { 152362da640Svporpo std::stringstream SS; 153362da640Svporpo SS << "define void @foo(i32 %v1, i32 %v2) {\n"; 154362da640Svporpo SS << " %def1 = add i32 %v1, %v2\n"; 155362da640Svporpo SS << " %def2 = add i32 %v1, %v2\n"; 156362da640Svporpo for (auto Cnt : seq<unsigned>(0, Size)) 157362da640Svporpo SS << " %add" << Cnt << " = add i32 %def1, %def1\n"; 158362da640Svporpo SS << "ret void"; 159362da640Svporpo SS << "}"; 160362da640Svporpo return SS.str(); 161362da640Svporpo } 162362da640Svporpo 163362da640Svporpo template <IR IRTy> static void RAUW(benchmark::State &State) { 164362da640Svporpo LLVMContext LLVMCtx; 165362da640Svporpo sandboxir::Context Ctx(LLVMCtx); 166362da640Svporpo std::unique_ptr<llvm::Module> LLVMM; 167362da640Svporpo unsigned NumInstrs = State.range(0); 168362da640Svporpo auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateRAUWIR, NumInstrs); 169362da640Svporpo auto It = BB->begin(); 170362da640Svporpo auto *Def1 = &*It++; 171362da640Svporpo auto *Def2 = &*It++; 172362da640Svporpo for (auto _ : State) { 173362da640Svporpo Def1->replaceAllUsesWith(Def2); 174362da640Svporpo Def2->replaceAllUsesWith(Def1); 175362da640Svporpo } 1760cfa5abdSvporpo finalize<IRTy>(Ctx); 177362da640Svporpo } 178362da640Svporpo 179bd4e0dfaSvporpo static std::string generateRUOWIR(unsigned NumOperands) { 180bd4e0dfaSvporpo std::stringstream SS; 181bd4e0dfaSvporpo auto GenOps = [&SS, NumOperands]() { 182bd4e0dfaSvporpo for (auto Cnt : seq<unsigned>(0, NumOperands)) { 183bd4e0dfaSvporpo SS << "i8 %arg" << Cnt; 184bd4e0dfaSvporpo bool IsLast = Cnt + 1 == NumOperands; 185bd4e0dfaSvporpo if (!IsLast) 186bd4e0dfaSvporpo SS << ", "; 187bd4e0dfaSvporpo } 188bd4e0dfaSvporpo }; 189bd4e0dfaSvporpo 190bd4e0dfaSvporpo SS << "define void @foo("; 191bd4e0dfaSvporpo GenOps(); 192bd4e0dfaSvporpo SS << ") {\n"; 193bd4e0dfaSvporpo 194bd4e0dfaSvporpo SS << " call void @foo("; 195bd4e0dfaSvporpo GenOps(); 196bd4e0dfaSvporpo SS << ")\n"; 197bd4e0dfaSvporpo SS << "ret void"; 198bd4e0dfaSvporpo SS << "}"; 199bd4e0dfaSvporpo return SS.str(); 200bd4e0dfaSvporpo } 201bd4e0dfaSvporpo 202bd4e0dfaSvporpo template <IR IRTy> static void RUOW(benchmark::State &State) { 203bd4e0dfaSvporpo LLVMContext LLVMCtx; 204bd4e0dfaSvporpo sandboxir::Context Ctx(LLVMCtx); 205bd4e0dfaSvporpo std::unique_ptr<llvm::Module> LLVMM; 206bd4e0dfaSvporpo unsigned NumOperands = State.range(0); 207bd4e0dfaSvporpo auto *BB = genIR<IRTy>(LLVMM, LLVMCtx, Ctx, generateRUOWIR, NumOperands); 208bd4e0dfaSvporpo 209bd4e0dfaSvporpo auto It = BB->begin(); 210bd4e0dfaSvporpo auto *F = BB->getParent(); 211bd4e0dfaSvporpo auto *Arg0 = F->getArg(0); 212bd4e0dfaSvporpo auto *Arg1 = F->getArg(1); 213bd4e0dfaSvporpo auto *Call = &*It++; 214bd4e0dfaSvporpo for (auto _ : State) 215bd4e0dfaSvporpo Call->replaceUsesOfWith(Arg0, Arg1); 2160cfa5abdSvporpo finalize<IRTy>(Ctx); 217bd4e0dfaSvporpo } 218bd4e0dfaSvporpo 21931d48372Svporpo // Measure the time it takes to create Sandbox IR without/with tracking. 22031d48372Svporpo BENCHMARK(SBoxIRCreation<IR::SBoxNoTracking>) 22131d48372Svporpo ->Args({10}) 22231d48372Svporpo ->Args({100}) 22331d48372Svporpo ->Args({1000}); 22431d48372Svporpo BENCHMARK(SBoxIRCreation<IR::SBoxTracking>) 22531d48372Svporpo ->Args({10}) 22631d48372Svporpo ->Args({100}) 22731d48372Svporpo ->Args({1000}); 22831d48372Svporpo 2295e25291bSvporpo BENCHMARK(GetType<IR::LLVM>); 2300cfa5abdSvporpo BENCHMARK(GetType<IR::SBoxNoTracking>); 2315e25291bSvporpo 2325e25291bSvporpo BENCHMARK(BBWalk<IR::LLVM>)->Args({1024}); 2330cfa5abdSvporpo BENCHMARK(BBWalk<IR::SBoxTracking>)->Args({1024}); 2345e25291bSvporpo 235362da640Svporpo BENCHMARK(RAUW<IR::LLVM>)->Args({512}); 2360cfa5abdSvporpo BENCHMARK(RAUW<IR::SBoxNoTracking>)->Args({512}); 2370cfa5abdSvporpo BENCHMARK(RAUW<IR::SBoxTracking>)->Args({512}); 238362da640Svporpo 239bd4e0dfaSvporpo BENCHMARK(RUOW<IR::LLVM>)->Args({4096}); 2400cfa5abdSvporpo BENCHMARK(RUOW<IR::SBoxNoTracking>)->Args({4096}); 2410cfa5abdSvporpo BENCHMARK(RUOW<IR::SBoxTracking>)->Args({4096}); 242bd4e0dfaSvporpo 2435e25291bSvporpo BENCHMARK_MAIN(); 244