1 //===- R600MCCodeEmitter.cpp - Code Emitter for R600->Cayman GPU families -===//
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
7 //===----------------------------------------------------------------------===//
11 /// The R600 code emitter produces machine code that can be executed
12 /// directly on the GPU device.
14 //===----------------------------------------------------------------------===//
16 #include "MCTargetDesc/AMDGPUFixupKinds.h"
17 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
18 #include "R600Defines.h"
19 #include "llvm/MC/MCCodeEmitter.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCFixup.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrDesc.h"
24 #include "llvm/MC/MCInstrInfo.h"
25 #include "llvm/MC/MCRegisterInfo.h"
26 #include "llvm/MC/MCSubtargetInfo.h"
27 #include "llvm/Support/Endian.h"
28 #include "llvm/Support/EndianStream.h"
29 #include "llvm/Support/raw_ostream.h"
37 class R600MCCodeEmitter
: public MCCodeEmitter
{
38 const MCRegisterInfo
&MRI
;
39 const MCInstrInfo
&MCII
;
42 R600MCCodeEmitter(const MCInstrInfo
&mcii
, const MCRegisterInfo
&mri
)
43 : MRI(mri
), MCII(mcii
) {}
44 R600MCCodeEmitter(const R600MCCodeEmitter
&) = delete;
45 R600MCCodeEmitter
&operator=(const R600MCCodeEmitter
&) = delete;
47 /// Encode the instruction and write it to the OS.
48 void encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
49 SmallVectorImpl
<MCFixup
> &Fixups
,
50 const MCSubtargetInfo
&STI
) const;
52 /// \returns the encoding for an MCOperand.
53 uint64_t getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
54 SmallVectorImpl
<MCFixup
> &Fixups
,
55 const MCSubtargetInfo
&STI
) const;
59 void Emit(uint32_t value
, raw_ostream
&OS
) const;
60 void Emit(uint64_t value
, raw_ostream
&OS
) const;
62 unsigned getHWReg(unsigned regNo
) const;
64 uint64_t getBinaryCodeForInstr(const MCInst
&MI
,
65 SmallVectorImpl
<MCFixup
> &Fixups
,
66 const MCSubtargetInfo
&STI
) const;
67 FeatureBitset
computeAvailableFeatures(const FeatureBitset
&FB
) const;
69 verifyInstructionPredicates(const MCInst
&MI
,
70 const FeatureBitset
&AvailableFeatures
) const;
74 } // end anonymous namespace
93 MCCodeEmitter
*llvm::createR600MCCodeEmitter(const MCInstrInfo
&MCII
,
94 const MCRegisterInfo
&MRI
,
96 return new R600MCCodeEmitter(MCII
, MRI
);
99 void R600MCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
100 SmallVectorImpl
<MCFixup
> &Fixups
,
101 const MCSubtargetInfo
&STI
) const {
102 verifyInstructionPredicates(MI
,
103 computeAvailableFeatures(STI
.getFeatureBits()));
105 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
106 if (MI
.getOpcode() == R600::RETURN
||
107 MI
.getOpcode() == R600::FETCH_CLAUSE
||
108 MI
.getOpcode() == R600::ALU_CLAUSE
||
109 MI
.getOpcode() == R600::BUNDLE
||
110 MI
.getOpcode() == R600::KILL
) {
112 } else if (IS_VTX(Desc
)) {
113 uint64_t InstWord01
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
114 uint32_t InstWord2
= MI
.getOperand(2).getImm(); // Offset
115 if (!(STI
.getFeatureBits()[R600::FeatureCaymanISA
])) {
116 InstWord2
|= 1 << 19; // Mega-Fetch bit
119 Emit(InstWord01
, OS
);
121 Emit((uint32_t) 0, OS
);
122 } else if (IS_TEX(Desc
)) {
123 int64_t Sampler
= MI
.getOperand(14).getImm();
125 int64_t SrcSelect
[4] = {
126 MI
.getOperand(2).getImm(),
127 MI
.getOperand(3).getImm(),
128 MI
.getOperand(4).getImm(),
129 MI
.getOperand(5).getImm()
131 int64_t Offsets
[3] = {
132 MI
.getOperand(6).getImm() & 0x1F,
133 MI
.getOperand(7).getImm() & 0x1F,
134 MI
.getOperand(8).getImm() & 0x1F
137 uint64_t Word01
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
138 uint32_t Word2
= Sampler
<< 15 | SrcSelect
[ELEMENT_X
] << 20 |
139 SrcSelect
[ELEMENT_Y
] << 23 | SrcSelect
[ELEMENT_Z
] << 26 |
140 SrcSelect
[ELEMENT_W
] << 29 | Offsets
[0] << 0 | Offsets
[1] << 5 |
145 Emit((uint32_t) 0, OS
);
147 uint64_t Inst
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
148 if ((STI
.getFeatureBits()[R600::FeatureR600ALUInst
]) &&
149 ((Desc
.TSFlags
& R600_InstFlag::OP1
) ||
150 Desc
.TSFlags
& R600_InstFlag::OP2
)) {
151 uint64_t ISAOpCode
= Inst
& (0x3FFULL
<< 39);
152 Inst
&= ~(0x3FFULL
<< 39);
153 Inst
|= ISAOpCode
<< 1;
159 void R600MCCodeEmitter::Emit(uint32_t Value
, raw_ostream
&OS
) const {
160 support::endian::write(OS
, Value
, support::little
);
163 void R600MCCodeEmitter::Emit(uint64_t Value
, raw_ostream
&OS
) const {
164 support::endian::write(OS
, Value
, support::little
);
167 unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo
) const {
168 return MRI
.getEncodingValue(RegNo
) & HW_REG_MASK
;
171 uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
173 SmallVectorImpl
<MCFixup
> &Fixups
,
174 const MCSubtargetInfo
&STI
) const {
176 if (HAS_NATIVE_OPERANDS(MCII
.get(MI
.getOpcode()).TSFlags
))
177 return MRI
.getEncodingValue(MO
.getReg());
178 return getHWReg(MO
.getReg());
182 // We put rodata at the end of code section, then map the entire
183 // code secetion as vtx buf. Thus the section relative address is the
185 // Each R600 literal instruction has two operands
186 // We can't easily get the order of the current one, so compare against
187 // the first one and adjust offset.
188 const unsigned offset
= (&MO
== &MI
.getOperand(0)) ? 0 : 4;
189 Fixups
.push_back(MCFixup::create(offset
, MO
.getExpr(), FK_SecRel_4
, MI
.getLoc()));
197 #define ENABLE_INSTR_PREDICATE_VERIFIER
198 #include "R600GenMCCodeEmitter.inc"