xref: /llvm-project/llvm/benchmarks/SandboxIRBench.cpp (revision e22b07e766e415d6a0ed4c73fe5286fcf25f8d98)
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