Index: llvm/trunk/tools/llvm-exegesis/lib/AArch64/Target.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/AArch64/Target.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/AArch64/Target.cpp @@ -9,6 +9,7 @@ #include "../Target.h" #include "../Latency.h" #include "AArch64.h" +#include "AArch64RegisterInfo.h" namespace exegesis { @@ -26,38 +27,51 @@ } }; -class ExegesisAArch64Target : public ExegesisTarget { - std::vector setRegToConstant(const llvm::MCSubtargetInfo &STI, - unsigned Reg) const override { - llvm_unreachable("Not yet implemented"); - } +namespace { - std::vector setRegTo(const llvm::MCSubtargetInfo &STI, - const llvm::APInt &Value, - unsigned Reg) const override { - llvm_unreachable("Not yet implemented"); +static unsigned getLoadImmediateOpcode(unsigned RegBitWidth) { + switch (RegBitWidth) { + case 32: + return llvm::AArch64::MOVi32imm; + case 64: + return llvm::AArch64::MOVi64imm; } + llvm_unreachable("Invalid Value Width"); +} - unsigned getScratchMemoryRegister(const llvm::Triple &) const override { - llvm_unreachable("Not yet implemented"); - } +// Generates instruction to load an immediate value into a register. +static llvm::MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth, + const llvm::APInt &Value) { + if (Value.getBitWidth() > RegBitWidth) + llvm_unreachable("Value must fit in the Register"); + return llvm::MCInstBuilder(getLoadImmediateOpcode(RegBitWidth)) + .addReg(Reg) + .addImm(Value.getZExtValue()); +} - void fillMemoryOperands(InstructionBuilder &IB, unsigned Reg, - unsigned Offset) const override { - llvm_unreachable("Not yet implemented"); - } +} // namespace - unsigned getMaxMemoryAccessSize() const override { - llvm_unreachable("Not yet implemented"); +class ExegesisAArch64Target : public ExegesisTarget { + std::vector setRegTo(const llvm::MCSubtargetInfo &STI, + unsigned Reg, + const llvm::APInt &Value) const override { + if (llvm::AArch64::GPR32RegClass.contains(Reg)) + return {loadImmediate(Reg, 32, Value)}; + if (llvm::AArch64::GPR64RegClass.contains(Reg)) + return {loadImmediate(Reg, 64, Value)}; + llvm::errs() << "setRegTo is not implemented, results will be unreliable\n"; + return {}; } bool matchesArch(llvm::Triple::ArchType Arch) const override { return Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be; } + void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override { // Function return is a pseudo-instruction that needs to be expanded PM.add(llvm::createAArch64ExpandPseudoPass()); } + std::unique_ptr createLatencyBenchmarkRunner(const LLVMState &State) const override { return llvm::make_unique(State); Index: llvm/trunk/tools/llvm-exegesis/lib/Assembler.h =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/Assembler.h +++ llvm/trunk/tools/llvm-exegesis/lib/Assembler.h @@ -39,6 +39,12 @@ // convention and target machine). llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM); +// A simple object storing the value for a particular register. +struct RegisterValue { + unsigned Register; + llvm::APInt Value; +}; + // Creates a temporary `void foo(char*)` function containing the provided // Instructions. Runs a set of llvm Passes to provide correct prologue and // epilogue. Once the MachineFunction is ready, it is assembled for TM to @@ -46,7 +52,7 @@ void assembleToStream(const ExegesisTarget &ET, std::unique_ptr TM, llvm::ArrayRef LiveIns, - llvm::ArrayRef RegsToDef, + llvm::ArrayRef RegisterInitialValues, llvm::ArrayRef Instructions, llvm::raw_pwrite_stream &AsmStream); Index: llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/Assembler.cpp @@ -29,17 +29,17 @@ static constexpr const char FunctionID[] = "foo"; static std::vector -generateSnippetSetupCode(const llvm::ArrayRef RegsToDef, - const ExegesisTarget &ET, - const llvm::LLVMTargetMachine &TM, bool &IsComplete) { - IsComplete = true; +generateSnippetSetupCode(const ExegesisTarget &ET, + const llvm::MCSubtargetInfo *const MSI, + llvm::ArrayRef RegisterInitialValues, + bool &IsSnippetSetupComplete) { std::vector Result; - for (const unsigned Reg : RegsToDef) { + for (const RegisterValue &RV : RegisterInitialValues) { // Load a constant in the register. - const auto Code = ET.setRegToConstant(*TM.getMCSubtargetInfo(), Reg); - if (Code.empty()) - IsComplete = false; - Result.insert(Result.end(), Code.begin(), Code.end()); + const auto SetRegisterCode = ET.setRegTo(*MSI, RV.Register, RV.Value); + if (SetRegisterCode.empty()) + IsSnippetSetupComplete = false; + Result.insert(Result.end(), SetRegisterCode.begin(), SetRegisterCode.end()); } return Result; } @@ -149,7 +149,7 @@ void assembleToStream(const ExegesisTarget &ET, std::unique_ptr TM, llvm::ArrayRef LiveIns, - llvm::ArrayRef RegsToDef, + llvm::ArrayRef RegisterInitialValues, llvm::ArrayRef Instructions, llvm::raw_pwrite_stream &AsmStream) { std::unique_ptr Context = @@ -171,13 +171,12 @@ MF.getRegInfo().addLiveIn(Reg); bool IsSnippetSetupComplete = false; - std::vector SnippetWithSetup = - generateSnippetSetupCode(RegsToDef, ET, *TM, IsSnippetSetupComplete); - if (!SnippetWithSetup.empty()) { - SnippetWithSetup.insert(SnippetWithSetup.end(), Instructions.begin(), - Instructions.end()); - Instructions = SnippetWithSetup; - } + std::vector Code = + generateSnippetSetupCode(ET, TM->getMCSubtargetInfo(), + RegisterInitialValues, IsSnippetSetupComplete); + + Code.insert(Code.end(), Instructions.begin(), Instructions.end()); + // If the snippet setup is not complete, we disable liveliness tracking. This // means that we won't know what values are in the registers. if (!IsSnippetSetupComplete) @@ -188,7 +187,7 @@ MF.getRegInfo().freezeReservedRegs(MF); // Fill the MachineFunction from the instructions. - fillMachineFunction(MF, LiveIns, Instructions); + fillMachineFunction(MF, LiveIns, Code); // We create the pass manager, run the passes to populate AsmBuffer. llvm::MCContext &MCContext = MMI->getContext(); Index: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkCode.h =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkCode.h +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkCode.h @@ -23,7 +23,7 @@ // Before the code is executed some instructions are added to setup the // registers initial values. - std::vector RegsToDef; + std::vector RegisterInitialValues; // We also need to provide the registers that are live on entry for the // assembler to generate proper prologue/epilogue. Index: llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -104,7 +104,7 @@ return std::move(E); llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/); assembleToStream(State.getExegesisTarget(), State.createTargetMachine(), - BC.LiveIns, BC.RegsToDef, Code, OFS); + BC.LiveIns, BC.RegisterInitialValues, Code, OFS); return ResultPath.str(); } Index: llvm/trunk/tools/llvm-exegesis/lib/SnippetGenerator.h =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/SnippetGenerator.h +++ llvm/trunk/tools/llvm-exegesis/lib/SnippetGenerator.h @@ -48,8 +48,8 @@ generateConfigurations(unsigned Opcode) const; // Given a snippet, computes which registers the setup code needs to define. - std::vector - computeRegsToDef(const std::vector &Snippet) const; + std::vector computeRegisterInitialValues( + const std::vector &Snippet) const; protected: const LLVMState &State; Index: llvm/trunk/tools/llvm-exegesis/lib/SnippetGenerator.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/SnippetGenerator.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/SnippetGenerator.cpp @@ -49,7 +49,7 @@ } if (CT.ScratchSpacePointerInReg) BC.LiveIns.push_back(CT.ScratchSpacePointerInReg); - BC.RegsToDef = computeRegsToDef(CT.Instructions); + BC.RegisterInitialValues = computeRegisterInitialValues(CT.Instructions); Output.push_back(std::move(BC)); } return Output; @@ -57,14 +57,14 @@ return E.takeError(); } -std::vector SnippetGenerator::computeRegsToDef( +std::vector SnippetGenerator::computeRegisterInitialValues( const std::vector &Instructions) const { // Collect all register uses and create an assignment for each of them. // Ignore memory operands which are handled separately. // Loop invariant: DefinedRegs[i] is true iif it has been set at least once // before the current instruction. llvm::BitVector DefinedRegs = RATC.emptyRegisters(); - std::vector RegsToDef; + std::vector RIV; for (const InstructionBuilder &IB : Instructions) { // Returns the register that this Operand sets or uses, or 0 if this is not // a register. @@ -82,7 +82,7 @@ if (!Op.IsDef) { const unsigned Reg = GetOpReg(Op); if (Reg > 0 && !DefinedRegs.test(Reg)) { - RegsToDef.push_back(Reg); + RIV.push_back(RegisterValue{Reg, llvm::APInt()}); DefinedRegs.set(Reg); } } @@ -96,7 +96,7 @@ } } } - return RegsToDef; + return RIV; } llvm::Expected SnippetGenerator::generateSelfAliasingCodeTemplate( Index: llvm/trunk/tools/llvm-exegesis/lib/Target.h =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/Target.h +++ llvm/trunk/tools/llvm-exegesis/lib/Target.h @@ -36,29 +36,32 @@ virtual void addTargetSpecificPasses(llvm::PassManagerBase &PM) const {} // Generates code to move a constant into a the given register. + // Precondition: Value must fit into Reg. virtual std::vector - setRegToConstant(const llvm::MCSubtargetInfo &STI, unsigned Reg) const = 0; - - // Generates code to move a constant into a the given register. - virtual std::vector setRegTo(const llvm::MCSubtargetInfo &STI, - const llvm::APInt &Value, - unsigned Reg) const = 0; + setRegTo(const llvm::MCSubtargetInfo &STI, unsigned Reg, + const llvm::APInt &Value) const = 0; // Returns the register pointing to scratch memory, or 0 if this target // does not support memory operands. The benchmark function uses the // default calling convention. - virtual unsigned getScratchMemoryRegister(const llvm::Triple &) const = 0; + virtual unsigned getScratchMemoryRegister(const llvm::Triple &) const { + return 0; + } // Fills memory operands with references to the address at [Reg] + Offset. virtual void fillMemoryOperands(InstructionBuilder &IB, unsigned Reg, - unsigned Offset) const = 0; + unsigned Offset) const { + + llvm_unreachable( + "fillMemoryOperands() requires getScratchMemoryRegister() > 0"); + } // Returns the maximum number of bytes a load/store instruction can access at // once. This is typically the size of the largest register available on the // processor. Note that this only used as a hint to generate independant // load/stores to/from memory, so the exact returned value does not really // matter as long as it's large enough. - virtual unsigned getMaxMemoryAccessSize() const = 0; + virtual unsigned getMaxMemoryAccessSize() const { return 0; } // Creates a snippet generator for the given mode. std::unique_ptr Index: llvm/trunk/tools/llvm-exegesis/lib/Target.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/Target.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/Target.cpp @@ -89,27 +89,9 @@ // Default implementation. class ExegesisDefaultTarget : public ExegesisTarget { private: - std::vector setRegToConstant(const llvm::MCSubtargetInfo &STI, - unsigned Reg) const override { - llvm_unreachable("Not yet implemented"); - } - std::vector setRegTo(const llvm::MCSubtargetInfo &STI, - const llvm::APInt &Value, - unsigned Reg) const override { - llvm_unreachable("Not yet implemented"); - } - - unsigned getScratchMemoryRegister(const llvm::Triple &) const override { - llvm_unreachable("Not yet implemented"); - } - - void fillMemoryOperands(InstructionBuilder &IB, unsigned Reg, - unsigned Offset) const override { - llvm_unreachable("Not yet implemented"); - } - - unsigned getMaxMemoryAccessSize() const override { + unsigned Reg, + const llvm::APInt &Value) const override { llvm_unreachable("Not yet implemented"); } Index: llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp =================================================================== --- llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp +++ llvm/trunk/tools/llvm-exegesis/lib/X86/Target.cpp @@ -101,8 +101,8 @@ } }; -static unsigned GetLoadImmediateOpcode(const llvm::APInt &Value) { - switch (Value.getBitWidth()) { +static unsigned GetLoadImmediateOpcode(unsigned RegBitWidth) { + switch (RegBitWidth) { case 8: return llvm::X86::MOV8ri; case 16: @@ -115,8 +115,12 @@ llvm_unreachable("Invalid Value Width"); } -static llvm::MCInst loadImmediate(unsigned Reg, const llvm::APInt &Value) { - return llvm::MCInstBuilder(GetLoadImmediateOpcode(Value)) +// Generates instruction to load an immediate value into a register. +static llvm::MCInst loadImmediate(unsigned Reg, unsigned RegBitWidth, + const llvm::APInt &Value) { + if (Value.getBitWidth() > RegBitWidth) + llvm_unreachable("Value must fit in the Register"); + return llvm::MCInstBuilder(GetLoadImmediateOpcode(RegBitWidth)) .addReg(Reg) .addImm(Value.getZExtValue()); } @@ -163,39 +167,67 @@ .addImm(Bytes); } +// Reserves some space on the stack, fills it with the content of the provided +// constant and provide methods to load the stack value into a register. struct ConstantInliner { explicit ConstantInliner(const llvm::APInt &Constant) : StackSize(Constant.getBitWidth() / 8) { assert(Constant.getBitWidth() % 8 == 0 && "Must be a multiple of 8"); - Add(allocateStackSpace(StackSize)); + add(allocateStackSpace(StackSize)); size_t ByteOffset = 0; for (; StackSize - ByteOffset >= 4; ByteOffset += 4) - Add(fillStackSpace( + add(fillStackSpace( llvm::X86::MOV32mi, ByteOffset, Constant.extractBits(32, ByteOffset * 8).getZExtValue())); if (StackSize - ByteOffset >= 2) { - Add(fillStackSpace( + add(fillStackSpace( llvm::X86::MOV16mi, ByteOffset, Constant.extractBits(16, ByteOffset * 8).getZExtValue())); ByteOffset += 2; } if (StackSize - ByteOffset >= 1) - Add(fillStackSpace( + add(fillStackSpace( llvm::X86::MOV8mi, ByteOffset, Constant.extractBits(8, ByteOffset * 8).getZExtValue())); } - ConstantInliner &Add(const llvm::MCInst &Inst) { - Instructions.push_back(Inst); - return *this; + std::vector loadAndFinalize(unsigned Reg, unsigned RegBitWidth, + unsigned Opcode) { + assert(StackSize * 8 == RegBitWidth && + "Value does not have the correct size"); + add(loadToReg(Reg, Opcode)); + add(releaseStackSpace(StackSize)); + return std::move(Instructions); + } + + std::vector + loadX87AndFinalize(unsigned Reg, unsigned RegBitWidth, unsigned Opcode) { + assert(StackSize * 8 == RegBitWidth && + "Value does not have the correct size"); + add(llvm::MCInstBuilder(Opcode) + .addReg(llvm::X86::RSP) // BaseReg + .addImm(1) // ScaleAmt + .addReg(0) // IndexReg + .addImm(0) // Disp + .addReg(0)); // Segment + if (Reg != llvm::X86::ST0) + add(llvm::MCInstBuilder(llvm::X86::ST_Frr).addReg(Reg)); + add(releaseStackSpace(StackSize)); + return std::move(Instructions); } - std::vector finalize() { - Add(releaseStackSpace(StackSize)); + std::vector popFlagAndFinalize() { + assert(StackSize * 8 == 64 && "Value does not have the correct size"); + add(llvm::MCInstBuilder(llvm::X86::POPF64)); return std::move(Instructions); } private: + ConstantInliner &add(const llvm::MCInst &Inst) { + Instructions.push_back(Inst); + return *this; + } + const size_t StackSize; std::vector Instructions; }; @@ -248,64 +280,47 @@ } } - std::vector setRegToConstant(const llvm::MCSubtargetInfo &STI, - unsigned Reg) const override { - // GPR. + std::vector setRegTo(const llvm::MCSubtargetInfo &STI, + unsigned Reg, + const llvm::APInt &Value) const override { if (llvm::X86::GR8RegClass.contains(Reg)) - return {llvm::MCInstBuilder(llvm::X86::MOV8ri).addReg(Reg).addImm(1)}; + return {loadImmediate(Reg, 8, Value)}; if (llvm::X86::GR16RegClass.contains(Reg)) - return {llvm::MCInstBuilder(llvm::X86::MOV16ri).addReg(Reg).addImm(1)}; + return {loadImmediate(Reg, 16, Value)}; if (llvm::X86::GR32RegClass.contains(Reg)) - return {llvm::MCInstBuilder(llvm::X86::MOV32ri).addReg(Reg).addImm(1)}; + return {loadImmediate(Reg, 32, Value)}; if (llvm::X86::GR64RegClass.contains(Reg)) - return {llvm::MCInstBuilder(llvm::X86::MOV64ri32).addReg(Reg).addImm(1)}; - // MMX. + return {loadImmediate(Reg, 64, Value)}; + ConstantInliner CI(Value); if (llvm::X86::VR64RegClass.contains(Reg)) - return setVectorRegToConstant(Reg, 8, llvm::X86::MMX_MOVQ64rm); - // {X,Y,Z}MM. + return CI.loadAndFinalize(Reg, 64, llvm::X86::MMX_MOVQ64rm); if (llvm::X86::VR128XRegClass.contains(Reg)) { if (STI.getFeatureBits()[llvm::X86::FeatureAVX512]) - return setVectorRegToConstant(Reg, 16, llvm::X86::VMOVDQU32Z128rm); + return CI.loadAndFinalize(Reg, 128, llvm::X86::VMOVDQU32Z128rm); if (STI.getFeatureBits()[llvm::X86::FeatureAVX]) - return setVectorRegToConstant(Reg, 16, llvm::X86::VMOVDQUrm); - return setVectorRegToConstant(Reg, 16, llvm::X86::MOVDQUrm); + return CI.loadAndFinalize(Reg, 128, llvm::X86::VMOVDQUrm); + return CI.loadAndFinalize(Reg, 128, llvm::X86::MOVDQUrm); } if (llvm::X86::VR256XRegClass.contains(Reg)) { if (STI.getFeatureBits()[llvm::X86::FeatureAVX512]) - return setVectorRegToConstant(Reg, 32, llvm::X86::VMOVDQU32Z256rm); - return setVectorRegToConstant(Reg, 32, llvm::X86::VMOVDQUYrm); + return CI.loadAndFinalize(Reg, 256, llvm::X86::VMOVDQU32Z256rm); + if (STI.getFeatureBits()[llvm::X86::FeatureAVX]) + return CI.loadAndFinalize(Reg, 256, llvm::X86::VMOVDQUYrm); } if (llvm::X86::VR512RegClass.contains(Reg)) - return setVectorRegToConstant(Reg, 64, llvm::X86::VMOVDQU32Zrm); - // X87. - if (llvm::X86::RFP32RegClass.contains(Reg) || - llvm::X86::RFP64RegClass.contains(Reg) || - llvm::X86::RFP80RegClass.contains(Reg)) - return setVectorRegToConstant(Reg, 8, llvm::X86::LD_Fp64m); - if (Reg == llvm::X86::EFLAGS) { - // Set all flags to 0 but the bits that are "reserved and set to 1". - constexpr const uint32_t kImmValue = 0x00007002u; - std::vector Result; - Result.push_back(allocateStackSpace(8)); - Result.push_back(fillStackSpace(llvm::X86::MOV64mi32, 0, kImmValue)); - Result.push_back(llvm::MCInstBuilder(llvm::X86::POPF64)); // Also pops. - return Result; + if (STI.getFeatureBits()[llvm::X86::FeatureAVX512]) + return CI.loadAndFinalize(Reg, 512, llvm::X86::VMOVDQU32Zrm); + if (llvm::X86::RSTRegClass.contains(Reg)) { + if (Value.getBitWidth() == 32) + return CI.loadX87AndFinalize(Reg, 32, llvm::X86::LD_F32m); + if (Value.getBitWidth() == 64) + return CI.loadX87AndFinalize(Reg, 64, llvm::X86::LD_F64m); + if (Value.getBitWidth() == 80) + return CI.loadX87AndFinalize(Reg, 80, llvm::X86::LD_F80m); } - llvm_unreachable("Not yet implemented"); - } - - std::vector setRegTo(const llvm::MCSubtargetInfo &STI, - const llvm::APInt &Value, - unsigned Reg) const override { - if (llvm::X86::GR8RegClass.contains(Reg) || - llvm::X86::GR16RegClass.contains(Reg) || - llvm::X86::GR32RegClass.contains(Reg) || - llvm::X86::GR64RegClass.contains(Reg)) - return {loadImmediate(Reg, Value)}; - ConstantInliner CI(Value); - if (llvm::X86::VR64RegClass.contains(Reg)) - return CI.Add(loadToReg(Reg, llvm::X86::MMX_MOVQ64rm)).finalize(); - llvm_unreachable("Not yet implemented"); + if (Reg == llvm::X86::EFLAGS) + return CI.popFlagAndFinalize(); + return {}; // Not yet implemented. } std::unique_ptr @@ -321,31 +336,6 @@ bool matchesArch(llvm::Triple::ArchType Arch) const override { return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86; } - -private: - // setRegToConstant() specialized for a vector register of size - // `RegSizeBytes`. `RMOpcode` is the opcode used to do a memory -> vector - // register load. - static std::vector - setVectorRegToConstant(const unsigned Reg, const unsigned RegSizeBytes, - const unsigned RMOpcode) { - // There is no instruction to directly set XMM, go through memory. - // Since vector values can be interpreted as integers of various sizes (8 - // to 64 bits) as well as floats and double, so we chose an immediate - // value that has set bits for all byte values and is a normal float/ - // double. 0x40404040 is ~32.5 when interpreted as a double and ~3.0f when - // interpreted as a float. - constexpr const uint32_t kImmValue = 0x40404040u; - std::vector Result; - Result.push_back(allocateStackSpace(RegSizeBytes)); - constexpr const unsigned kMov32NumBytes = 4; - for (unsigned Disp = 0; Disp < RegSizeBytes; Disp += kMov32NumBytes) { - Result.push_back(fillStackSpace(llvm::X86::MOV32mi, Disp, kImmValue)); - } - Result.push_back(loadToReg(Reg, RMOpcode)); - Result.push_back(releaseStackSpace(RegSizeBytes)); - return Result; - } }; } // namespace Index: llvm/trunk/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp =================================================================== --- llvm/trunk/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp +++ llvm/trunk/unittests/tools/llvm-exegesis/AArch64/TargetTest.cpp @@ -15,11 +15,16 @@ namespace { +using llvm::APInt; +using llvm::MCInst; using testing::Gt; +using testing::IsEmpty; +using testing::Not; using testing::NotNull; -using testing::SizeIs; -constexpr const char kTriple[] = "aarch64-unknown-linux"; +static const char kTriple[] = "aarch64-unknown-linux"; +static const char kGenericCpu[] = "generic"; +static const char kNoFeatures[] = ""; class AArch64TargetTest : public ::testing::Test { protected: @@ -29,7 +34,10 @@ std::string error; Target_ = llvm::TargetRegistry::lookupTarget(kTriple, error); EXPECT_THAT(Target_, NotNull()); + STI_.reset( + Target_->createMCSubtargetInfo(kTriple, kGenericCpu, kNoFeatures)); } + static void SetUpTestCase() { LLVMInitializeAArch64TargetInfo(); LLVMInitializeAArch64Target(); @@ -37,9 +45,20 @@ InitializeAArch64ExegesisTarget(); } + std::vector setRegTo(unsigned Reg, const APInt &Value) { + return ExegesisTarget_->setRegTo(*STI_, Reg, Value); + } + const llvm::Target *Target_; const ExegesisTarget *const ExegesisTarget_; + std::unique_ptr STI_; }; +TEST_F(AArch64TargetTest, SetRegToConstant) { + // The AArch64 target currently doesn't know how to set register values. + const auto Insts = setRegTo(llvm::AArch64::X0, llvm::APInt()); + EXPECT_THAT(Insts, Not(IsEmpty())); +} + } // namespace } // namespace exegesis Index: llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp =================================================================== --- llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp +++ llvm/trunk/unittests/tools/llvm-exegesis/ARM/AssemblerTest.cpp @@ -30,12 +30,11 @@ }; TEST_F(ARMMachineFunctionGeneratorTest, DISABLED_JitFunction) { - Check(ExegesisTarget::getDefault(), {}, llvm::MCInst(), 0x1e, 0xff, 0x2f, - 0xe1); + Check({}, llvm::MCInst(), 0x1e, 0xff, 0x2f, 0xe1); } TEST_F(ARMMachineFunctionGeneratorTest, DISABLED_JitFunctionADDrr) { - Check(ExegesisTarget::getDefault(), {llvm::ARM::R0}, + Check({{llvm::ARM::R0, llvm::APInt()}}, MCInstBuilder(llvm::ARM::ADDrr) .addReg(llvm::ARM::R0) .addReg(llvm::ARM::R0) Index: llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h =================================================================== --- llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h +++ llvm/trunk/unittests/tools/llvm-exegesis/Common/AssemblerUtils.h @@ -32,7 +32,9 @@ const std::string &CpuName) : TT(TT), CpuName(CpuName), CanExecute(llvm::Triple(TT).getArch() == - llvm::Triple(llvm::sys::getProcessTriple()).getArch()) { + llvm::Triple(llvm::sys::getProcessTriple()).getArch()), + ET(ExegesisTarget::lookup(llvm::Triple(TT))) { + assert(ET); if (!CanExecute) { llvm::outs() << "Skipping execution, host:" << llvm::sys::getProcessTriple() << ", target:" << TT @@ -41,12 +43,12 @@ } template - inline void Check(const ExegesisTarget &ET, - llvm::ArrayRef RegsToDef, llvm::MCInst MCInst, - Bs... Bytes) { + inline void Check(llvm::ArrayRef RegisterInitialValues, + llvm::MCInst MCInst, Bs... Bytes) { ExecutableFunction Function = - (MCInst.getOpcode() == 0) ? assembleToFunction(ET, RegsToDef, {}) - : assembleToFunction(ET, RegsToDef, {MCInst}); + (MCInst.getOpcode() == 0) + ? assembleToFunction(RegisterInitialValues, {}) + : assembleToFunction(RegisterInitialValues, {MCInst}); ASSERT_THAT(Function.getFunctionBytes().str(), testing::ElementsAre(Bytes...)); if (CanExecute) { @@ -70,14 +72,12 @@ } ExecutableFunction - assembleToFunction(const ExegesisTarget &ET, - llvm::ArrayRef RegsToDef, + assembleToFunction(llvm::ArrayRef RegisterInitialValues, llvm::ArrayRef Instructions) { llvm::SmallString<256> Buffer; llvm::raw_svector_ostream AsmStream(Buffer); - assembleToStream(ET, createTargetMachine(), /*LiveIns=*/{}, - RegsToDef, Instructions, - AsmStream); + assembleToStream(*ET, createTargetMachine(), /*LiveIns=*/{}, + RegisterInitialValues, Instructions, AsmStream); return ExecutableFunction(createTargetMachine(), getObjectFromBuffer(AsmStream.str())); } @@ -85,6 +85,7 @@ const std::string TT; const std::string CpuName; const bool CanExecute; + const ExegesisTarget *const ET; }; } // namespace exegesis Index: llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp =================================================================== --- llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp +++ llvm/trunk/unittests/tools/llvm-exegesis/X86/AssemblerTest.cpp @@ -39,19 +39,12 @@ }; TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunction) { - Check(ExegesisTarget::getDefault(), {}, llvm::MCInst(), 0xc3); -} - -TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr_Default) { - Check(ExegesisTarget::getDefault(), {EAX}, - MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX), 0x31, 0xc0, - 0xc3); + Check({}, llvm::MCInst(), 0xc3); } TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionXOR32rr_X86) { - const auto *ET = ExegesisTarget::lookup(llvm::Triple("x86_64-unknown-linux")); - ASSERT_NE(ET, nullptr); - Check(*ET, {EAX}, MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX), + Check({{EAX, llvm::APInt(32, 1)}}, + MCInstBuilder(XOR32rr).addReg(EAX).addReg(EAX).addReg(EAX), // mov eax, 1 0xb8, 0x01, 0x00, 0x00, 0x00, // xor eax, eax @@ -59,15 +52,13 @@ } TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV64ri) { - Check(ExegesisTarget::getDefault(), {}, - MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42), 0x48, 0xc7, 0xc0, 0x2a, - 0x00, 0x00, 0x00, 0xc3); + Check({}, MCInstBuilder(MOV64ri32).addReg(RAX).addImm(42), 0x48, 0xc7, 0xc0, + 0x2a, 0x00, 0x00, 0x00, 0xc3); } TEST_F(X86MachineFunctionGeneratorTest, DISABLED_JitFunctionMOV32ri) { - Check(ExegesisTarget::getDefault(), {}, - MCInstBuilder(MOV32ri).addReg(EAX).addImm(42), 0xb8, 0x2a, 0x00, 0x00, - 0x00, 0xc3); + Check({}, MCInstBuilder(MOV32ri).addReg(EAX).addImm(42), 0xb8, 0x2a, 0x00, + 0x00, 0x00, 0xc3); } } // namespace Index: llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp =================================================================== --- llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp +++ llvm/trunk/unittests/tools/llvm-exegesis/X86/SnippetGeneratorTest.cpp @@ -261,7 +261,13 @@ using FakeSnippetGeneratorTest = SnippetGeneratorTest; -TEST_F(FakeSnippetGeneratorTest, ComputeRegsToDefAdd16ri) { +testing::Matcher IsRegisterValue(unsigned Reg, + llvm::APInt Value) { + return testing::AllOf(testing::Field(&RegisterValue::Register, Reg), + testing::Field(&RegisterValue::Value, Value)); +} + +TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd16ri) { // ADD16ri: // explicit def 0 : reg RegClass=GR16 // explicit use 1 : reg RegClass=GR16 | TIED_TO:0 @@ -272,11 +278,11 @@ llvm::MCOperand::createReg(llvm::X86::AX); std::vector Snippet; Snippet.push_back(std::move(IB)); - const auto RegsToDef = Generator.computeRegsToDef(Snippet); - EXPECT_THAT(RegsToDef, UnorderedElementsAre(llvm::X86::AX)); + const auto RIV = Generator.computeRegisterInitialValues(Snippet); + EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(llvm::X86::AX, llvm::APInt()))); } -TEST_F(FakeSnippetGeneratorTest, ComputeRegsToDefAdd64rr) { +TEST_F(FakeSnippetGeneratorTest, ComputeRegisterInitialValuesAdd64rr) { // ADD64rr: // mov64ri rax, 42 // add64rr rax, rax, rbx @@ -298,8 +304,8 @@ Snippet.push_back(std::move(Add)); } - const auto RegsToDef = Generator.computeRegsToDef(Snippet); - EXPECT_THAT(RegsToDef, UnorderedElementsAre(llvm::X86::RBX)); + const auto RIV = Generator.computeRegisterInitialValues(Snippet); + EXPECT_THAT(RIV, ElementsAre(IsRegisterValue(llvm::X86::RBX, llvm::APInt()))); } } // namespace Index: llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp =================================================================== --- llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp +++ llvm/trunk/unittests/tools/llvm-exegesis/X86/TargetTest.cpp @@ -13,7 +13,7 @@ namespace llvm { -bool operator==(const llvm::MCOperand &a, const llvm::MCOperand &b) { +bool operator==(const MCOperand &a, const MCOperand &b) { if (a.isImm() && b.isImm()) return a.getImm() == b.getImm(); if (a.isReg() && b.isReg()) @@ -21,7 +21,7 @@ return false; } -bool operator==(const llvm::MCInst &a, const llvm::MCInst &b) { +bool operator==(const MCInst &a, const MCInst &b) { if (a.getOpcode() != b.getOpcode()) return false; if (a.getNumOperands() != b.getNumOperands()) @@ -41,17 +41,71 @@ namespace { +using testing::AllOf; using testing::ElementsAre; +using testing::ElementsAreArray; +using testing::Eq; using testing::Gt; +using testing::Matcher; using testing::NotNull; +using testing::Property; using testing::SizeIs; using llvm::APInt; using llvm::MCInst; using llvm::MCInstBuilder; +using llvm::MCOperand; -constexpr const char kTriple[] = "x86_64-unknown-linux"; +Matcher IsImm(int64_t Value) { + return AllOf(Property(&MCOperand::isImm, Eq(true)), + Property(&MCOperand::getImm, Eq(Value))); +} + +Matcher IsReg(unsigned Reg) { + return AllOf(Property(&MCOperand::isReg, Eq(true)), + Property(&MCOperand::getReg, Eq(Reg))); +} + +Matcher OpcodeIs(unsigned Opcode) { + return Property(&MCInst::getOpcode, Eq(Opcode)); +} + +Matcher IsMovImmediate(unsigned Opcode, int64_t Reg, int64_t Value) { + return AllOf(OpcodeIs(Opcode), ElementsAre(IsReg(Reg), IsImm(Value))); +} + +Matcher IsMovValueToStack(unsigned Opcode, int64_t Value, + size_t Offset) { + return AllOf(OpcodeIs(Opcode), + ElementsAre(IsReg(llvm::X86::RSP), IsImm(1), IsReg(0), + IsImm(Offset), IsReg(0), IsImm(Value))); +} + +Matcher IsMovValueFromStack(unsigned Opcode, unsigned Reg) { + return AllOf(OpcodeIs(Opcode), + ElementsAre(IsReg(Reg), IsReg(llvm::X86::RSP), IsImm(1), + IsReg(0), IsImm(0), IsReg(0))); +} + +Matcher IsStackAllocate(unsigned Size) { + return AllOf( + OpcodeIs(llvm::X86::SUB64ri8), + ElementsAre(IsReg(llvm::X86::RSP), IsReg(llvm::X86::RSP), IsImm(Size))); +} + +Matcher IsStackDeallocate(unsigned Size) { + return AllOf( + OpcodeIs(llvm::X86::ADD64ri8), + ElementsAre(IsReg(llvm::X86::RSP), IsReg(llvm::X86::RSP), IsImm(Size))); +} +static const char kTriple[] = "x86_64-unknown-linux"; +static const char kFeaturesEmpty[] = ""; +static const char kFeaturesAvx[] = "+avx"; +static const char kFeaturesAvx512VL[] = "+avx512vl"; +static const char kCpuCore2[] = "core2"; + +template class X86TargetTest : public ::testing::Test { protected: X86TargetTest() @@ -60,7 +114,9 @@ std::string error; Target_ = llvm::TargetRegistry::lookupTarget(kTriple, error); EXPECT_THAT(Target_, NotNull()); + STI_.reset(Target_->createMCSubtargetInfo(kTriple, kCpuCore2, Features)); } + static void SetUpTestCase() { LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); @@ -68,173 +124,208 @@ InitializeX86ExegesisTarget(); } + std::vector setRegTo(unsigned Reg, const APInt &Value) { + return ExegesisTarget_->setRegTo(*STI_, Reg, Value); + } + const llvm::Target *Target_; const ExegesisTarget *const ExegesisTarget_; + std::unique_ptr STI_; }; -TEST_F(X86TargetTest, SetRegToConstantGPR) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::EAX); - EXPECT_THAT(Insts, SizeIs(1)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::MOV32ri); - EXPECT_EQ(Insts[0].getOperand(0).getReg(), llvm::X86::EAX); -} - -TEST_F(X86TargetTest, SetRegToConstantXMM_SSE2) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::XMM1); - EXPECT_THAT(Insts, SizeIs(7U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[5].getOpcode(), llvm::X86::MOVDQUrm); - EXPECT_EQ(Insts[6].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetRegToConstantXMM_AVX) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "+avx")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::XMM1); - EXPECT_THAT(Insts, SizeIs(7U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[5].getOpcode(), llvm::X86::VMOVDQUrm); - EXPECT_EQ(Insts[6].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetRegToConstantXMM_AVX512) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "+avx512vl")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::XMM1); - EXPECT_THAT(Insts, SizeIs(7U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[5].getOpcode(), llvm::X86::VMOVDQU32Z128rm); - EXPECT_EQ(Insts[6].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetRegToConstantMMX) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::MM1); - EXPECT_THAT(Insts, SizeIs(5U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MMX_MOVQ64rm); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetRegToConstantYMM_AVX) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "+avx")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::YMM1); - EXPECT_THAT(Insts, SizeIs(11U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[5].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[6].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[7].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[8].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[9].getOpcode(), llvm::X86::VMOVDQUYrm); - EXPECT_EQ(Insts[10].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetRegToConstantYMM_AVX512) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "+avx512vl")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::YMM1); - EXPECT_THAT(Insts, SizeIs(11U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[5].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[6].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[7].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[8].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[9].getOpcode(), llvm::X86::VMOVDQU32Z256rm); - EXPECT_EQ(Insts[10].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetRegToConstantZMM_AVX512) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "+avx512vl")); - const auto Insts = ExegesisTarget_->setRegToConstant(*STI, llvm::X86::ZMM1); - EXPECT_THAT(Insts, SizeIs(19U)); - EXPECT_EQ(Insts[0].getOpcode(), llvm::X86::SUB64ri8); - EXPECT_EQ(Insts[1].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[2].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[3].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[4].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[5].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[6].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[7].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[8].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[9].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[10].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[11].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[12].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[13].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[14].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[15].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[16].getOpcode(), llvm::X86::MOV32mi); - EXPECT_EQ(Insts[17].getOpcode(), llvm::X86::VMOVDQU32Zrm); - EXPECT_EQ(Insts[18].getOpcode(), llvm::X86::ADD64ri8); -} - -TEST_F(X86TargetTest, SetToAPInt) { - const std::unique_ptr STI( - Target_->createMCSubtargetInfo(kTriple, "core2", "")); - // EXPECT_THAT(ExegesisTarget_->setRegTo(*STI, APInt(8, 0xFFU), - // llvm::X86::AL), - // ElementsAre((MCInst)MCInstBuilder(llvm::X86::MOV8ri) - // .addReg(llvm::X86::AL) - // .addImm(0xFFU))); - // EXPECT_THAT( - // ExegesisTarget_->setRegTo(*STI, APInt(16, 0xFFFFU), llvm::X86::BX), - // ElementsAre((MCInst)MCInstBuilder(llvm::X86::MOV16ri) - // .addReg(llvm::X86::BX) - // .addImm(0xFFFFU))); - // EXPECT_THAT( - // ExegesisTarget_->setRegTo(*STI, APInt(32, 0x7FFFFU), llvm::X86::ECX), - // ElementsAre((MCInst)MCInstBuilder(llvm::X86::MOV32ri) - // .addReg(llvm::X86::ECX) - // .addImm(0x7FFFFU))); - // EXPECT_THAT(ExegesisTarget_->setRegTo(*STI, APInt(64, - // 0x7FFFFFFFFFFFFFFFULL), - // llvm::X86::RDX), - // ElementsAre((MCInst)MCInstBuilder(llvm::X86::MOV64ri) - // .addReg(llvm::X86::RDX) - // .addImm(0x7FFFFFFFFFFFFFFFULL))); - - const std::unique_ptr MRI( - Target_->createMCRegInfo(kTriple)); - const std::unique_ptr MAI( - Target_->createMCAsmInfo(*MRI, kTriple)); - const std::unique_ptr MII(Target_->createMCInstrInfo()); - const std::unique_ptr MIP( - Target_->createMCInstPrinter(llvm::Triple(kTriple), 1, *MAI, *MII, *MRI)); - - for (const auto M : ExegesisTarget_->setRegTo( - *STI, APInt(80, "ABCD1234123456785678", 16), llvm::X86::MM0)) { - MIP->printInst(&M, llvm::errs(), "", *STI); - llvm::errs() << "\n"; - } +using Core2TargetTest = X86TargetTest; +using Core2AvxTargetTest = X86TargetTest; +using Core2Avx512TargetTest = X86TargetTest; + +TEST_F(Core2TargetTest, SetFlags) { + const unsigned Reg = llvm::X86::EFLAGS; + EXPECT_THAT( + setRegTo(Reg, APInt(64, 0x1111222233334444ULL)), + ElementsAre(IsStackAllocate(8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), + OpcodeIs(llvm::X86::POPF64))); +} + +TEST_F(Core2TargetTest, SetRegToGR8Value) { + const uint8_t Value = 0xFFU; + const unsigned Reg = llvm::X86::AL; + EXPECT_THAT(setRegTo(Reg, APInt(8, Value)), + ElementsAre(IsMovImmediate(llvm::X86::MOV8ri, Reg, Value))); +} + +TEST_F(Core2TargetTest, SetRegToGR16Value) { + const uint16_t Value = 0xFFFFU; + const unsigned Reg = llvm::X86::BX; + EXPECT_THAT(setRegTo(Reg, APInt(16, Value)), + ElementsAre(IsMovImmediate(llvm::X86::MOV16ri, Reg, Value))); +} + +TEST_F(Core2TargetTest, SetRegToGR32Value) { + const uint32_t Value = 0x7FFFFU; + const unsigned Reg = llvm::X86::ECX; + EXPECT_THAT(setRegTo(Reg, APInt(32, Value)), + ElementsAre(IsMovImmediate(llvm::X86::MOV32ri, Reg, Value))); +} + +TEST_F(Core2TargetTest, SetRegToGR64Value) { + const uint64_t Value = 0x7FFFFFFFFFFFFFFFULL; + const unsigned Reg = llvm::X86::RDX; + EXPECT_THAT(setRegTo(Reg, APInt(64, Value)), + ElementsAre(IsMovImmediate(llvm::X86::MOV64ri, Reg, Value))); +} + +TEST_F(Core2TargetTest, SetRegToVR64Value) { + EXPECT_THAT( + setRegTo(llvm::X86::MM0, APInt(64, 0x1111222233334444ULL)), + ElementsAre(IsStackAllocate(8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), + IsMovValueFromStack(llvm::X86::MMX_MOVQ64rm, llvm::X86::MM0), + IsStackDeallocate(8))); +} + +TEST_F(Core2TargetTest, SetRegToVR128Value_Use_MOVDQUrm) { + EXPECT_THAT( + setRegTo(llvm::X86::XMM0, + APInt(128, "11112222333344445555666677778888", 16)), + ElementsAre(IsStackAllocate(16), + IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), + IsMovValueFromStack(llvm::X86::MOVDQUrm, llvm::X86::XMM0), + IsStackDeallocate(16))); +} + +TEST_F(Core2AvxTargetTest, SetRegToVR128Value_Use_VMOVDQUrm) { + EXPECT_THAT( + setRegTo(llvm::X86::XMM0, + APInt(128, "11112222333344445555666677778888", 16)), + ElementsAre(IsStackAllocate(16), + IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), + IsMovValueFromStack(llvm::X86::VMOVDQUrm, llvm::X86::XMM0), + IsStackDeallocate(16))); +} + +TEST_F(Core2Avx512TargetTest, SetRegToVR128Value_Use_VMOVDQU32Z128rm) { + EXPECT_THAT( + setRegTo(llvm::X86::XMM0, + APInt(128, "11112222333344445555666677778888", 16)), + ElementsAre( + IsStackAllocate(16), + IsMovValueToStack(llvm::X86::MOV32mi, 0x77778888UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x55556666UL, 4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 12), + IsMovValueFromStack(llvm::X86::VMOVDQU32Z128rm, llvm::X86::XMM0), + IsStackDeallocate(16))); +} + +TEST_F(Core2AvxTargetTest, SetRegToVR256Value_Use_VMOVDQUYrm) { + const char ValueStr[] = + "1111111122222222333333334444444455555555666666667777777788888888"; + EXPECT_THAT(setRegTo(llvm::X86::YMM0, APInt(256, ValueStr, 16)), + ElementsAreArray( + {IsStackAllocate(32), + IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 12), + IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 16), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 20), + IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 24), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 28), + IsMovValueFromStack(llvm::X86::VMOVDQUYrm, llvm::X86::YMM0), + IsStackDeallocate(32)})); +} + +TEST_F(Core2Avx512TargetTest, SetRegToVR256Value_Use_VMOVDQU32Z256rm) { + const char ValueStr[] = + "1111111122222222333333334444444455555555666666667777777788888888"; + EXPECT_THAT( + setRegTo(llvm::X86::YMM0, APInt(256, ValueStr, 16)), + ElementsAreArray( + {IsStackAllocate(32), + IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 12), + IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 16), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 20), + IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 24), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 28), + IsMovValueFromStack(llvm::X86::VMOVDQU32Z256rm, llvm::X86::YMM0), + IsStackDeallocate(32)})); +} + +TEST_F(Core2Avx512TargetTest, SetRegToVR512Value) { + const char ValueStr[] = + "1111111122222222333333334444444455555555666666667777777788888888" + "99999999AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFF00000000"; + EXPECT_THAT( + setRegTo(llvm::X86::ZMM0, APInt(512, ValueStr, 16)), + ElementsAreArray( + {IsStackAllocate(64), + IsMovValueToStack(llvm::X86::MOV32mi, 0x00000000UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0xFFFFFFFFUL, 4), + IsMovValueToStack(llvm::X86::MOV32mi, 0xEEEEEEEEUL, 8), + IsMovValueToStack(llvm::X86::MOV32mi, 0xDDDDDDDDUL, 12), + IsMovValueToStack(llvm::X86::MOV32mi, 0xCCCCCCCCUL, 16), + IsMovValueToStack(llvm::X86::MOV32mi, 0xBBBBBBBBUL, 20), + IsMovValueToStack(llvm::X86::MOV32mi, 0xAAAAAAAAUL, 24), + IsMovValueToStack(llvm::X86::MOV32mi, 0x99999999UL, 28), + IsMovValueToStack(llvm::X86::MOV32mi, 0x88888888UL, 32), + IsMovValueToStack(llvm::X86::MOV32mi, 0x77777777UL, 36), + IsMovValueToStack(llvm::X86::MOV32mi, 0x66666666UL, 40), + IsMovValueToStack(llvm::X86::MOV32mi, 0x55555555UL, 44), + IsMovValueToStack(llvm::X86::MOV32mi, 0x44444444UL, 48), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33333333UL, 52), + IsMovValueToStack(llvm::X86::MOV32mi, 0x22222222UL, 56), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11111111UL, 60), + IsMovValueFromStack(llvm::X86::VMOVDQU32Zrm, llvm::X86::ZMM0), + IsStackDeallocate(64)})); +} + +TEST_F(Core2TargetTest, SetRegToST0_32Bits) { + EXPECT_THAT( + setRegTo(llvm::X86::ST0, APInt(32, 0x11112222ULL)), + ElementsAre(IsStackAllocate(4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), + OpcodeIs(llvm::X86::LD_F32m), IsStackDeallocate(4))); +} + +TEST_F(Core2TargetTest, SetRegToST1_32Bits) { + const MCInst CopySt0ToSt1 = + llvm::MCInstBuilder(llvm::X86::ST_Frr).addReg(llvm::X86::ST1); + EXPECT_THAT( + setRegTo(llvm::X86::ST1, APInt(32, 0x11112222ULL)), + ElementsAre(IsStackAllocate(4), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 0), + OpcodeIs(llvm::X86::LD_F32m), CopySt0ToSt1, + IsStackDeallocate(4))); +} + +TEST_F(Core2TargetTest, SetRegToST0_64Bits) { + EXPECT_THAT( + setRegTo(llvm::X86::ST0, APInt(64, 0x1111222233334444ULL)), + ElementsAre(IsStackAllocate(8), + IsMovValueToStack(llvm::X86::MOV32mi, 0x33334444UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x11112222UL, 4), + OpcodeIs(llvm::X86::LD_F64m), IsStackDeallocate(8))); +} + +TEST_F(Core2TargetTest, SetRegToST0_80Bits) { + EXPECT_THAT( + setRegTo(llvm::X86::ST0, APInt(80, "11112222333344445555", 16)), + ElementsAre(IsStackAllocate(10), + IsMovValueToStack(llvm::X86::MOV32mi, 0x44445555UL, 0), + IsMovValueToStack(llvm::X86::MOV32mi, 0x22223333UL, 4), + IsMovValueToStack(llvm::X86::MOV16mi, 0x1111UL, 8), + OpcodeIs(llvm::X86::LD_F80m), IsStackDeallocate(10))); } } // namespace