1 //===-- AssemblerUtils.h ----------------------------------------*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_UNITTESTS_TOOLS_LLVMEXEGESIS_ASSEMBLERUTILS_H 10 #define LLVM_UNITTESTS_TOOLS_LLVMEXEGESIS_ASSEMBLERUTILS_H 11 12 #include "Assembler.h" 13 #include "BenchmarkRunner.h" 14 #include "Target.h" 15 #include "llvm/ADT/ArrayRef.h" 16 #include "llvm/CodeGen/MachineInstrBuilder.h" 17 #include "llvm/CodeGen/TargetInstrInfo.h" 18 #include "llvm/CodeGen/TargetSubtargetInfo.h" 19 #include "llvm/MC/MCInstBuilder.h" 20 #include "llvm/MC/TargetRegistry.h" 21 #include "llvm/Support/TargetSelect.h" 22 #include "llvm/TargetParser/Host.h" 23 #include "llvm/Testing/Support/Error.h" 24 #include "gmock/gmock.h" 25 #include "gtest/gtest.h" 26 27 namespace llvm { 28 namespace exegesis { 29 30 class MachineFunctionGeneratorBaseTest : public ::testing::Test { 31 protected: 32 MachineFunctionGeneratorBaseTest(const std::string &TT, 33 const std::string &CpuName) 34 : TT(TT), CpuName(CpuName), 35 CanExecute(Triple(TT).getArch() == 36 Triple(sys::getProcessTriple()).getArch()), 37 ET(ExegesisTarget::lookup(Triple(TT))) { 38 assert(ET); 39 if (!CanExecute) { 40 outs() << "Skipping execution, host:" << sys::getProcessTriple() 41 << ", target:" << TT << "\n"; 42 } 43 } 44 45 template <class... Bs> 46 inline void Check(ArrayRef<RegisterValue> RegisterInitialValues, MCInst Inst, 47 Bs... Bytes) { 48 ExecutableFunction Function = 49 (Inst.getOpcode() == 0) 50 ? assembleToFunction(RegisterInitialValues, [](FunctionFiller &) {}) 51 : assembleToFunction(RegisterInitialValues, 52 [Inst](FunctionFiller &Filler) { 53 Filler.getEntry().addInstruction(Inst); 54 }); 55 ASSERT_THAT(Function.getFunctionBytes().str(), 56 testing::ElementsAre(Bytes...)); 57 if (CanExecute) { 58 BenchmarkRunner::ScratchSpace Scratch; 59 Function(Scratch.ptr()); 60 } 61 } 62 63 private: 64 std::unique_ptr<TargetMachine> createTargetMachine() { 65 std::string Error; 66 const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error); 67 EXPECT_TRUE(TheTarget) << Error << " " << TT; 68 const TargetOptions Options; 69 TargetMachine *TM = TheTarget->createTargetMachine(TT, CpuName, "", Options, 70 Reloc::Model::Static); 71 EXPECT_TRUE(TM) << TT << " " << CpuName; 72 return std::unique_ptr<TargetMachine>(TM); 73 } 74 75 ExecutableFunction 76 assembleToFunction(ArrayRef<RegisterValue> RegisterInitialValues, 77 FillFunction Fill) { 78 SmallString<256> Buffer; 79 raw_svector_ostream AsmStream(Buffer); 80 BenchmarkKey Key; 81 Key.RegisterInitialValues = RegisterInitialValues; 82 EXPECT_FALSE(assembleToStream(*ET, createTargetMachine(), /*LiveIns=*/{}, 83 Fill, AsmStream, Key, false)); 84 Expected<ExecutableFunction> ExecFunc = ExecutableFunction::create( 85 createTargetMachine(), getObjectFromBuffer(AsmStream.str())); 86 87 // We can't use ASSERT_THAT_EXPECTED here as it doesn't work inside of 88 // non-void functions. 89 EXPECT_TRUE(detail::TakeExpected(ExecFunc).Success()); 90 return std::move(*ExecFunc); 91 } 92 93 const std::string TT; 94 const std::string CpuName; 95 const bool CanExecute; 96 const ExegesisTarget *const ET; 97 }; 98 99 } // namespace exegesis 100 } // namespace llvm 101 102 #endif 103