1 | //===- R600MCCodeEmitter.cpp - Code Emitter for R600->Cayman GPU families -===// |
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 | /// \file |
10 | /// |
11 | /// The R600 code emitter produces machine code that can be executed |
12 | /// directly on the GPU device. |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #include "MCTargetDesc/R600MCTargetDesc.h" |
17 | #include "R600Defines.h" |
18 | #include "llvm/MC/MCCodeEmitter.h" |
19 | #include "llvm/MC/MCContext.h" |
20 | #include "llvm/MC/MCInst.h" |
21 | #include "llvm/MC/MCInstrInfo.h" |
22 | #include "llvm/MC/MCRegisterInfo.h" |
23 | #include "llvm/MC/MCSubtargetInfo.h" |
24 | #include "llvm/Support/EndianStream.h" |
25 | #include "llvm/TargetParser/SubtargetFeature.h" |
26 | |
27 | using namespace llvm; |
28 | |
29 | namespace { |
30 | |
31 | class R600MCCodeEmitter : public MCCodeEmitter { |
32 | const MCRegisterInfo &MRI; |
33 | const MCInstrInfo &MCII; |
34 | |
35 | public: |
36 | R600MCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri) |
37 | : MRI(mri), MCII(mcii) {} |
38 | R600MCCodeEmitter(const R600MCCodeEmitter &) = delete; |
39 | R600MCCodeEmitter &operator=(const R600MCCodeEmitter &) = delete; |
40 | |
41 | /// Encode the instruction and write it to the OS. |
42 | void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB, |
43 | SmallVectorImpl<MCFixup> &Fixups, |
44 | const MCSubtargetInfo &STI) const override; |
45 | |
46 | /// \returns the encoding for an MCOperand. |
47 | uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, |
48 | SmallVectorImpl<MCFixup> &Fixups, |
49 | const MCSubtargetInfo &STI) const; |
50 | |
51 | private: |
52 | void emit(uint32_t value, SmallVectorImpl<char> &CB) const; |
53 | void emit(uint64_t value, SmallVectorImpl<char> &CB) const; |
54 | |
55 | unsigned getHWReg(unsigned regNo) const; |
56 | |
57 | uint64_t getBinaryCodeForInstr(const MCInst &MI, |
58 | SmallVectorImpl<MCFixup> &Fixups, |
59 | const MCSubtargetInfo &STI) const; |
60 | }; |
61 | |
62 | } // end anonymous namespace |
63 | |
64 | enum RegElement { |
65 | ELEMENT_X = 0, |
66 | ELEMENT_Y, |
67 | ELEMENT_Z, |
68 | ELEMENT_W |
69 | }; |
70 | |
71 | enum FCInstr { |
72 | FC_IF_PREDICATE = 0, |
73 | FC_ELSE, |
74 | FC_ENDIF, |
75 | FC_BGNLOOP, |
76 | FC_ENDLOOP, |
77 | FC_BREAK_PREDICATE, |
78 | FC_CONTINUE |
79 | }; |
80 | |
81 | MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII, |
82 | MCContext &Ctx) { |
83 | return new R600MCCodeEmitter(MCII, *Ctx.getRegisterInfo()); |
84 | } |
85 | |
86 | void R600MCCodeEmitter::encodeInstruction(const MCInst &MI, |
87 | SmallVectorImpl<char> &CB, |
88 | SmallVectorImpl<MCFixup> &Fixups, |
89 | const MCSubtargetInfo &STI) const { |
90 | const MCInstrDesc &Desc = MCII.get(Opcode: MI.getOpcode()); |
91 | if (MI.getOpcode() == R600::RETURN || |
92 | MI.getOpcode() == R600::FETCH_CLAUSE || |
93 | MI.getOpcode() == R600::ALU_CLAUSE || |
94 | MI.getOpcode() == R600::BUNDLE || |
95 | MI.getOpcode() == R600::KILL) { |
96 | return; |
97 | } |
98 | if (IS_VTX(Desc)) { |
99 | uint64_t InstWord01 = getBinaryCodeForInstr(MI, Fixups, STI); |
100 | uint32_t InstWord2 = MI.getOperand(i: 2).getImm(); // Offset |
101 | if (!(STI.hasFeature(Feature: R600::FeatureCaymanISA))) { |
102 | InstWord2 |= 1 << 19; // Mega-Fetch bit |
103 | } |
104 | |
105 | emit(value: InstWord01, CB); |
106 | emit(value: InstWord2, CB); |
107 | emit(value: (uint32_t)0, CB); |
108 | } else if (IS_TEX(Desc)) { |
109 | int64_t Sampler = MI.getOperand(i: 14).getImm(); |
110 | |
111 | int64_t SrcSelect[4] = { |
112 | MI.getOperand(i: 2).getImm(), MI.getOperand(i: 3).getImm(), |
113 | MI.getOperand(i: 4).getImm(), MI.getOperand(i: 5).getImm()}; |
114 | int64_t Offsets[3] = {MI.getOperand(i: 6).getImm() & 0x1F, |
115 | MI.getOperand(i: 7).getImm() & 0x1F, |
116 | MI.getOperand(i: 8).getImm() & 0x1F}; |
117 | |
118 | uint64_t Word01 = getBinaryCodeForInstr(MI, Fixups, STI); |
119 | uint32_t Word2 = Sampler << 15 | SrcSelect[ELEMENT_X] << 20 | |
120 | SrcSelect[ELEMENT_Y] << 23 | SrcSelect[ELEMENT_Z] << 26 | |
121 | SrcSelect[ELEMENT_W] << 29 | Offsets[0] << 0 | |
122 | Offsets[1] << 5 | Offsets[2] << 10; |
123 | |
124 | emit(value: Word01, CB); |
125 | emit(value: Word2, CB); |
126 | emit(value: (uint32_t)0, CB); |
127 | } else { |
128 | uint64_t Inst = getBinaryCodeForInstr(MI, Fixups, STI); |
129 | if ((STI.hasFeature(Feature: R600::FeatureR600ALUInst)) && |
130 | ((Desc.TSFlags & R600_InstFlag::OP1) || |
131 | Desc.TSFlags & R600_InstFlag::OP2)) { |
132 | uint64_t ISAOpCode = Inst & (0x3FFULL << 39); |
133 | Inst &= ~(0x3FFULL << 39); |
134 | Inst |= ISAOpCode << 1; |
135 | } |
136 | emit(value: Inst, CB); |
137 | } |
138 | } |
139 | |
140 | void R600MCCodeEmitter::emit(uint32_t Value, SmallVectorImpl<char> &CB) const { |
141 | support::endian::write(Out&: CB, V: Value, E: llvm::endianness::little); |
142 | } |
143 | |
144 | void R600MCCodeEmitter::emit(uint64_t Value, SmallVectorImpl<char> &CB) const { |
145 | support::endian::write(Out&: CB, V: Value, E: llvm::endianness::little); |
146 | } |
147 | |
148 | unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo) const { |
149 | return MRI.getEncodingValue(RegNo) & HW_REG_MASK; |
150 | } |
151 | |
152 | uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI, |
153 | const MCOperand &MO, |
154 | SmallVectorImpl<MCFixup> &Fixups, |
155 | const MCSubtargetInfo &STI) const { |
156 | if (MO.isReg()) { |
157 | if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags)) |
158 | return MRI.getEncodingValue(RegNo: MO.getReg()); |
159 | return getHWReg(RegNo: MO.getReg()); |
160 | } |
161 | |
162 | if (MO.isExpr()) { |
163 | // We put rodata at the end of code section, then map the entire |
164 | // code secetion as vtx buf. Thus the section relative address is the |
165 | // correct one. |
166 | // Each R600 literal instruction has two operands |
167 | // We can't easily get the order of the current one, so compare against |
168 | // the first one and adjust offset. |
169 | const unsigned offset = (&MO == &MI.getOperand(i: 0)) ? 0 : 4; |
170 | Fixups.push_back(Elt: MCFixup::create(Offset: offset, Value: MO.getExpr(), Kind: FK_SecRel_4, Loc: MI.getLoc())); |
171 | return 0; |
172 | } |
173 | |
174 | assert(MO.isImm()); |
175 | return MO.getImm(); |
176 | } |
177 | |
178 | #include "R600GenMCCodeEmitter.inc" |
179 | |