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 uint64_t computeAvailableFeatures(const FeatureBitset
&FB
) const;
68 void verifyInstructionPredicates(const MCInst
&MI
,
69 uint64_t AvailableFeatures
) const;
73 } // end anonymous namespace
92 MCCodeEmitter
*llvm::createR600MCCodeEmitter(const MCInstrInfo
&MCII
,
93 const MCRegisterInfo
&MRI
,
95 return new R600MCCodeEmitter(MCII
, MRI
);
98 void R600MCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
99 SmallVectorImpl
<MCFixup
> &Fixups
,
100 const MCSubtargetInfo
&STI
) const {
101 verifyInstructionPredicates(MI
,
102 computeAvailableFeatures(STI
.getFeatureBits()));
104 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
105 if (MI
.getOpcode() == R600::RETURN
||
106 MI
.getOpcode() == R600::FETCH_CLAUSE
||
107 MI
.getOpcode() == R600::ALU_CLAUSE
||
108 MI
.getOpcode() == R600::BUNDLE
||
109 MI
.getOpcode() == R600::KILL
) {
111 } else if (IS_VTX(Desc
)) {
112 uint64_t InstWord01
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
113 uint32_t InstWord2
= MI
.getOperand(2).getImm(); // Offset
114 if (!(STI
.getFeatureBits()[R600::FeatureCaymanISA
])) {
115 InstWord2
|= 1 << 19; // Mega-Fetch bit
118 Emit(InstWord01
, OS
);
120 Emit((uint32_t) 0, OS
);
121 } else if (IS_TEX(Desc
)) {
122 int64_t Sampler
= MI
.getOperand(14).getImm();
124 int64_t SrcSelect
[4] = {
125 MI
.getOperand(2).getImm(),
126 MI
.getOperand(3).getImm(),
127 MI
.getOperand(4).getImm(),
128 MI
.getOperand(5).getImm()
130 int64_t Offsets
[3] = {
131 MI
.getOperand(6).getImm() & 0x1F,
132 MI
.getOperand(7).getImm() & 0x1F,
133 MI
.getOperand(8).getImm() & 0x1F
136 uint64_t Word01
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
137 uint32_t Word2
= Sampler
<< 15 | SrcSelect
[ELEMENT_X
] << 20 |
138 SrcSelect
[ELEMENT_Y
] << 23 | SrcSelect
[ELEMENT_Z
] << 26 |
139 SrcSelect
[ELEMENT_W
] << 29 | Offsets
[0] << 0 | Offsets
[1] << 5 |
144 Emit((uint32_t) 0, OS
);
146 uint64_t Inst
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
147 if ((STI
.getFeatureBits()[R600::FeatureR600ALUInst
]) &&
148 ((Desc
.TSFlags
& R600_InstFlag::OP1
) ||
149 Desc
.TSFlags
& R600_InstFlag::OP2
)) {
150 uint64_t ISAOpCode
= Inst
& (0x3FFULL
<< 39);
151 Inst
&= ~(0x3FFULL
<< 39);
152 Inst
|= ISAOpCode
<< 1;
158 void R600MCCodeEmitter::Emit(uint32_t Value
, raw_ostream
&OS
) const {
159 support::endian::write(OS
, Value
, support::little
);
162 void R600MCCodeEmitter::Emit(uint64_t Value
, raw_ostream
&OS
) const {
163 support::endian::write(OS
, Value
, support::little
);
166 unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo
) const {
167 return MRI
.getEncodingValue(RegNo
) & HW_REG_MASK
;
170 uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
172 SmallVectorImpl
<MCFixup
> &Fixups
,
173 const MCSubtargetInfo
&STI
) const {
175 if (HAS_NATIVE_OPERANDS(MCII
.get(MI
.getOpcode()).TSFlags
))
176 return MRI
.getEncodingValue(MO
.getReg());
177 return getHWReg(MO
.getReg());
181 // We put rodata at the end of code section, then map the entire
182 // code secetion as vtx buf. Thus the section relative address is the
184 // Each R600 literal instruction has two operands
185 // We can't easily get the order of the current one, so compare against
186 // the first one and adjust offset.
187 const unsigned offset
= (&MO
== &MI
.getOperand(0)) ? 0 : 4;
188 Fixups
.push_back(MCFixup::create(offset
, MO
.getExpr(), FK_SecRel_4
, MI
.getLoc()));
196 #define ENABLE_INSTR_PREDICATE_VERIFIER
197 #include "R600GenMCCodeEmitter.inc"