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 "AMDGPURegisterInfo.h"
17 #include "MCTargetDesc/AMDGPUFixupKinds.h"
18 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
19 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
20 #include "SIDefines.h"
21 #include "Utils/AMDGPUBaseInfo.h"
22 #include "llvm/MC/MCCodeEmitter.h"
23 #include "llvm/MC/MCContext.h"
24 #include "llvm/MC/MCExpr.h"
25 #include "llvm/MC/MCFixup.h"
26 #include "llvm/MC/MCInst.h"
27 #include "llvm/MC/MCInstrDesc.h"
28 #include "llvm/MC/MCInstrInfo.h"
29 #include "llvm/MC/MCRegisterInfo.h"
30 #include "llvm/MC/MCSubtargetInfo.h"
31 #include "llvm/MC/MCSymbol.h"
32 #include "llvm/Support/Casting.h"
33 #include "llvm/Support/ErrorHandling.h"
34 #include "llvm/Support/MathExtras.h"
35 #include "llvm/Support/raw_ostream.h"
44 class SIMCCodeEmitter
: public AMDGPUMCCodeEmitter
{
45 const MCRegisterInfo
&MRI
;
47 /// Encode an fp or int literal
48 uint32_t getLitEncoding(const MCOperand
&MO
, const MCOperandInfo
&OpInfo
,
49 const MCSubtargetInfo
&STI
) const;
52 SIMCCodeEmitter(const MCInstrInfo
&mcii
, const MCRegisterInfo
&mri
,
54 : AMDGPUMCCodeEmitter(mcii
), MRI(mri
) {}
55 SIMCCodeEmitter(const SIMCCodeEmitter
&) = delete;
56 SIMCCodeEmitter
&operator=(const SIMCCodeEmitter
&) = delete;
58 /// Encode the instruction and write it to the OS.
59 void encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
60 SmallVectorImpl
<MCFixup
> &Fixups
,
61 const MCSubtargetInfo
&STI
) const override
;
63 /// \returns the encoding for an MCOperand.
64 uint64_t getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
65 SmallVectorImpl
<MCFixup
> &Fixups
,
66 const MCSubtargetInfo
&STI
) const override
;
68 /// Use a fixup to encode the simm16 field for SOPP branch
70 unsigned getSOPPBrEncoding(const MCInst
&MI
, unsigned OpNo
,
71 SmallVectorImpl
<MCFixup
> &Fixups
,
72 const MCSubtargetInfo
&STI
) const override
;
74 unsigned getSDWASrcEncoding(const MCInst
&MI
, unsigned OpNo
,
75 SmallVectorImpl
<MCFixup
> &Fixups
,
76 const MCSubtargetInfo
&STI
) const override
;
78 unsigned getSDWAVopcDstEncoding(const MCInst
&MI
, unsigned OpNo
,
79 SmallVectorImpl
<MCFixup
> &Fixups
,
80 const MCSubtargetInfo
&STI
) const override
;
82 unsigned getAVOperandEncoding(const MCInst
&MI
, unsigned OpNo
,
83 SmallVectorImpl
<MCFixup
> &Fixups
,
84 const MCSubtargetInfo
&STI
) const override
;
87 } // end anonymous namespace
89 MCCodeEmitter
*llvm::createSIMCCodeEmitter(const MCInstrInfo
&MCII
,
90 const MCRegisterInfo
&MRI
,
92 return new SIMCCodeEmitter(MCII
, MRI
, Ctx
);
95 // Returns the encoding value to use if the given integer is an integer inline
96 // immediate value, or 0 if it is not.
97 template <typename IntTy
>
98 static uint32_t getIntInlineImmEncoding(IntTy Imm
) {
99 if (Imm
>= 0 && Imm
<= 64)
102 if (Imm
>= -16 && Imm
<= -1)
103 return 192 + std::abs(Imm
);
108 static uint32_t getLit16Encoding(uint16_t Val
, const MCSubtargetInfo
&STI
) {
109 uint16_t IntImm
= getIntInlineImmEncoding(static_cast<int16_t>(Val
));
113 if (Val
== 0x3800) // 0.5
116 if (Val
== 0xB800) // -0.5
119 if (Val
== 0x3C00) // 1.0
122 if (Val
== 0xBC00) // -1.0
125 if (Val
== 0x4000) // 2.0
128 if (Val
== 0xC000) // -2.0
131 if (Val
== 0x4400) // 4.0
134 if (Val
== 0xC400) // -4.0
137 if (Val
== 0x3118 && // 1.0 / (2.0 * pi)
138 STI
.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm
])
144 static uint32_t getLit32Encoding(uint32_t Val
, const MCSubtargetInfo
&STI
) {
145 uint32_t IntImm
= getIntInlineImmEncoding(static_cast<int32_t>(Val
));
149 if (Val
== FloatToBits(0.5f
))
152 if (Val
== FloatToBits(-0.5f
))
155 if (Val
== FloatToBits(1.0f
))
158 if (Val
== FloatToBits(-1.0f
))
161 if (Val
== FloatToBits(2.0f
))
164 if (Val
== FloatToBits(-2.0f
))
167 if (Val
== FloatToBits(4.0f
))
170 if (Val
== FloatToBits(-4.0f
))
173 if (Val
== 0x3e22f983 && // 1.0 / (2.0 * pi)
174 STI
.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm
])
180 static uint32_t getLit64Encoding(uint64_t Val
, const MCSubtargetInfo
&STI
) {
181 uint32_t IntImm
= getIntInlineImmEncoding(static_cast<int64_t>(Val
));
185 if (Val
== DoubleToBits(0.5))
188 if (Val
== DoubleToBits(-0.5))
191 if (Val
== DoubleToBits(1.0))
194 if (Val
== DoubleToBits(-1.0))
197 if (Val
== DoubleToBits(2.0))
200 if (Val
== DoubleToBits(-2.0))
203 if (Val
== DoubleToBits(4.0))
206 if (Val
== DoubleToBits(-4.0))
209 if (Val
== 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
210 STI
.getFeatureBits()[AMDGPU::FeatureInv2PiInlineImm
])
216 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand
&MO
,
217 const MCOperandInfo
&OpInfo
,
218 const MCSubtargetInfo
&STI
) const {
221 const auto *C
= dyn_cast
<MCConstantExpr
>(MO
.getExpr());
228 assert(!MO
.isFPImm());
236 switch (OpInfo
.OperandType
) {
237 case AMDGPU::OPERAND_REG_IMM_INT32
:
238 case AMDGPU::OPERAND_REG_IMM_FP32
:
239 case AMDGPU::OPERAND_REG_INLINE_C_INT32
:
240 case AMDGPU::OPERAND_REG_INLINE_C_FP32
:
241 case AMDGPU::OPERAND_REG_INLINE_AC_INT32
:
242 case AMDGPU::OPERAND_REG_INLINE_AC_FP32
:
243 return getLit32Encoding(static_cast<uint32_t>(Imm
), STI
);
245 case AMDGPU::OPERAND_REG_IMM_INT64
:
246 case AMDGPU::OPERAND_REG_IMM_FP64
:
247 case AMDGPU::OPERAND_REG_INLINE_C_INT64
:
248 case AMDGPU::OPERAND_REG_INLINE_C_FP64
:
249 return getLit64Encoding(static_cast<uint64_t>(Imm
), STI
);
251 case AMDGPU::OPERAND_REG_IMM_INT16
:
252 case AMDGPU::OPERAND_REG_IMM_FP16
:
253 case AMDGPU::OPERAND_REG_INLINE_C_INT16
:
254 case AMDGPU::OPERAND_REG_INLINE_C_FP16
:
255 case AMDGPU::OPERAND_REG_INLINE_AC_INT16
:
256 case AMDGPU::OPERAND_REG_INLINE_AC_FP16
:
257 // FIXME Is this correct? What do inline immediates do on SI for f16 src
258 // which does not have f16 support?
259 return getLit16Encoding(static_cast<uint16_t>(Imm
), STI
);
261 case AMDGPU::OPERAND_REG_IMM_V2INT16
:
262 case AMDGPU::OPERAND_REG_IMM_V2FP16
:
263 if (!isUInt
<16>(Imm
) && STI
.getFeatureBits()[AMDGPU::FeatureVOP3Literal
])
264 return getLit32Encoding(static_cast<uint32_t>(Imm
), STI
);
266 case AMDGPU::OPERAND_REG_INLINE_C_V2INT16
:
267 case AMDGPU::OPERAND_REG_INLINE_C_V2FP16
:
268 case AMDGPU::OPERAND_REG_INLINE_AC_V2INT16
:
269 case AMDGPU::OPERAND_REG_INLINE_AC_V2FP16
: {
270 uint16_t Lo16
= static_cast<uint16_t>(Imm
);
271 uint32_t Encoding
= getLit16Encoding(Lo16
, STI
);
275 llvm_unreachable("invalid operand size");
279 void SIMCCodeEmitter::encodeInstruction(const MCInst
&MI
, raw_ostream
&OS
,
280 SmallVectorImpl
<MCFixup
> &Fixups
,
281 const MCSubtargetInfo
&STI
) const {
282 verifyInstructionPredicates(MI
,
283 computeAvailableFeatures(STI
.getFeatureBits()));
285 uint64_t Encoding
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
286 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
287 unsigned bytes
= Desc
.getSize();
289 for (unsigned i
= 0; i
< bytes
; i
++) {
290 OS
.write((uint8_t) ((Encoding
>> (8 * i
)) & 0xff));
294 if (AMDGPU::isGFX10(STI
) && Desc
.TSFlags
& SIInstrFlags::MIMG
) {
295 int vaddr0
= AMDGPU::getNamedOperandIdx(MI
.getOpcode(),
296 AMDGPU::OpName::vaddr0
);
297 int srsrc
= AMDGPU::getNamedOperandIdx(MI
.getOpcode(),
298 AMDGPU::OpName::srsrc
);
299 assert(vaddr0
>= 0 && srsrc
> vaddr0
);
300 unsigned NumExtraAddrs
= srsrc
- vaddr0
- 1;
301 unsigned NumPadding
= (-NumExtraAddrs
) & 3;
303 for (unsigned i
= 0; i
< NumExtraAddrs
; ++i
)
304 OS
.write((uint8_t)getMachineOpValue(MI
, MI
.getOperand(vaddr0
+ 1 + i
),
306 for (unsigned i
= 0; i
< NumPadding
; ++i
)
310 if ((bytes
> 8 && STI
.getFeatureBits()[AMDGPU::FeatureVOP3Literal
]) ||
311 (bytes
> 4 && !STI
.getFeatureBits()[AMDGPU::FeatureVOP3Literal
]))
314 // Check for additional literals in SRC0/1/2 (Op 1/2/3)
315 for (unsigned i
= 0, e
= Desc
.getNumOperands(); i
< e
; ++i
) {
317 // Check if this operand should be encoded as [SV]Src
318 if (!AMDGPU::isSISrcOperand(Desc
, i
))
321 // Is this operand a literal immediate?
322 const MCOperand
&Op
= MI
.getOperand(i
);
323 if (getLitEncoding(Op
, Desc
.OpInfo
[i
], STI
) != 255)
331 else if (Op
.isExpr()) {
332 if (const auto *C
= dyn_cast
<MCConstantExpr
>(Op
.getExpr()))
335 } else if (!Op
.isExpr()) // Exprs will be replaced with a fixup value.
336 llvm_unreachable("Must be immediate or expr");
338 for (unsigned j
= 0; j
< 4; j
++) {
339 OS
.write((uint8_t) ((Imm
>> (8 * j
)) & 0xff));
342 // Only one literal value allowed
347 unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst
&MI
, unsigned OpNo
,
348 SmallVectorImpl
<MCFixup
> &Fixups
,
349 const MCSubtargetInfo
&STI
) const {
350 const MCOperand
&MO
= MI
.getOperand(OpNo
);
353 const MCExpr
*Expr
= MO
.getExpr();
354 MCFixupKind Kind
= (MCFixupKind
)AMDGPU::fixup_si_sopp_br
;
355 Fixups
.push_back(MCFixup::create(0, Expr
, Kind
, MI
.getLoc()));
359 return getMachineOpValue(MI
, MO
, Fixups
, STI
);
363 SIMCCodeEmitter::getSDWASrcEncoding(const MCInst
&MI
, unsigned OpNo
,
364 SmallVectorImpl
<MCFixup
> &Fixups
,
365 const MCSubtargetInfo
&STI
) const {
366 using namespace AMDGPU::SDWA
;
370 const MCOperand
&MO
= MI
.getOperand(OpNo
);
373 unsigned Reg
= MO
.getReg();
374 RegEnc
|= MRI
.getEncodingValue(Reg
);
375 RegEnc
&= SDWA9EncValues::SRC_VGPR_MASK
;
376 if (AMDGPU::isSGPR(AMDGPU::mc2PseudoReg(Reg
), &MRI
)) {
377 RegEnc
|= SDWA9EncValues::SRC_SGPR_MASK
;
381 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
382 uint32_t Enc
= getLitEncoding(MO
, Desc
.OpInfo
[OpNo
], STI
);
383 if (Enc
!= ~0U && Enc
!= 255) {
384 return Enc
| SDWA9EncValues::SRC_SGPR_MASK
;
388 llvm_unreachable("Unsupported operand kind");
393 SIMCCodeEmitter::getSDWAVopcDstEncoding(const MCInst
&MI
, unsigned OpNo
,
394 SmallVectorImpl
<MCFixup
> &Fixups
,
395 const MCSubtargetInfo
&STI
) const {
396 using namespace AMDGPU::SDWA
;
400 const MCOperand
&MO
= MI
.getOperand(OpNo
);
402 unsigned Reg
= MO
.getReg();
403 if (Reg
!= AMDGPU::VCC
&& Reg
!= AMDGPU::VCC_LO
) {
404 RegEnc
|= MRI
.getEncodingValue(Reg
);
405 RegEnc
&= SDWA9EncValues::VOPC_DST_SGPR_MASK
;
406 RegEnc
|= SDWA9EncValues::VOPC_DST_VCC_MASK
;
412 SIMCCodeEmitter::getAVOperandEncoding(const MCInst
&MI
, unsigned OpNo
,
413 SmallVectorImpl
<MCFixup
> &Fixups
,
414 const MCSubtargetInfo
&STI
) const {
415 unsigned Reg
= MI
.getOperand(OpNo
).getReg();
416 uint64_t Enc
= MRI
.getEncodingValue(Reg
);
418 // VGPR and AGPR have the same encoding, but SrcA and SrcB operands of mfma
419 // instructions use acc[0:1] modifier bits to distinguish. These bits are
420 // encoded as a virtual 9th bit of the register for these operands.
421 if (MRI
.getRegClass(AMDGPU::AGPR_32RegClassID
).contains(Reg
) ||
422 MRI
.getRegClass(AMDGPU::AReg_64RegClassID
).contains(Reg
))
428 static bool needsPCRel(const MCExpr
*Expr
) {
429 switch (Expr
->getKind()) {
430 case MCExpr::SymbolRef
: {
431 auto *SE
= cast
<MCSymbolRefExpr
>(Expr
);
432 MCSymbolRefExpr::VariantKind Kind
= SE
->getKind();
433 return Kind
!= MCSymbolRefExpr::VK_AMDGPU_ABS32_LO
&&
434 Kind
!= MCSymbolRefExpr::VK_AMDGPU_ABS32_HI
;
436 case MCExpr::Binary
: {
437 auto *BE
= cast
<MCBinaryExpr
>(Expr
);
438 if (BE
->getOpcode() == MCBinaryExpr::Sub
)
440 return needsPCRel(BE
->getLHS()) || needsPCRel(BE
->getRHS());
443 return needsPCRel(cast
<MCUnaryExpr
>(Expr
)->getSubExpr());
445 case MCExpr::Constant
:
448 llvm_unreachable("invalid kind");
451 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst
&MI
,
453 SmallVectorImpl
<MCFixup
> &Fixups
,
454 const MCSubtargetInfo
&STI
) const {
456 return MRI
.getEncodingValue(MO
.getReg());
458 if (MO
.isExpr() && MO
.getExpr()->getKind() != MCExpr::Constant
) {
459 // FIXME: If this is expression is PCRel or not should not depend on what
460 // the expression looks like. Given that this is just a general expression,
461 // it should probably be FK_Data_4 and whatever is producing
463 // s_add_u32 s2, s2, (extern_const_addrspace+16
465 // And expecting a PCRel should instead produce
468 // s_add_u32 s2, s2, (extern_const_addrspace+16)-.Ltmp1
470 if (needsPCRel(MO
.getExpr()))
475 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
476 uint32_t Offset
= Desc
.getSize();
477 assert(Offset
== 4 || Offset
== 8);
480 MCFixup::create(Offset
, MO
.getExpr(), Kind
, MI
.getLoc()));
483 // Figure out the operand number, needed for isSrcOperand check
485 for (unsigned e
= MI
.getNumOperands(); OpNo
< e
; ++OpNo
) {
486 if (&MO
== &MI
.getOperand(OpNo
))
490 const MCInstrDesc
&Desc
= MCII
.get(MI
.getOpcode());
491 if (AMDGPU::isSISrcOperand(Desc
, OpNo
)) {
492 uint32_t Enc
= getLitEncoding(MO
, Desc
.OpInfo
[OpNo
], STI
);
494 (Enc
!= 255 || Desc
.getSize() == 4 || Desc
.getSize() == 8))
497 } else if (MO
.isImm())
500 llvm_unreachable("Encoding of this operand type is not supported yet.");
504 #define ENABLE_INSTR_PREDICATE_VERIFIER
505 #include "AMDGPUGenMCCodeEmitter.inc"