blob: 5951752e1d79a73b16710507ffb41826d89bdb05 [file] [log] [blame]
Clement Courbet44b4c542018-06-19 11:28:59 +00001//===-- Target.cpp ----------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "../Target.h"
10
Clement Courbet4860b982018-06-26 08:49:30 +000011#include "../Latency.h"
12#include "../Uops.h"
Clement Courbeta51efc22018-06-25 13:12:02 +000013#include "MCTargetDesc/X86MCTargetDesc.h"
Clement Courbet6fd00e32018-06-20 11:54:35 +000014#include "X86.h"
Clement Courbeta51efc22018-06-25 13:12:02 +000015#include "X86RegisterInfo.h"
16#include "llvm/MC/MCInstBuilder.h"
Clement Courbet6fd00e32018-06-20 11:54:35 +000017
Clement Courbet44b4c542018-06-19 11:28:59 +000018namespace exegesis {
19
Clement Courbet4860b982018-06-26 08:49:30 +000020// Test whether we can generate a snippet for this instruction.
21static llvm::Error shouldRun(const LLVMState &State, const unsigned Opcode) {
22 const auto &InstrInfo = State.getInstrInfo();
23 const auto OpcodeName = InstrInfo.getName(Opcode);
24 if (OpcodeName.startswith("POPF") || OpcodeName.startswith("PUSHF") ||
25 OpcodeName.startswith("ADJCALLSTACK")) {
26 return llvm::make_error<BenchmarkFailure>(
27 "Unsupported opcode: Push/Pop/AdjCallStack");
28 }
29 return llvm::ErrorSuccess();
30}
31
Clement Courbet44b4c542018-06-19 11:28:59 +000032namespace {
33
Clement Courbet4860b982018-06-26 08:49:30 +000034class X86LatencyBenchmarkRunner : public LatencyBenchmarkRunner {
35private:
36 using LatencyBenchmarkRunner::LatencyBenchmarkRunner;
37
38 llvm::Expected<SnippetPrototype>
39 generatePrototype(unsigned Opcode) const override {
40 if (llvm::Error E = shouldRun(State, Opcode)) {
41 return std::move(E);
42 }
43 return LatencyBenchmarkRunner::generatePrototype(Opcode);
44 }
45};
46
47class X86UopsBenchmarkRunner : public UopsBenchmarkRunner {
48private:
49 using UopsBenchmarkRunner::UopsBenchmarkRunner;
50
51 llvm::Expected<SnippetPrototype>
52 generatePrototype(unsigned Opcode) const override {
53 if (llvm::Error E = shouldRun(State, Opcode)) {
54 return std::move(E);
55 }
56 return UopsBenchmarkRunner::generatePrototype(Opcode);
57 }
58};
59
Clement Courbet44b4c542018-06-19 11:28:59 +000060class ExegesisX86Target : public ExegesisTarget {
Clement Courbet6fd00e32018-06-20 11:54:35 +000061 void addTargetSpecificPasses(llvm::PassManagerBase &PM) const override {
62 // Lowers FP pseudo-instructions, e.g. ABS_Fp32 -> ABS_F.
63 // FIXME: Enable when the exegesis assembler no longer does
64 // Properties.reset(TracksLiveness);
65 // PM.add(llvm::createX86FloatingPointStackifierPass());
66 }
67
Clement Courbeta51efc22018-06-25 13:12:02 +000068 std::vector<llvm::MCInst>
69 setRegToConstant(const unsigned Reg) const override {
70 // FIXME: Handle FP stack:
71 // llvm::X86::RFP32RegClass
72 // llvm::X86::RFP64RegClass
73 // llvm::X86::RFP80RegClass
74 if (llvm::X86::GR8RegClass.contains(Reg)) {
75 return {llvm::MCInstBuilder(llvm::X86::MOV8ri).addReg(Reg).addImm(1)};
76 }
77 if (llvm::X86::GR16RegClass.contains(Reg)) {
78 return {llvm::MCInstBuilder(llvm::X86::MOV16ri).addReg(Reg).addImm(1)};
79 }
80 if (llvm::X86::GR32RegClass.contains(Reg)) {
81 return {llvm::MCInstBuilder(llvm::X86::MOV32ri).addReg(Reg).addImm(1)};
82 }
83 if (llvm::X86::GR64RegClass.contains(Reg)) {
84 return {llvm::MCInstBuilder(llvm::X86::MOV64ri32).addReg(Reg).addImm(1)};
85 }
86 if (llvm::X86::VR128XRegClass.contains(Reg)) {
87 return setVectorRegToConstant(Reg, 16, llvm::X86::VMOVDQUrm);
88 }
89 if (llvm::X86::VR256XRegClass.contains(Reg)) {
90 return setVectorRegToConstant(Reg, 32, llvm::X86::VMOVDQUYrm);
91 }
92 if (llvm::X86::VR512RegClass.contains(Reg)) {
93 return setVectorRegToConstant(Reg, 64, llvm::X86::VMOVDQU64Zrm);
94 }
95 return {};
96 }
97
Clement Courbet4860b982018-06-26 08:49:30 +000098 std::unique_ptr<BenchmarkRunner>
99 createLatencyBenchmarkRunner(const LLVMState &State) const override {
100 return llvm::make_unique<X86LatencyBenchmarkRunner>(State);
101 }
102
103 std::unique_ptr<BenchmarkRunner>
104 createUopsBenchmarkRunner(const LLVMState &State) const override {
105 return llvm::make_unique<X86UopsBenchmarkRunner>(State);
106 }
107
Clement Courbet44b4c542018-06-19 11:28:59 +0000108 bool matchesArch(llvm::Triple::ArchType Arch) const override {
109 return Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86;
110 }
Clement Courbeta51efc22018-06-25 13:12:02 +0000111
112private:
113 // setRegToConstant() specialized for a vector register of size
114 // `RegSizeBytes`. `RMOpcode` is the opcode used to do a memory -> vector
115 // register load.
116 static std::vector<llvm::MCInst>
117 setVectorRegToConstant(const unsigned Reg, const unsigned RegSizeBytes,
118 const unsigned RMOpcode) {
119 // There is no instruction to directly set XMM, go through memory.
120 // Since vector values can be interpreted as integers of various sizes (8
121 // to 64 bits) as well as floats and double, so we chose an immediate
122 // value that has set bits for all byte values and is a normal float/
123 // double. 0x40404040 is ~32.5 when interpreted as a double and ~3.0f when
124 // interpreted as a float.
125 constexpr const uint64_t kImmValue = 0x40404040ull;
126 std::vector<llvm::MCInst> Result;
127 // Allocate scratch memory on the stack.
128 Result.push_back(llvm::MCInstBuilder(llvm::X86::SUB64ri8)
129 .addReg(llvm::X86::RSP)
130 .addReg(llvm::X86::RSP)
131 .addImm(RegSizeBytes));
132 // Fill scratch memory.
133 for (unsigned Disp = 0; Disp < RegSizeBytes; Disp += 4) {
134 Result.push_back(llvm::MCInstBuilder(llvm::X86::MOV32mi)
135 // Address = ESP
136 .addReg(llvm::X86::RSP) // BaseReg
137 .addImm(1) // ScaleAmt
138 .addReg(0) // IndexReg
139 .addImm(Disp) // Disp
140 .addReg(0) // Segment
141 // Immediate.
142 .addImm(kImmValue));
143 }
144 // Load Reg from scratch memory.
145 Result.push_back(llvm::MCInstBuilder(RMOpcode)
146 .addReg(Reg)
147 // Address = ESP
148 .addReg(llvm::X86::RSP) // BaseReg
149 .addImm(1) // ScaleAmt
150 .addReg(0) // IndexReg
151 .addImm(0) // Disp
152 .addReg(0)); // Segment
153 // Release scratch memory.
154 Result.push_back(llvm::MCInstBuilder(llvm::X86::ADD64ri8)
155 .addReg(llvm::X86::RSP)
156 .addReg(llvm::X86::RSP)
157 .addImm(RegSizeBytes));
158 return Result;
159 }
Clement Courbet44b4c542018-06-19 11:28:59 +0000160};
161
162} // namespace
163
Clement Courbetcff2caa2018-06-25 11:22:23 +0000164static ExegesisTarget *getTheExegesisX86Target() {
Clement Courbet44b4c542018-06-19 11:28:59 +0000165 static ExegesisX86Target Target;
166 return &Target;
167}
168
169void InitializeX86ExegesisTarget() {
170 ExegesisTarget::registerTarget(getTheExegesisX86Target());
171}
172
Clement Courbetcff2caa2018-06-25 11:22:23 +0000173} // namespace exegesis