1 //===-- SIMCCodeEmitter.cpp - SI Code Emitter -----------------------------===//
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 //===----------------------------------------------------------------------===//
10 /// The SI code emitter produces machine code that can be executed
11 /// directly on the GPU device.
13 //===----------------------------------------------------------------------===//
16 #include "MCTargetDesc/AMDGPUFixupKinds.h"
17 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
18 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
19 #include "Utils/AMDGPUBaseInfo.h"
20 #include "llvm/MC/MCCodeEmitter.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCExpr.h"
23 #include "llvm/MC/MCFixup.h"
24 #include "llvm/MC/MCInst.h"
25 #include "llvm/MC/MCInstrDesc.h"
26 #include "llvm/MC/MCInstrInfo.h"
27 #include "llvm/MC/MCRegisterInfo.h"
28 #include "llvm/MC/MCSubtargetInfo.h"
29 #include "llvm/MC/MCSymbol.h"
30 #include "llvm/Support/Casting.h"
31 #include "llvm/Support/ErrorHandling.h"
32 #include "llvm/Support/MathExtras.h"
33 #include "llvm/Support/raw_ostream.h"
42 class SIMCCodeEmitter
: public AMDGPUMCCodeEmitter
{
43 const MCRegisterInfo
&MRI
;
45 /// Encode an fp or int literal
46 uint32_t getLitEncoding(const MCOperand
&MO
, const MCOperandInfo
&OpInfo
,
47 const MCSubtargetInfo
&STI
) const;
50 SIMCCodeEmitter(const MCInstrInfo
&mcii
, const MCRegisterInfo
&mri
,
52 : AMDGPUMCCodeEmitter(mcii
), MRI(mri
) {}
53 SIMCCodeEmitter(const SIMCCodeEmitter
&) = delete;
54 SIMCCodeEmitter
&operator=(const SIMCCodeEmitter
&) = delete;
56 /// Encode the instruction and write it to the OS.
57 void encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
58 SmallVectorImpl
<MCFixup
> &Fixups
,
59 const MCSubtargetInfo
&STI
) const override
;
61 /// \returns the encoding for an MCOperand.
62 uint64_t getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
63 SmallVectorImpl
<MCFixup
> &Fixups
,
64 const MCSubtargetInfo
&STI
) const override
;
66 /// Use a fixup to encode the simm16 field for SOPP branch
68 unsigned getSOPPBrEncoding(const MCInst
&MI
, unsigned OpNo
,
69 SmallVectorImpl
<MCFixup
> &Fixups
,
70 const MCSubtargetInfo
&STI
) const override
;
72 unsigned getSDWASrcEncoding(const MCInst
&MI
, unsigned OpNo
,
73 SmallVectorImpl
<MCFixup
> &Fixups
,
74 const MCSubtargetInfo
&STI
) const override
;
76 unsigned getSDWAVopcDstEncoding(const MCInst
&MI
, unsigned OpNo
,
77 SmallVectorImpl
<MCFixup
> &Fixups
,
78 const MCSubtargetInfo
&STI
) const override
;
81 } // end anonymous namespace
83 MCCodeEmitter
*llvm::createSIMCCodeEmitter(const MCInstrInfo
&MCII
,
84 const MCRegisterInfo
&MRI
,
86 return new SIMCCodeEmitter(MCII
, MRI
, Ctx
);
89 // Returns the encoding value to use if the given integer is an integer inline
90 // immediate value, or 0 if it is not.
91 template <typename IntTy
>
92 static uint32_t getIntInlineImmEncoding(IntTy Imm
) {
93 if (Imm
>= 0 && Imm
<= 64)
96 if (Imm
>= -16 && Imm
<= -1)
97 return 192 + std::abs(Imm
);
102 static uint32_t getLit16Encoding(uint16_t Val
, const MCSubtargetInfo
&STI
) {
103 uint16_t IntImm
= getIntInlineImmEncoding(static_cast<int16_t>(Val
));
107 if (Val
== 0x3800) // 0.5
110 if (Val
== 0xB800) // -0.5
113 if (Val
== 0x3C00) // 1.0
116 if (Val
== 0xBC00) // -1.0
119 if (Val
== 0x4000) // 2.0
122 if (Val
== 0xC000) // -2.0
125 if (Val
== 0x4400) // 4.0
128 if (Val
== 0xC400) // -4.0
131 if (Val
== 0x3118 && // 1.0 / (2.0 * pi)
132 STI
.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm
])
138 static uint32_t getLit32Encoding(uint32_t Val
, const MCSubtargetInfo
&STI
) {
139 uint32_t IntImm
= getIntInlineImmEncoding(static_cast<int32_t>(Val
));
143 if (Val
== FloatToBits(0.5f
))
146 if (Val
== FloatToBits(-0.5f
))
149 if (Val
== FloatToBits(1.0f
))
152 if (Val
== FloatToBits(-1.0f
))
155 if (Val
== FloatToBits(2.0f
))
158 if (Val
== FloatToBits(-2.0f
))
161 if (Val
== FloatToBits(4.0f
))
164 if (Val
== FloatToBits(-4.0f
))
167 if (Val
== 0x3e22f983 && // 1.0 / (2.0 * pi)
168 STI
.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm
])
174 static uint32_t getLit64Encoding(uint64_t Val
, const MCSubtargetInfo
&STI
) {
175 uint32_t IntImm
= getIntInlineImmEncoding(static_cast<int64_t>(Val
));
179 if (Val
== DoubleToBits(0.5))
182 if (Val
== DoubleToBits(-0.5))
185 if (Val
== DoubleToBits(1.0))
188 if (Val
== DoubleToBits(-1.0))
191 if (Val
== DoubleToBits(2.0))
194 if (Val
== DoubleToBits(-2.0))
197 if (Val
== DoubleToBits(4.0))
200 if (Val
== DoubleToBits(-4.0))
203 if (Val
== 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
204 STI
.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm
])
210 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand
&MO
,
211 const MCOperandInfo
&OpInfo
,
212 const MCSubtargetInfo
&STI
) const {
215 const auto *C
= dyn_cast
<MCConstantExpr
>(MO
.getExpr());
222 assert(!MO
.isFPImm());
230 switch (OpInfo
.OperandType
) {
231 case AMDGPU::OPERAND_REG_IMM_INT32
:
232 case AMDGPU::OPERAND_REG_IMM_FP32
:
233 case AMDGPU::OPERAND_REG_INLINE_C_INT32
:
234 case AMDGPU::OPERAND_REG_INLINE_C_FP32
:
235 return getLit32Encoding(static_cast<uint32_t>(Imm
), STI
);
237 case AMDGPU::OPERAND_REG_IMM_INT64
:
238 case AMDGPU::OPERAND_REG_IMM_FP64
:
239 case AMDGPU::OPERAND_REG_INLINE_C_INT64
:
240 case AMDGPU::OPERAND_REG_INLINE_C_FP64
:
241 return getLit64Encoding(static_cast<uint64_t>(Imm
), STI
);
243 case AMDGPU::OPERAND_REG_IMM_INT16
:
244 case AMDGPU::OPERAND_REG_IMM_FP16
:
245 case AMDGPU::OPERAND_REG_INLINE_C_INT16
:
246 case AMDGPU::OPERAND_REG_INLINE_C_FP16
:
247 // FIXME Is this correct? What do inline immediates do on SI for f16 src
248 // which does not have f16 support?
249 return getLit16Encoding(static_cast<uint16_t>(Imm
), STI
);
251 case AMDGPU::OPERAND_REG_INLINE_C_V2INT16
:
252 case AMDGPU::OPERAND_REG_INLINE_C_V2FP16
: {
253 uint16_t Lo16
= static_cast<uint16_t>(Imm
);
254 uint32_t Encoding
= getLit16Encoding(Lo16
, STI
);
258 llvm_unreachable("invalid operand size");
262 void SIMCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
263 SmallVectorImpl
<MCFixup
> &Fixups
,
264 const MCSubtargetInfo
&STI
) const {
265 verifyInstructionPredicates(MI
,
266 computeAvailableFeatures(STI
.getFeatureBits()));
268 uint64_t Encoding
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
269 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
270 unsigned bytes
= Desc
.getSize();
272 for (unsigned i
= 0; i
< bytes
; i
++) {
273 OS
.write((uint8_t) ((Encoding
>> (8 * i
)) & 0xff));
279 // Check for additional literals in SRC0/1/2 (Op 1/2/3)
280 for (unsigned i
= 0, e
= Desc
.getNumOperands(); i
< e
; ++i
) {
282 // Check if this operand should be encoded as [SV]Src
283 if (!AMDGPU::isSISrcOperand(Desc
, i
))
286 // Is this operand a literal immediate?
287 const MCOperand
&Op
= MI
.getOperand(i
);
288 if (getLitEncoding(Op
, Desc
.OpInfo
[i
], STI
) != 255)
296 else if (Op
.isExpr()) {
297 if (const auto *C
= dyn_cast
<MCConstantExpr
>(Op
.getExpr()))
300 } else if (!Op
.isExpr()) // Exprs will be replaced with a fixup value.
301 llvm_unreachable("Must be immediate or expr");
303 for (unsigned j
= 0; j
< 4; j
++) {
304 OS
.write((uint8_t) ((Imm
>> (8 * j
)) & 0xff));
307 // Only one literal value allowed
312 unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst
&MI
, unsigned OpNo
,
313 SmallVectorImpl
<MCFixup
> &Fixups
,
314 const MCSubtargetInfo
&STI
) const {
315 const MCOperand
&MO
= MI
.getOperand(OpNo
);
318 const MCExpr
*Expr
= MO
.getExpr();
319 MCFixupKind Kind
= (MCFixupKind
)AMDGPU::fixup_si_sopp_br
;
320 Fixups
.push_back(MCFixup::create(0, Expr
, Kind
, MI
.getLoc()));
324 return getMachineOpValue(MI
, MO
, Fixups
, STI
);
328 SIMCCodeEmitter::getSDWASrcEncoding(const MCInst
&MI
, unsigned OpNo
,
329 SmallVectorImpl
<MCFixup
> &Fixups
,
330 const MCSubtargetInfo
&STI
) const {
331 using namespace AMDGPU::SDWA
;
335 const MCOperand
&MO
= MI
.getOperand(OpNo
);
338 unsigned Reg
= MO
.getReg();
339 RegEnc
|= MRI
.getEncodingValue(Reg
);
340 RegEnc
&= SDWA9EncValues::SRC_VGPR_MASK
;
341 if (AMDGPU::isSGPR(AMDGPU::mc2PseudoReg(Reg
), &MRI
)) {
342 RegEnc
|= SDWA9EncValues::SRC_SGPR_MASK
;
346 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
347 uint32_t Enc
= getLitEncoding(MO
, Desc
.OpInfo
[OpNo
], STI
);
348 if (Enc
!= ~0U && Enc
!= 255) {
349 return Enc
| SDWA9EncValues::SRC_SGPR_MASK
;
353 llvm_unreachable("Unsupported operand kind");
358 SIMCCodeEmitter::getSDWAVopcDstEncoding(const MCInst
&MI
, unsigned OpNo
,
359 SmallVectorImpl
<MCFixup
> &Fixups
,
360 const MCSubtargetInfo
&STI
) const {
361 using namespace AMDGPU::SDWA
;
365 const MCOperand
&MO
= MI
.getOperand(OpNo
);
367 unsigned Reg
= MO
.getReg();
368 if (Reg
!= AMDGPU::VCC
) {
369 RegEnc
|= MRI
.getEncodingValue(Reg
);
370 RegEnc
&= SDWA9EncValues::VOPC_DST_SGPR_MASK
;
371 RegEnc
|= SDWA9EncValues::VOPC_DST_VCC_MASK
;
376 static bool needsPCRel(const MCExpr
*Expr
) {
377 switch (Expr
->getKind()) {
378 case MCExpr::SymbolRef
:
380 case MCExpr::Binary
: {
381 auto *BE
= cast
<MCBinaryExpr
>(Expr
);
382 if (BE
->getOpcode() == MCBinaryExpr::Sub
)
384 return needsPCRel(BE
->getLHS()) || needsPCRel(BE
->getRHS());
387 return needsPCRel(cast
<MCUnaryExpr
>(Expr
)->getSubExpr());
389 case MCExpr::Constant
:
392 llvm_unreachable("invalid kind");
395 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
397 SmallVectorImpl
<MCFixup
> &Fixups
,
398 const MCSubtargetInfo
&STI
) const {
400 return MRI
.getEncodingValue(MO
.getReg());
402 if (MO
.isExpr() && MO
.getExpr()->getKind() != MCExpr::Constant
) {
403 // FIXME: If this is expression is PCRel or not should not depend on what
404 // the expression looks like. Given that this is just a general expression,
405 // it should probably be FK_Data_4 and whatever is producing
407 // s_add_u32 s2, s2, (extern_const_addrspace+16
409 // And expecting a PCRel should instead produce
412 // s_add_u32 s2, s2, (extern_const_addrspace+16)-.Ltmp1
414 if (needsPCRel(MO
.getExpr()))
418 Fixups
.push_back(MCFixup::create(4, MO
.getExpr(), Kind
, MI
.getLoc()));
421 // Figure out the operand number, needed for isSrcOperand check
423 for (unsigned e
= MI
.getNumOperands(); OpNo
< e
; ++OpNo
) {
424 if (&MO
== &MI
.getOperand(OpNo
))
428 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
429 if (AMDGPU::isSISrcOperand(Desc
, OpNo
)) {
430 uint32_t Enc
= getLitEncoding(MO
, Desc
.OpInfo
[OpNo
], STI
);
431 if (Enc
!= ~0U && (Enc
!= 255 || Desc
.getSize() == 4))
434 } else if (MO
.isImm())
437 llvm_unreachable("Encoding of this operand type is not supported yet.");
441 #define ENABLE_INSTR_PREDICATE_VERIFIER
442 #include "AMDGPUGenMCCodeEmitter.inc"