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/AMDGPUMCTargetDesc.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/SubtargetFeature.h"
24 #include "llvm/Support/EndianStream.h"
30 class R600MCCodeEmitter
: public MCCodeEmitter
{
31 const MCRegisterInfo
&MRI
;
32 const MCInstrInfo
&MCII
;
35 R600MCCodeEmitter(const MCInstrInfo
&mcii
, const MCRegisterInfo
&mri
)
36 : MRI(mri
), MCII(mcii
) {}
37 R600MCCodeEmitter(const R600MCCodeEmitter
&) = delete;
38 R600MCCodeEmitter
&operator=(const R600MCCodeEmitter
&) = delete;
40 /// Encode the instruction and write it to the OS.
41 void encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
42 SmallVectorImpl
<MCFixup
> &Fixups
,
43 const MCSubtargetInfo
&STI
) const override
;
45 /// \returns the encoding for an MCOperand.
46 uint64_t getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
47 SmallVectorImpl
<MCFixup
> &Fixups
,
48 const MCSubtargetInfo
&STI
) const;
52 void Emit(uint32_t value
, raw_ostream
&OS
) const;
53 void Emit(uint64_t value
, raw_ostream
&OS
) const;
55 unsigned getHWReg(unsigned regNo
) const;
57 uint64_t getBinaryCodeForInstr(const MCInst
&MI
,
58 SmallVectorImpl
<MCFixup
> &Fixups
,
59 const MCSubtargetInfo
&STI
) const;
60 FeatureBitset
computeAvailableFeatures(const FeatureBitset
&FB
) const;
62 verifyInstructionPredicates(const MCInst
&MI
,
63 const FeatureBitset
&AvailableFeatures
) const;
67 } // end anonymous namespace
86 MCCodeEmitter
*llvm::createR600MCCodeEmitter(const MCInstrInfo
&MCII
,
87 const MCRegisterInfo
&MRI
,
89 return new R600MCCodeEmitter(MCII
, MRI
);
92 void R600MCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
93 SmallVectorImpl
<MCFixup
> &Fixups
,
94 const MCSubtargetInfo
&STI
) const {
95 verifyInstructionPredicates(MI
,
96 computeAvailableFeatures(STI
.getFeatureBits()));
98 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
99 if (MI
.getOpcode() == R600::RETURN
||
100 MI
.getOpcode() == R600::FETCH_CLAUSE
||
101 MI
.getOpcode() == R600::ALU_CLAUSE
||
102 MI
.getOpcode() == R600::BUNDLE
||
103 MI
.getOpcode() == R600::KILL
) {
105 } else if (IS_VTX(Desc
)) {
106 uint64_t InstWord01
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
107 uint32_t InstWord2
= MI
.getOperand(2).getImm(); // Offset
108 if (!(STI
.getFeatureBits()[R600::FeatureCaymanISA
])) {
109 InstWord2
|= 1 << 19; // Mega-Fetch bit
112 Emit(InstWord01
, OS
);
114 Emit((uint32_t) 0, OS
);
115 } else if (IS_TEX(Desc
)) {
116 int64_t Sampler
= MI
.getOperand(14).getImm();
118 int64_t SrcSelect
[4] = {
119 MI
.getOperand(2).getImm(),
120 MI
.getOperand(3).getImm(),
121 MI
.getOperand(4).getImm(),
122 MI
.getOperand(5).getImm()
124 int64_t Offsets
[3] = {
125 MI
.getOperand(6).getImm() & 0x1F,
126 MI
.getOperand(7).getImm() & 0x1F,
127 MI
.getOperand(8).getImm() & 0x1F
130 uint64_t Word01
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
131 uint32_t Word2
= Sampler
<< 15 | SrcSelect
[ELEMENT_X
] << 20 |
132 SrcSelect
[ELEMENT_Y
] << 23 | SrcSelect
[ELEMENT_Z
] << 26 |
133 SrcSelect
[ELEMENT_W
] << 29 | Offsets
[0] << 0 | Offsets
[1] << 5 |
138 Emit((uint32_t) 0, OS
);
140 uint64_t Inst
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
141 if ((STI
.getFeatureBits()[R600::FeatureR600ALUInst
]) &&
142 ((Desc
.TSFlags
& R600_InstFlag::OP1
) ||
143 Desc
.TSFlags
& R600_InstFlag::OP2
)) {
144 uint64_t ISAOpCode
= Inst
& (0x3FFULL
<< 39);
145 Inst
&= ~(0x3FFULL
<< 39);
146 Inst
|= ISAOpCode
<< 1;
152 void R600MCCodeEmitter::Emit(uint32_t Value
, raw_ostream
&OS
) const {
153 support::endian::write(OS
, Value
, support::little
);
156 void R600MCCodeEmitter::Emit(uint64_t Value
, raw_ostream
&OS
) const {
157 support::endian::write(OS
, Value
, support::little
);
160 unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo
) const {
161 return MRI
.getEncodingValue(RegNo
) & HW_REG_MASK
;
164 uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
166 SmallVectorImpl
<MCFixup
> &Fixups
,
167 const MCSubtargetInfo
&STI
) const {
169 if (HAS_NATIVE_OPERANDS(MCII
.get(MI
.getOpcode()).TSFlags
))
170 return MRI
.getEncodingValue(MO
.getReg());
171 return getHWReg(MO
.getReg());
175 // We put rodata at the end of code section, then map the entire
176 // code secetion as vtx buf. Thus the section relative address is the
178 // Each R600 literal instruction has two operands
179 // We can't easily get the order of the current one, so compare against
180 // the first one and adjust offset.
181 const unsigned offset
= (&MO
== &MI
.getOperand(0)) ? 0 : 4;
182 Fixups
.push_back(MCFixup::create(offset
, MO
.getExpr(), FK_SecRel_4
, MI
.getLoc()));
190 #define ENABLE_INSTR_PREDICATE_VERIFIER
191 #include "R600GenMCCodeEmitter.inc"