LLVM 23.0.0git
AMDGPUMCCodeEmitter.cpp
Go to the documentation of this file.
1//===-- AMDGPUMCCodeEmitter.cpp - AMDGPU Code Emitter ---------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// The AMDGPU code emitter produces machine code that can be executed
11/// directly on the GPU device.
12//
13//===----------------------------------------------------------------------===//
14
18#include "SIDefines.h"
20#include "llvm/ADT/APInt.h"
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCInstrInfo.h"
29#include <optional>
30
31using namespace llvm;
32
33namespace {
34
35class AMDGPUMCCodeEmitter : public MCCodeEmitter {
36 const MCRegisterInfo &MRI;
37 const MCInstrInfo &MCII;
38
39public:
40 AMDGPUMCCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo &MRI)
41 : MRI(MRI), MCII(MCII) {}
42
43 /// Encode the instruction and write it to the OS.
44 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
45 SmallVectorImpl<MCFixup> &Fixups,
46 const MCSubtargetInfo &STI) const override;
47
48 void getMachineOpValue(const MCInst &MI, const MCOperand &MO, APInt &Op,
49 SmallVectorImpl<MCFixup> &Fixups,
50 const MCSubtargetInfo &STI) const;
51
52 void getMachineOpValueT16(const MCInst &MI, unsigned OpNo, APInt &Op,
53 SmallVectorImpl<MCFixup> &Fixups,
54 const MCSubtargetInfo &STI) const;
55
56 void getMachineOpValueT16Lo128(const MCInst &MI, unsigned OpNo, APInt &Op,
57 SmallVectorImpl<MCFixup> &Fixups,
58 const MCSubtargetInfo &STI) const;
59
60 /// Use a fixup to encode the simm16 field for SOPP branch
61 /// instructions.
62 void getSOPPBrEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
63 SmallVectorImpl<MCFixup> &Fixups,
64 const MCSubtargetInfo &STI) const;
65
66 void getSMEMOffsetEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
67 SmallVectorImpl<MCFixup> &Fixups,
68 const MCSubtargetInfo &STI) const;
69
70 void getSDWASrcEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
71 SmallVectorImpl<MCFixup> &Fixups,
72 const MCSubtargetInfo &STI) const;
73
74 void getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
75 SmallVectorImpl<MCFixup> &Fixups,
76 const MCSubtargetInfo &STI) const;
77
78 void getAVOperandEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
79 SmallVectorImpl<MCFixup> &Fixups,
80 const MCSubtargetInfo &STI) const;
81
82private:
83 uint64_t getImplicitOpSelHiEncoding(int Opcode) const;
84 void getMachineOpValueCommon(const MCInst &MI, const MCOperand &MO,
85 unsigned OpNo, APInt &Op,
86 SmallVectorImpl<MCFixup> &Fixups,
87 const MCSubtargetInfo &STI) const;
88
89 /// Encode an fp or int literal.
90 std::optional<uint64_t>
91 getLitEncoding(const MCInstrDesc &Desc, const MCOperand &MO, unsigned OpNo,
92 const MCSubtargetInfo &STI,
93 bool HasMandatoryLiteral = false) const;
94
95 void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
96 APInt &Inst, APInt &Scratch,
97 const MCSubtargetInfo &STI) const;
98
99 template <bool HasSrc0, bool HasSrc1, bool HasSrc2>
100 APInt postEncodeVOP3(const MCInst &MI, APInt EncodedValue,
101 const MCSubtargetInfo &STI) const;
102
103 APInt postEncodeVOPCX(const MCInst &MI, APInt EncodedValue,
104 const MCSubtargetInfo &STI) const;
105};
106
107} // end anonymous namespace
108
110 MCContext &Ctx) {
111 return new AMDGPUMCCodeEmitter(MCII, *Ctx.getRegisterInfo());
112}
113
115 const MCExpr *Value, uint16_t Kind, bool PCRel = false) {
116 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));
117}
118
119// Returns the encoding value to use if the given integer is an integer inline
120// immediate value, or 0 if it is not.
121template <typename IntTy>
123 if (Imm >= 0 && Imm <= 64)
124 return 128 + Imm;
125
126 if (Imm >= -16 && Imm <= -1)
127 return 192 + std::abs(Imm);
128
129 return 0;
130}
131
133 uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
134 if (IntImm != 0)
135 return IntImm;
136
137 if (Val == 0x3800) // 0.5
138 return 240;
139
140 if (Val == 0xB800) // -0.5
141 return 241;
142
143 if (Val == 0x3C00) // 1.0
144 return 242;
145
146 if (Val == 0xBC00) // -1.0
147 return 243;
148
149 if (Val == 0x4000) // 2.0
150 return 244;
151
152 if (Val == 0xC000) // -2.0
153 return 245;
154
155 if (Val == 0x4400) // 4.0
156 return 246;
157
158 if (Val == 0xC400) // -4.0
159 return 247;
160
161 if (Val == 0x3118 && // 1.0 / (2.0 * pi)
162 STI.hasFeature(AMDGPU::FeatureInv2PiInlineImm))
163 return 248;
164
165 return 255;
166}
167
169 uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
170 if (IntImm != 0)
171 return IntImm;
172
173 // clang-format off
174 switch (Val) {
175 case 0x3F00: return 240; // 0.5
176 case 0xBF00: return 241; // -0.5
177 case 0x3F80: return 242; // 1.0
178 case 0xBF80: return 243; // -1.0
179 case 0x4000: return 244; // 2.0
180 case 0xC000: return 245; // -2.0
181 case 0x4080: return 246; // 4.0
182 case 0xC080: return 247; // -4.0
183 case 0x3E22: return 248; // 1.0 / (2.0 * pi)
184 default: return 255;
185 }
186 // clang-format on
187}
188
190 uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
191 if (IntImm != 0)
192 return IntImm;
193
194 if (Val == llvm::bit_cast<uint32_t>(0.5f))
195 return 240;
196
197 if (Val == llvm::bit_cast<uint32_t>(-0.5f))
198 return 241;
199
200 if (Val == llvm::bit_cast<uint32_t>(1.0f))
201 return 242;
202
203 if (Val == llvm::bit_cast<uint32_t>(-1.0f))
204 return 243;
205
206 if (Val == llvm::bit_cast<uint32_t>(2.0f))
207 return 244;
208
209 if (Val == llvm::bit_cast<uint32_t>(-2.0f))
210 return 245;
211
212 if (Val == llvm::bit_cast<uint32_t>(4.0f))
213 return 246;
214
215 if (Val == llvm::bit_cast<uint32_t>(-4.0f))
216 return 247;
217
218 if (Val == 0x3e22f983 && // 1.0 / (2.0 * pi)
219 STI.hasFeature(AMDGPU::FeatureInv2PiInlineImm))
220 return 248;
221
222 return 255;
223}
224
226 return getLit32Encoding(Val, STI);
227}
228
230 const MCSubtargetInfo &STI, bool IsFP) {
231 uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
232 if (IntImm != 0)
233 return IntImm;
234
235 if (Val == llvm::bit_cast<uint64_t>(0.5))
236 return 240;
237
238 if (Val == llvm::bit_cast<uint64_t>(-0.5))
239 return 241;
240
241 if (Val == llvm::bit_cast<uint64_t>(1.0))
242 return 242;
243
244 if (Val == llvm::bit_cast<uint64_t>(-1.0))
245 return 243;
246
247 if (Val == llvm::bit_cast<uint64_t>(2.0))
248 return 244;
249
250 if (Val == llvm::bit_cast<uint64_t>(-2.0))
251 return 245;
252
253 if (Val == llvm::bit_cast<uint64_t>(4.0))
254 return 246;
255
256 if (Val == llvm::bit_cast<uint64_t>(-4.0))
257 return 247;
258
259 if (Val == 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
260 STI.hasFeature(AMDGPU::FeatureInv2PiInlineImm))
261 return 248;
262
263 // The rest part needs to align with AMDGPUInstPrinter::printLiteral64.
264
265 bool CanUse64BitLiterals =
266 STI.hasFeature(AMDGPU::Feature64BitLiterals) &&
268 if (IsFP) {
269 return CanUse64BitLiterals && Lo_32(Val) ? 254 : 255;
270 }
271
272 return CanUse64BitLiterals && (!isInt<32>(Val) || !isUInt<32>(Val)) ? 254
273 : 255;
274}
275
276std::optional<uint64_t> AMDGPUMCCodeEmitter::getLitEncoding(
277 const MCInstrDesc &Desc, const MCOperand &MO, unsigned OpNo,
278 const MCSubtargetInfo &STI, bool HasMandatoryLiteral) const {
279 const MCOperandInfo &OpInfo = Desc.operands()[OpNo];
280 int64_t Imm = 0;
281 if (MO.isExpr()) {
282 if (!MO.getExpr()->evaluateAsAbsolute(Imm) ||
284 if (OpInfo.OperandType == AMDGPU::OPERAND_KIMM16 ||
287 return Imm;
288 if (STI.hasFeature(AMDGPU::Feature64BitLiterals) &&
289 AMDGPU::getOperandSize(OpInfo) == 8 &&
291 return 254;
292 return 255;
293 }
294 } else {
295 assert(!MO.isDFPImm());
296
297 if (!MO.isImm())
298 return {};
299
300 Imm = MO.getImm();
301 }
302
303 switch (OpInfo.OperandType) {
313 return getLit32Encoding(static_cast<uint32_t>(Imm), STI);
314
317 return getLit64Encoding(Desc, static_cast<uint64_t>(Imm), STI, false);
318
321 return getLit64Encoding(Desc, static_cast<uint64_t>(Imm), STI, true);
322
324 auto Enc = getLit64Encoding(Desc, static_cast<uint64_t>(Imm), STI, true);
325 return (HasMandatoryLiteral && Enc == 255) ? 254 : Enc;
326 }
327
330 return getLit16IntEncoding(static_cast<uint32_t>(Imm), STI);
331
334 // FIXME Is this correct? What do inline immediates do on SI for f16 src
335 // which does not have f16 support?
336 return getLit16Encoding(static_cast<uint16_t>(Imm), STI);
337
340 // We don't actually need to check Inv2Pi here because BF16 instructions can
341 // only be emitted for targets that already support the feature.
342 return getLitBF16Encoding(static_cast<uint16_t>(Imm));
343
346 return AMDGPU::getInlineEncodingV2I16(static_cast<uint32_t>(Imm))
347 .value_or(255);
348
351 return AMDGPU::getInlineEncodingV2F16(static_cast<uint32_t>(Imm))
352 .value_or(255);
353
355 // V_PK_FMAC_F16 has different inline constant behavior on pre-GFX11 vs
356 // GFX11+: pre-GFX11 produces (f16, 0), GFX11+ duplicates f16 to both
357 // halves.
358 return AMDGPU::getPKFMACF16InlineEncoding(static_cast<uint32_t>(Imm),
360 .value_or(255);
361
364 return AMDGPU::getInlineEncodingV2BF16(static_cast<uint32_t>(Imm))
365 .value_or(255);
366
368 return 255;
369
373 return Imm;
374 default:
375 llvm_unreachable("invalid operand size");
376 }
377}
378
379uint64_t AMDGPUMCCodeEmitter::getImplicitOpSelHiEncoding(int Opcode) const {
380 using namespace AMDGPU::VOP3PEncoding;
381
382 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::op_sel_hi)) {
383 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src2))
384 return 0;
385 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src1))
386 return OP_SEL_HI_2;
387 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src0))
388 return OP_SEL_HI_1 | OP_SEL_HI_2;
389 }
391}
392
393void AMDGPUMCCodeEmitter::encodeInstruction(const MCInst &MI,
394 SmallVectorImpl<char> &CB,
395 SmallVectorImpl<MCFixup> &Fixups,
396 const MCSubtargetInfo &STI) const {
397 int Opcode = MI.getOpcode();
398 APInt Encoding, Scratch;
399 getBinaryCodeForInstr(MI, Fixups, Encoding, Scratch, STI);
400 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
401 unsigned bytes = Desc.getSize();
402
403 // Set unused op_sel_hi bits to 1 for VOP3P and MAI instructions.
404 // Note that accvgpr_read/write are MAI, have src0, but do not use op_sel.
405 if (((Desc.TSFlags & SIInstrFlags::VOP3P) ||
406 Opcode == AMDGPU::V_ACCVGPR_READ_B32_vi ||
407 Opcode == AMDGPU::V_ACCVGPR_WRITE_B32_vi) &&
408 // Matrix B format operand reuses op_sel_hi.
409 !AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::matrix_b_fmt) &&
410 // Matrix B scale operand reuses op_sel_hi.
411 !AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::matrix_b_scale) &&
412 // Matrix B reuse operand reuses op_sel_hi.
413 !AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::matrix_b_reuse)) {
414 Encoding |= getImplicitOpSelHiEncoding(Opcode);
415 }
416
417 for (unsigned i = 0; i < bytes; i++) {
418 CB.push_back((uint8_t)Encoding.extractBitsAsZExtValue(8, 8 * i));
419 }
420
421 // NSA encoding.
422 if (AMDGPU::isGFX10Plus(STI) && Desc.TSFlags & SIInstrFlags::MIMG) {
423 int vaddr0 = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
424 AMDGPU::OpName::vaddr0);
425 int srsrc = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
426 AMDGPU::OpName::srsrc);
427 assert(vaddr0 >= 0 && srsrc > vaddr0);
428 unsigned NumExtraAddrs = srsrc - vaddr0 - 1;
429 unsigned NumPadding = (-NumExtraAddrs) & 3;
430
431 for (unsigned i = 0; i < NumExtraAddrs; ++i) {
432 getMachineOpValue(MI, MI.getOperand(vaddr0 + 1 + i), Encoding, Fixups,
433 STI);
434 CB.push_back((uint8_t)Encoding.getLimitedValue());
435 }
436 CB.append(NumPadding, 0);
437 }
438
439 if ((bytes > 8 && STI.hasFeature(AMDGPU::FeatureVOP3Literal)) ||
440 (bytes > 4 && !STI.hasFeature(AMDGPU::FeatureVOP3Literal)))
441 return;
442
443 // Do not print literals from SISrc Operands for insts with mandatory literals
444 if (AMDGPU::hasNamedOperand(MI.getOpcode(), AMDGPU::OpName::imm))
445 return;
446
447 // Check for additional literals
448 for (unsigned i = 0, e = Desc.getNumOperands(); i < e; ++i) {
449
450 // Check if this operand should be encoded as [SV]Src
452 continue;
453
454 // Is this operand a literal immediate?
455 const MCOperand &Op = MI.getOperand(i);
456 auto Enc = getLitEncoding(Desc, Op, i, STI);
457 if (!Enc || (*Enc != 255 && *Enc != 254))
458 continue;
459
460 // Yes! Encode it
461 int64_t Imm = 0;
462
463 bool IsLit = false;
464 if (Op.isImm())
465 Imm = Op.getImm();
466 else if (Op.isExpr()) {
467 if (const auto *C = dyn_cast<MCConstantExpr>(Op.getExpr())) {
468 Imm = C->getValue();
469 } else if (AMDGPU::isLitExpr(Op.getExpr())) {
470 IsLit = true;
471 Imm = AMDGPU::getLitValue(Op.getExpr());
472 }
473 } else // Exprs will be replaced with a fixup value.
474 llvm_unreachable("Must be immediate or expr");
475
476 if (*Enc == 254) {
477 assert(STI.hasFeature(AMDGPU::Feature64BitLiterals));
479 } else {
480 auto OpType =
481 static_cast<AMDGPU::OperandType>(Desc.operands()[i].OperandType);
482 Imm = AMDGPU::encode32BitLiteral(Imm, OpType, IsLit);
484 }
485
486 // Only one literal value allowed
487 break;
488 }
489}
490
491void AMDGPUMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
492 APInt &Op,
493 SmallVectorImpl<MCFixup> &Fixups,
494 const MCSubtargetInfo &STI) const {
495 const MCOperand &MO = MI.getOperand(OpNo);
496
497 if (MO.isExpr()) {
498 const MCExpr *Expr = MO.getExpr();
499 addFixup(Fixups, 0, Expr, AMDGPU::fixup_si_sopp_br, true);
500 Op = APInt::getZero(96);
501 } else {
502 getMachineOpValue(MI, MO, Op, Fixups, STI);
503 }
504}
505
506void AMDGPUMCCodeEmitter::getSMEMOffsetEncoding(
507 const MCInst &MI, unsigned OpNo, APInt &Op,
508 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
509 auto Offset = MI.getOperand(OpNo).getImm();
510 // VI only supports 20-bit unsigned offsets.
512 Op = Offset;
513}
514
515void AMDGPUMCCodeEmitter::getSDWASrcEncoding(const MCInst &MI, unsigned OpNo,
516 APInt &Op,
517 SmallVectorImpl<MCFixup> &Fixups,
518 const MCSubtargetInfo &STI) const {
519 using namespace AMDGPU::SDWA;
520
521 uint64_t RegEnc = 0;
522
523 const MCOperand &MO = MI.getOperand(OpNo);
524
525 if (MO.isReg()) {
526 MCRegister Reg = MO.getReg();
527 RegEnc |= MRI.getEncodingValue(Reg);
528 RegEnc &= SDWA9EncValues::SRC_VGPR_MASK;
530 RegEnc |= SDWA9EncValues::SRC_SGPR_MASK;
531 }
532 Op = RegEnc;
533 return;
534 } else {
535 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
536 auto Enc = getLitEncoding(Desc, MO, OpNo, STI);
537 if (Enc && *Enc != 255) {
538 Op = *Enc | SDWA9EncValues::SRC_SGPR_MASK;
539 return;
540 }
541 }
542
543 llvm_unreachable("Unsupported operand kind");
544}
545
546void AMDGPUMCCodeEmitter::getSDWAVopcDstEncoding(
547 const MCInst &MI, unsigned OpNo, APInt &Op,
548 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
549 using namespace AMDGPU::SDWA;
550
551 uint64_t RegEnc = 0;
552
553 const MCOperand &MO = MI.getOperand(OpNo);
554
555 MCRegister Reg = MO.getReg();
556 if (Reg != AMDGPU::VCC && Reg != AMDGPU::VCC_LO) {
557 RegEnc |= MRI.getEncodingValue(Reg);
558 RegEnc &= SDWA9EncValues::VOPC_DST_SGPR_MASK;
559 RegEnc |= SDWA9EncValues::VOPC_DST_VCC_MASK;
560 }
561 Op = RegEnc;
562}
563
564void AMDGPUMCCodeEmitter::getAVOperandEncoding(
565 const MCInst &MI, unsigned OpNo, APInt &Op,
566 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
567 MCRegister Reg = MI.getOperand(OpNo).getReg();
568 unsigned Enc = MRI.getEncodingValue(Reg);
569 unsigned Idx = Enc & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
570 bool IsVGPROrAGPR =
572
573 // VGPR and AGPR have the same encoding, but SrcA and SrcB operands of mfma
574 // instructions use acc[0:1] modifier bits to distinguish. These bits are
575 // encoded as a virtual 9th bit of the register for these operands.
576 bool IsAGPR = Enc & AMDGPU::HWEncoding::IS_AGPR;
577
578 Op = Idx | (IsVGPROrAGPR << 8) | (IsAGPR << 9);
579}
580
581static bool needsPCRel(const MCExpr *Expr) {
582 switch (Expr->getKind()) {
583 case MCExpr::SymbolRef: {
584 auto *SE = cast<MCSymbolRefExpr>(Expr);
585 auto Spec = AMDGPU::getSpecifier(SE);
586 return Spec != AMDGPUMCExpr::S_ABS32_LO &&
588 }
589 case MCExpr::Binary: {
590 auto *BE = cast<MCBinaryExpr>(Expr);
591 if (BE->getOpcode() == MCBinaryExpr::Sub)
592 return false;
593 return needsPCRel(BE->getLHS()) || needsPCRel(BE->getRHS());
594 }
595 case MCExpr::Unary:
596 return needsPCRel(cast<MCUnaryExpr>(Expr)->getSubExpr());
598 case MCExpr::Target:
599 case MCExpr::Constant:
600 return false;
601 }
602 llvm_unreachable("invalid kind");
603}
604
605void AMDGPUMCCodeEmitter::getMachineOpValue(const MCInst &MI,
606 const MCOperand &MO, APInt &Op,
607 SmallVectorImpl<MCFixup> &Fixups,
608 const MCSubtargetInfo &STI) const {
609 if (MO.isReg()){
610 unsigned Enc = MRI.getEncodingValue(MO.getReg());
611 unsigned Idx = Enc & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
612 bool IsVGPROrAGPR =
614 Op = Idx | (IsVGPROrAGPR << 8);
615 return;
616 }
617 unsigned OpNo = &MO - MI.begin();
618 getMachineOpValueCommon(MI, MO, OpNo, Op, Fixups, STI);
619}
620
621void AMDGPUMCCodeEmitter::getMachineOpValueT16(
622 const MCInst &MI, unsigned OpNo, APInt &Op,
623 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
624 const MCOperand &MO = MI.getOperand(OpNo);
625 if (MO.isReg()) {
626 unsigned Enc = MRI.getEncodingValue(MO.getReg());
627 unsigned Idx = Enc & AMDGPU::HWEncoding::REG_IDX_MASK;
628 bool IsVGPR = Enc & AMDGPU::HWEncoding::IS_VGPR;
629 Op = Idx | (IsVGPR << 8);
630 return;
631 }
632 getMachineOpValueCommon(MI, MO, OpNo, Op, Fixups, STI);
633 // VGPRs include the suffix/op_sel bit in the register encoding, but
634 // immediates and SGPRs include it in src_modifiers. Therefore, copy the
635 // op_sel bit from the src operands into src_modifier operands if Op is
636 // src_modifiers and the corresponding src is a VGPR
637 int SrcMOIdx = -1;
638 assert(OpNo < INT_MAX);
639 if ((int)OpNo == AMDGPU::getNamedOperandIdx(MI.getOpcode(),
640 AMDGPU::OpName::src0_modifiers)) {
641 SrcMOIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
642 int VDstMOIdx =
643 AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vdst);
644 if (VDstMOIdx != -1) {
645 auto DstReg = MI.getOperand(VDstMOIdx).getReg();
646 if (AMDGPU::isHi16Reg(DstReg, MRI))
648 }
649 } else if ((int)OpNo == AMDGPU::getNamedOperandIdx(
650 MI.getOpcode(), AMDGPU::OpName::src1_modifiers))
651 SrcMOIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src1);
652 else if ((int)OpNo == AMDGPU::getNamedOperandIdx(
653 MI.getOpcode(), AMDGPU::OpName::src2_modifiers))
654 SrcMOIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src2);
655 if (SrcMOIdx == -1)
656 return;
657
658 const MCOperand &SrcMO = MI.getOperand(SrcMOIdx);
659 if (!SrcMO.isReg())
660 return;
661 auto SrcReg = SrcMO.getReg();
662 if (AMDGPU::isSGPR(SrcReg, &MRI))
663 return;
664 if (AMDGPU::isHi16Reg(SrcReg, MRI))
666}
667
668void AMDGPUMCCodeEmitter::getMachineOpValueT16Lo128(
669 const MCInst &MI, unsigned OpNo, APInt &Op,
670 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
671 const MCOperand &MO = MI.getOperand(OpNo);
672 if (MO.isReg()) {
673 uint16_t Encoding = MRI.getEncodingValue(MO.getReg());
674 unsigned RegIdx = Encoding & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
675 bool IsHi = Encoding & AMDGPU::HWEncoding::IS_HI16;
676 bool IsVGPR = Encoding & AMDGPU::HWEncoding::IS_VGPR;
677 assert((!IsVGPR || isUInt<7>(RegIdx)) && "VGPR0-VGPR127 expected!");
678 Op = (IsVGPR ? 0x100 : 0) | (IsHi ? 0x80 : 0) | RegIdx;
679 return;
680 }
681 getMachineOpValueCommon(MI, MO, OpNo, Op, Fixups, STI);
682}
683
684void AMDGPUMCCodeEmitter::getMachineOpValueCommon(
685 const MCInst &MI, const MCOperand &MO, unsigned OpNo, APInt &Op,
686 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
687 bool isLikeImm = false;
688 int64_t Val;
689
690 if (MO.isImm()) {
691 Val = MO.getImm();
692 isLikeImm = true;
693 } else if (MO.isExpr() && MO.getExpr()->evaluateAsAbsolute(Val)) {
694 isLikeImm = true;
695 } else if (MO.isExpr()) {
696 // FIXME: If this is expression is PCRel or not should not depend on what
697 // the expression looks like. Given that this is just a general expression,
698 // it should probably be FK_Data_4 and whatever is producing
699 //
700 // s_add_u32 s2, s2, (extern_const_addrspace+16
701 //
702 // And expecting a PCRel should instead produce
703 //
704 // .Ltmp1:
705 // s_add_u32 s2, s2, (extern_const_addrspace+16)-.Ltmp1
706 bool PCRel = needsPCRel(MO.getExpr());
707 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
708 uint32_t Offset = Desc.getSize();
709 assert(Offset == 4 || Offset == 8);
710 unsigned Size = AMDGPU::getOperandSize(Desc, OpNo);
712 addFixup(Fixups, Offset, MO.getExpr(), Kind, PCRel);
713 }
714
715 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
716 if (AMDGPU::isSISrcOperand(Desc, OpNo)) {
717 bool HasMandatoryLiteral =
718 AMDGPU::hasNamedOperand(MI.getOpcode(), AMDGPU::OpName::imm);
719 if (auto Enc = getLitEncoding(Desc, MO, OpNo, STI, HasMandatoryLiteral)) {
720 Op = *Enc;
721 return;
722 }
723
724 llvm_unreachable("Operand not supported for SISrc");
725 }
726
727 if (isLikeImm) {
728 Op = Val;
729 return;
730 }
731
732 llvm_unreachable("Encoding of this operand type is not supported yet.");
733}
734
735template <bool HasSrc0, bool HasSrc1, bool HasSrc2>
736APInt AMDGPUMCCodeEmitter::postEncodeVOP3(const MCInst &MI, APInt EncodedValue,
737 const MCSubtargetInfo &STI) const {
738 if (!AMDGPU::isGFX10Plus(STI))
739 return EncodedValue;
740 // Set unused source fields in VOP3 encodings to inline immediate 0 to avoid
741 // hardware conservatively assuming the instruction reads SGPRs.
742 constexpr uint64_t InlineImmediate0 = 0x80;
743 if (!HasSrc0)
744 EncodedValue |= InlineImmediate0 << 32;
745 if (!HasSrc1)
746 EncodedValue |= InlineImmediate0 << 41;
747 if (!HasSrc2)
748 EncodedValue |= InlineImmediate0 << 50;
749 return EncodedValue;
750}
751
752APInt AMDGPUMCCodeEmitter::postEncodeVOPCX(const MCInst &MI, APInt EncodedValue,
753 const MCSubtargetInfo &STI) const {
754 // GFX10+ v_cmpx opcodes promoted to VOP3 have implied dst=EXEC.
755 // Documentation requires dst to be encoded as EXEC (0x7E),
756 // but it looks like the actual value encoded for dst operand
757 // is ignored by HW. It was decided to define dst as "do not care"
758 // in td files to allow disassembler accept any dst value.
759 // However, dst is encoded as EXEC for compatibility with SP3.
760 [[maybe_unused]] const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
761 assert((Desc.TSFlags & SIInstrFlags::VOP3) &&
762 Desc.hasImplicitDefOfPhysReg(AMDGPU::EXEC));
763 EncodedValue |= MRI.getEncodingValue(AMDGPU::EXEC_LO) &
765 return postEncodeVOP3<true, true, false>(MI, EncodedValue, STI);
766}
767
768#include "AMDGPUGenMCCodeEmitter.inc"
static void addFixup(SmallVectorImpl< MCFixup > &Fixups, uint32_t Offset, const MCExpr *Value, uint16_t Kind, bool PCRel=false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static uint32_t getLit64Encoding(const MCInstrDesc &Desc, uint64_t Val, const MCSubtargetInfo &STI, bool IsFP)
static uint32_t getLit16IntEncoding(uint32_t Val, const MCSubtargetInfo &STI)
static void addFixup(SmallVectorImpl< MCFixup > &Fixups, uint32_t Offset, const MCExpr *Value, uint16_t Kind, bool PCRel=false)
static uint32_t getLitBF16Encoding(uint16_t Val)
static uint32_t getLit16Encoding(uint16_t Val, const MCSubtargetInfo &STI)
static uint32_t getIntInlineImmEncoding(IntTy Imm)
static bool needsPCRel(const MCExpr *Expr)
static uint32_t getLit32Encoding(uint32_t Val, const MCSubtargetInfo &STI)
Provides AMDGPU specific target descriptions.
This file implements a class to represent arbitrary precision integral constant values and operations...
IRTranslator LLVM IR MI
Register Reg
LLVM_ABI uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const
Definition APInt.cpp:521
uint64_t getLimitedValue(uint64_t Limit=UINT64_MAX) const
If this value is smaller than the specified limit, return it, otherwise return the limit value.
Definition APInt.h:476
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:201
@ Sub
Subtraction.
Definition MCExpr.h:324
MCCodeEmitter - Generic instruction encoding interface.
Context object for machine code objects.
Definition MCContext.h:83
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
@ Unary
Unary expressions.
Definition MCExpr.h:44
@ Constant
Constant expressions.
Definition MCExpr.h:42
@ SymbolRef
References to labels and assigned expressions.
Definition MCExpr.h:43
@ Target
Target specific expression.
Definition MCExpr.h:46
@ Specifier
Expression with a relocation specifier.
Definition MCExpr.h:45
@ Binary
Binary expressions.
Definition MCExpr.h:41
ExprKind getKind() const
Definition MCExpr.h:85
static MCFixupKind getDataKindForSize(unsigned Size)
Return the generic fixup kind for a value with the given size.
Definition MCFixup.h:110
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, bool PCRel=false)
Consider bit fields if we need more flags.
Definition MCFixup.h:86
Describe properties that are true of each instruction in the target description file.
Interface to description of machine instruction set.
Definition MCInstrInfo.h:27
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:90
uint8_t OperandType
Information about the type of the operand.
Definition MCInstrDesc.h:98
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
int64_t getImm() const
Definition MCInst.h:84
bool isImm() const
Definition MCInst.h:66
bool isReg() const
Definition MCInst.h:65
MCRegister getReg() const
Returns the register number.
Definition MCInst.h:73
bool isDFPImm() const
Definition MCInst.h:68
const MCExpr * getExpr() const
Definition MCInst.h:118
bool isExpr() const
Definition MCInst.h:69
uint16_t getEncodingValue(MCRegister Reg) const
Returns the encoding for Reg.
Generic base class for all target subtargets.
bool hasFeature(unsigned Feature) const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool isSGPR(MCRegister Reg, const MCRegisterInfo *TRI)
Is Reg - scalar register.
bool isHi16Reg(MCRegister Reg, const MCRegisterInfo &MRI)
static AMDGPUMCExpr::Specifier getSpecifier(const MCSymbolRefExpr *SRE)
LLVM_READONLY bool isLitExpr(const MCExpr *Expr)
@ fixup_si_sopp_br
16-bit PC relative fixup for SOPP branch instructions.
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
constexpr bool isSISrcOperand(const MCOperandInfo &OpInfo)
Is this an AMDGPU specific source operand?
LLVM_READONLY AMDGPUMCExpr::VariantKind getExprKind(const MCExpr *Expr)
LLVM_READONLY int64_t getLitValue(const MCExpr *Expr)
bool isGFX11Plus(const MCSubtargetInfo &STI)
std::optional< unsigned > getInlineEncodingV2F16(uint32_t Literal)
bool isGFX10Plus(const MCSubtargetInfo &STI)
int64_t encode32BitLiteral(int64_t Imm, OperandType Type, bool IsLit)
@ OPERAND_KIMM32
Operand with 32-bit immediate that uses the constant bus.
Definition SIDefines.h:234
@ OPERAND_REG_IMM_INT64
Definition SIDefines.h:204
@ OPERAND_REG_IMM_V2FP16
Definition SIDefines.h:211
@ OPERAND_REG_INLINE_C_FP64
Definition SIDefines.h:225
@ OPERAND_REG_INLINE_C_BF16
Definition SIDefines.h:222
@ OPERAND_REG_INLINE_C_V2BF16
Definition SIDefines.h:227
@ OPERAND_REG_IMM_V2INT16
Definition SIDefines.h:213
@ OPERAND_REG_IMM_BF16
Definition SIDefines.h:208
@ OPERAND_REG_IMM_INT32
Operands with register, 32-bit, or 64-bit immediate.
Definition SIDefines.h:203
@ OPERAND_REG_IMM_V2BF16
Definition SIDefines.h:210
@ OPERAND_REG_IMM_FP16
Definition SIDefines.h:209
@ OPERAND_REG_IMM_V2FP16_SPLAT
Definition SIDefines.h:212
@ OPERAND_REG_INLINE_C_INT64
Definition SIDefines.h:221
@ OPERAND_REG_INLINE_C_INT16
Operands with register or inline constant.
Definition SIDefines.h:219
@ OPERAND_REG_IMM_NOINLINE_V2FP16
Definition SIDefines.h:214
@ OPERAND_REG_IMM_FP64
Definition SIDefines.h:207
@ OPERAND_REG_INLINE_C_V2FP16
Definition SIDefines.h:228
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
Definition SIDefines.h:239
@ OPERAND_REG_INLINE_AC_FP32
Definition SIDefines.h:240
@ OPERAND_REG_IMM_V2INT32
Definition SIDefines.h:215
@ OPERAND_REG_IMM_FP32
Definition SIDefines.h:206
@ OPERAND_REG_INLINE_C_FP32
Definition SIDefines.h:224
@ OPERAND_REG_INLINE_C_INT32
Definition SIDefines.h:220
@ OPERAND_REG_INLINE_C_V2INT16
Definition SIDefines.h:226
@ OPERAND_REG_IMM_V2FP32
Definition SIDefines.h:216
@ OPERAND_REG_INLINE_AC_FP64
Definition SIDefines.h:241
@ OPERAND_REG_INLINE_C_FP16
Definition SIDefines.h:223
@ OPERAND_REG_IMM_INT16
Definition SIDefines.h:205
@ OPERAND_INLINE_SPLIT_BARRIER_INT32
Definition SIDefines.h:231
std::optional< unsigned > getPKFMACF16InlineEncoding(uint32_t Literal, bool IsGFX11Plus)
std::optional< unsigned > getInlineEncodingV2I16(uint32_t Literal)
bool isVI(const MCSubtargetInfo &STI)
MCRegister mc2PseudoReg(MCRegister Reg)
Convert hardware register Reg to a pseudo register.
std::optional< unsigned > getInlineEncodingV2BF16(uint32_t Literal)
LLVM_READNONE unsigned getOperandSize(const MCOperandInfo &OpInfo)
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:96
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:557
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:165
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
Op::Description Desc
uint16_t MCFixupKind
Extensible enumeration to represent the type of a fixup.
Definition MCFixup.h:22
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:189
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
Definition MathExtras.h:155
To bit_cast(const From &from) noexcept
Definition bit.h:90
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
MCCodeEmitter * createAMDGPUMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)