diff options
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib')
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp | 50 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/Assembler.cpp | 35 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/Assembler.h | 8 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/BenchmarkCode.h | 2 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 2 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp | 10 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/SnippetGenerator.h | 4 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/Target.cpp | 22 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/Target.h | 21 | ||||
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/X86/Target.cpp | 154 |
10 files changed, 151 insertions, 157 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp b/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp index a65713b9f42..90c5927ad29 100644 --- a/llvm/tools/llvm-exegesis/lib/AArch64/Target.cpp +++ b/llvm/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 @@ private: } }; -class ExegesisAArch64Target : public ExegesisTarget { - std::vector<llvm::MCInst> setRegToConstant(const llvm::MCSubtargetInfo &STI, - unsigned Reg) const override { - llvm_unreachable("Not yet implemented"); - } +namespace { - std::vector<llvm::MCInst> 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<llvm::MCInst> 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<BenchmarkRunner> createLatencyBenchmarkRunner(const LLVMState &State) const override { return llvm::make_unique<AArch64LatencyBenchmarkRunner>(State); diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.cpp b/llvm/tools/llvm-exegesis/lib/Assembler.cpp index 3b8b1d6bf38..cb6e9e13e65 100644 --- a/llvm/tools/llvm-exegesis/lib/Assembler.cpp +++ b/llvm/tools/llvm-exegesis/lib/Assembler.cpp @@ -29,17 +29,17 @@ static constexpr const char ModuleID[] = "ExegesisInfoTest"; static constexpr const char FunctionID[] = "foo"; static std::vector<llvm::MCInst> -generateSnippetSetupCode(const llvm::ArrayRef<unsigned> RegsToDef, - const ExegesisTarget &ET, - const llvm::LLVMTargetMachine &TM, bool &IsComplete) { - IsComplete = true; +generateSnippetSetupCode(const ExegesisTarget &ET, + const llvm::MCSubtargetInfo *const MSI, + llvm::ArrayRef<RegisterValue> RegisterInitialValues, + bool &IsSnippetSetupComplete) { std::vector<llvm::MCInst> 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 @@ llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM) { void assembleToStream(const ExegesisTarget &ET, std::unique_ptr<llvm::LLVMTargetMachine> TM, llvm::ArrayRef<unsigned> LiveIns, - llvm::ArrayRef<unsigned> RegsToDef, + llvm::ArrayRef<RegisterValue> RegisterInitialValues, llvm::ArrayRef<llvm::MCInst> Instructions, llvm::raw_pwrite_stream &AsmStream) { std::unique_ptr<llvm::LLVMContext> Context = @@ -171,13 +171,12 @@ void assembleToStream(const ExegesisTarget &ET, MF.getRegInfo().addLiveIn(Reg); bool IsSnippetSetupComplete = false; - std::vector<llvm::MCInst> SnippetWithSetup = - generateSnippetSetupCode(RegsToDef, ET, *TM, IsSnippetSetupComplete); - if (!SnippetWithSetup.empty()) { - SnippetWithSetup.insert(SnippetWithSetup.end(), Instructions.begin(), - Instructions.end()); - Instructions = SnippetWithSetup; - } + std::vector<llvm::MCInst> 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 @@ void assembleToStream(const ExegesisTarget &ET, 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(); diff --git a/llvm/tools/llvm-exegesis/lib/Assembler.h b/llvm/tools/llvm-exegesis/lib/Assembler.h index d5b542bc1bb..76030ae8f00 100644 --- a/llvm/tools/llvm-exegesis/lib/Assembler.h +++ b/llvm/tools/llvm-exegesis/lib/Assembler.h @@ -39,6 +39,12 @@ class ExegesisTarget; // 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 @@ llvm::BitVector getFunctionReservedRegs(const llvm::TargetMachine &TM); void assembleToStream(const ExegesisTarget &ET, std::unique_ptr<llvm::LLVMTargetMachine> TM, llvm::ArrayRef<unsigned> LiveIns, - llvm::ArrayRef<unsigned> RegsToDef, + llvm::ArrayRef<RegisterValue> RegisterInitialValues, llvm::ArrayRef<llvm::MCInst> Instructions, llvm::raw_pwrite_stream &AsmStream); diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h b/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h index 1195adf45f3..03708683106 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkCode.h @@ -23,7 +23,7 @@ struct BenchmarkCode { // Before the code is executed some instructions are added to setup the // registers initial values. - std::vector<unsigned> RegsToDef; + std::vector<RegisterValue> RegisterInitialValues; // We also need to provide the registers that are live on entry for the // assembler to generate proper prologue/epilogue. diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp index 2d82f594553..6c22d1c0cec 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -104,7 +104,7 @@ BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC, 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(); } diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp index 5b51a09923a..cb58b2dfc4b 100644 --- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp +++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.cpp @@ -49,7 +49,7 @@ SnippetGenerator::generateConfigurations(unsigned Opcode) const { } 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 @@ SnippetGenerator::generateConfigurations(unsigned Opcode) const { return E.takeError(); } -std::vector<unsigned> SnippetGenerator::computeRegsToDef( +std::vector<RegisterValue> SnippetGenerator::computeRegisterInitialValues( const std::vector<InstructionBuilder> &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<unsigned> RegsToDef; + std::vector<RegisterValue> 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 @@ std::vector<unsigned> SnippetGenerator::computeRegsToDef( 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 @@ std::vector<unsigned> SnippetGenerator::computeRegsToDef( } } } - return RegsToDef; + return RIV; } llvm::Expected<CodeTemplate> SnippetGenerator::generateSelfAliasingCodeTemplate( diff --git a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h index ced8ebc5a28..2a412ba95e6 100644 --- a/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h +++ b/llvm/tools/llvm-exegesis/lib/SnippetGenerator.h @@ -48,8 +48,8 @@ public: generateConfigurations(unsigned Opcode) const; // Given a snippet, computes which registers the setup code needs to define. - std::vector<unsigned> - computeRegsToDef(const std::vector<InstructionBuilder> &Snippet) const; + std::vector<RegisterValue> computeRegisterInitialValues( + const std::vector<InstructionBuilder> &Snippet) const; protected: const LLVMState &State; diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp index b45c821823f..8baa8499c92 100644 --- a/llvm/tools/llvm-exegesis/lib/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Target.cpp @@ -89,27 +89,9 @@ namespace { // Default implementation. class ExegesisDefaultTarget : public ExegesisTarget { private: - std::vector<llvm::MCInst> setRegToConstant(const llvm::MCSubtargetInfo &STI, - unsigned Reg) const override { - llvm_unreachable("Not yet implemented"); - } - std::vector<llvm::MCInst> 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"); } diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h index 85147937966..5deb4c56aea 100644 --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -36,29 +36,32 @@ public: 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<llvm::MCInst> - setRegToConstant(const llvm::MCSubtargetInfo &STI, unsigned Reg) const = 0; - - // Generates code to move a constant into a the given register. - virtual std::vector<llvm::MCInst> 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<SnippetGenerator> diff --git a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp index e55e77d876c..2d8f9582d43 100644 --- a/llvm/tools/llvm-exegesis/lib/X86/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/X86/Target.cpp @@ -101,8 +101,8 @@ protected: } }; -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 @@ static unsigned GetLoadImmediateOpcode(const llvm::APInt &Value) { 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 @@ static llvm::MCInst releaseStackSpace(unsigned Bytes) { .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<llvm::MCInst> 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<llvm::MCInst> + 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<llvm::MCInst> finalize() { - Add(releaseStackSpace(StackSize)); + std::vector<llvm::MCInst> 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<llvm::MCInst> Instructions; }; @@ -248,64 +280,47 @@ class ExegesisX86Target : public ExegesisTarget { } } - std::vector<llvm::MCInst> setRegToConstant(const llvm::MCSubtargetInfo &STI, - unsigned Reg) const override { - // GPR. + std::vector<llvm::MCInst> 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<llvm::MCInst> 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<llvm::MCInst> 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<SnippetGenerator> @@ -321,31 +336,6 @@ class ExegesisX86Target : public ExegesisTarget { 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<llvm::MCInst> - 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<llvm::MCInst> 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 |

