LLVM 24.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 void getMachineOpValueRsrcRegOp(const MCInst &MI, unsigned OpNo, APInt &Op,
61 SmallVectorImpl<MCFixup> &Fixups,
62 const MCSubtargetInfo &STI) const;
63
64 /// Use a fixup to encode the simm16 field for SOPP branch
65 /// instructions.
66 void getSOPPBrEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
67 SmallVectorImpl<MCFixup> &Fixups,
68 const MCSubtargetInfo &STI) const;
69
70 void getSMEMOffsetEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
71 SmallVectorImpl<MCFixup> &Fixups,
72 const MCSubtargetInfo &STI) const;
73
74 void getSDWASrcEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
75 SmallVectorImpl<MCFixup> &Fixups,
76 const MCSubtargetInfo &STI) const;
77
78 void getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
79 SmallVectorImpl<MCFixup> &Fixups,
80 const MCSubtargetInfo &STI) const;
81
82 void getAVOperandEncoding(const MCInst &MI, unsigned OpNo, APInt &Op,
83 SmallVectorImpl<MCFixup> &Fixups,
84 const MCSubtargetInfo &STI) const;
85
86private:
87 uint64_t getImplicitOpSelHiEncoding(int Opcode) const;
88 void getMachineOpValueCommon(const MCInst &MI, const MCOperand &MO,
89 unsigned OpNo, APInt &Op,
90 SmallVectorImpl<MCFixup> &Fixups,
91 const MCSubtargetInfo &STI) const;
92
93 /// Encode an fp or int literal.
94 std::optional<uint64_t>
95 getLitEncoding(const MCInstrDesc &Desc, const MCOperand &MO, unsigned OpNo,
96 const MCSubtargetInfo &STI,
97 bool HasMandatoryLiteral = false) const;
98
99 void getBinaryCodeForInstr(const MCInst &MI, SmallVectorImpl<MCFixup> &Fixups,
100 APInt &Inst, APInt &Scratch,
101 const MCSubtargetInfo &STI) const;
102
103 template <bool HasSrc0, bool HasSrc1, bool HasSrc2>
104 APInt postEncodeVOP3(const MCInst &MI, APInt EncodedValue,
105 const MCSubtargetInfo &STI) const;
106
107 APInt postEncodeVOPCX(const MCInst &MI, APInt EncodedValue,
108 const MCSubtargetInfo &STI) const;
109};
110
111} // end anonymous namespace
112
114 MCContext &Ctx) {
115 return new AMDGPUMCCodeEmitter(MCII, *Ctx.getRegisterInfo());
116}
117
119 const MCExpr *Value, uint16_t Kind, bool PCRel = false) {
120 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));
121}
122
123// Returns the encoding value to use if the given integer is an integer inline
124// immediate value, or 0 if it is not.
125template <typename IntTy>
127 if (Imm >= 0 && Imm <= 64)
128 return 128 + Imm;
129
130 if (Imm >= -16 && Imm <= -1)
131 return 192 + std::abs(Imm);
132
133 return 0;
134}
135
137 uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
138 if (IntImm != 0)
139 return IntImm;
140
141 if (Val == 0x3800) // 0.5
142 return 240;
143
144 if (Val == 0xB800) // -0.5
145 return 241;
146
147 if (Val == 0x3C00) // 1.0
148 return 242;
149
150 if (Val == 0xBC00) // -1.0
151 return 243;
152
153 if (Val == 0x4000) // 2.0
154 return 244;
155
156 if (Val == 0xC000) // -2.0
157 return 245;
158
159 if (Val == 0x4400) // 4.0
160 return 246;
161
162 if (Val == 0xC400) // -4.0
163 return 247;
164
165 if (Val == 0x3118 && // 1.0 / (2.0 * pi)
166 STI.hasFeature(AMDGPU::FeatureInv2PiInlineImm))
167 return 248;
168
169 return 255;
170}
171
173 uint16_t IntImm = getIntInlineImmEncoding(static_cast<int16_t>(Val));
174 if (IntImm != 0)
175 return IntImm;
176
177 // clang-format off
178 switch (Val) {
179 case 0x3F00: return 240; // 0.5
180 case 0xBF00: return 241; // -0.5
181 case 0x3F80: return 242; // 1.0
182 case 0xBF80: return 243; // -1.0
183 case 0x4000: return 244; // 2.0
184 case 0xC000: return 245; // -2.0
185 case 0x4080: return 246; // 4.0
186 case 0xC080: return 247; // -4.0
187 case 0x3E22: return 248; // 1.0 / (2.0 * pi)
188 default: return 255;
189 }
190 // clang-format on
191}
192
194 uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
195 if (IntImm != 0)
196 return IntImm;
197
198 if (Val == llvm::bit_cast<uint32_t>(0.5f))
199 return 240;
200
201 if (Val == llvm::bit_cast<uint32_t>(-0.5f))
202 return 241;
203
204 if (Val == llvm::bit_cast<uint32_t>(1.0f))
205 return 242;
206
207 if (Val == llvm::bit_cast<uint32_t>(-1.0f))
208 return 243;
209
210 if (Val == llvm::bit_cast<uint32_t>(2.0f))
211 return 244;
212
213 if (Val == llvm::bit_cast<uint32_t>(-2.0f))
214 return 245;
215
216 if (Val == llvm::bit_cast<uint32_t>(4.0f))
217 return 246;
218
219 if (Val == llvm::bit_cast<uint32_t>(-4.0f))
220 return 247;
221
222 if (Val == 0x3e22f983 && // 1.0 / (2.0 * pi)
223 STI.hasFeature(AMDGPU::FeatureInv2PiInlineImm))
224 return 248;
225
226 return 255;
227}
228
230 return getLit32Encoding(Val, STI);
231}
232
234 const MCSubtargetInfo &STI, bool IsFP) {
235 uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
236 if (IntImm != 0)
237 return IntImm;
238
239 if (Val == llvm::bit_cast<uint64_t>(0.5))
240 return 240;
241
242 if (Val == llvm::bit_cast<uint64_t>(-0.5))
243 return 241;
244
245 if (Val == llvm::bit_cast<uint64_t>(1.0))
246 return 242;
247
248 if (Val == llvm::bit_cast<uint64_t>(-1.0))
249 return 243;
250
251 if (Val == llvm::bit_cast<uint64_t>(2.0))
252 return 244;
253
254 if (Val == llvm::bit_cast<uint64_t>(-2.0))
255 return 245;
256
257 if (Val == llvm::bit_cast<uint64_t>(4.0))
258 return 246;
259
260 if (Val == llvm::bit_cast<uint64_t>(-4.0))
261 return 247;
262
263 if (Val == 0x3fc45f306dc9c882 && // 1.0 / (2.0 * pi)
264 STI.hasFeature(AMDGPU::FeatureInv2PiInlineImm))
265 return 248;
266
267 // The rest part needs to align with AMDGPUInstPrinter::printLiteral64.
268
269 bool CanUse64BitLiterals = STI.hasFeature(AMDGPU::Feature64BitLiterals) &&
271 if (IsFP) {
272 return CanUse64BitLiterals && Lo_32(Val) ? 254 : 255;
273 }
274
275 return CanUse64BitLiterals && (!isInt<32>(Val) || !isUInt<32>(Val)) ? 254
276 : 255;
277}
278
279std::optional<uint64_t> AMDGPUMCCodeEmitter::getLitEncoding(
280 const MCInstrDesc &Desc, const MCOperand &MO, unsigned OpNo,
281 const MCSubtargetInfo &STI, bool HasMandatoryLiteral) const {
282 const MCOperandInfo &OpInfo = Desc.operands()[OpNo];
283 int64_t Imm = 0;
284 if (MO.isExpr()) {
285 if (!MO.getExpr()->evaluateAsAbsolute(Imm) ||
287 if (OpInfo.OperandType == AMDGPU::OPERAND_KIMM16 ||
290 return Imm;
291 if (STI.hasFeature(AMDGPU::Feature64BitLiterals) &&
292 AMDGPU::getOperandSize(OpInfo) == 8 &&
294 return 254;
295 return 255;
296 }
297 } else {
298 assert(!MO.isDFPImm());
299
300 if (!MO.isImm())
301 return {};
302
303 Imm = MO.getImm();
304 }
305
306 switch (OpInfo.OperandType) {
316 return getLit32Encoding(static_cast<uint32_t>(Imm), STI);
317
321 return getLit64Encoding(Desc, static_cast<uint64_t>(Imm), STI, false);
322
325 return getLit64Encoding(Desc, static_cast<uint64_t>(Imm), STI, true);
326
329 auto Enc = getLit64Encoding(Desc, static_cast<uint64_t>(Imm), STI, true);
330 return (HasMandatoryLiteral && Enc == 255) ? 254 : Enc;
331 }
332
335 return getLit16IntEncoding(static_cast<uint32_t>(Imm), STI);
336
339 // FIXME Is this correct? What do inline immediates do on SI for f16 src
340 // which does not have f16 support?
341 return getLit16Encoding(static_cast<uint16_t>(Imm), STI);
342
344 return 255;
345
348 // We don't actually need to check Inv2Pi here because BF16 instructions can
349 // only be emitted for targets that already support the feature.
350 return getLitBF16Encoding(static_cast<uint16_t>(Imm));
351
354 return AMDGPU::getInlineEncodingV2I16(static_cast<uint32_t>(Imm))
355 .value_or(255);
356
359 return AMDGPU::getInlineEncodingV2F16(static_cast<uint32_t>(Imm))
360 .value_or(255);
361
363 // V_PK_FMAC_F16 has different inline constant behavior on pre-GFX11 vs
364 // GFX11+: pre-GFX11 produces (f16, 0), GFX11+ duplicates f16 to both
365 // halves.
366 return AMDGPU::getPKFMACF16InlineEncoding(static_cast<uint32_t>(Imm),
368 .value_or(255);
369
372 return AMDGPU::getInlineEncodingV2BF16(static_cast<uint32_t>(Imm))
373 .value_or(255);
374
376 return 255;
377
381 return Imm;
382 default:
383 llvm_unreachable("invalid operand size");
384 }
385}
386
387uint64_t AMDGPUMCCodeEmitter::getImplicitOpSelHiEncoding(int Opcode) const {
388 using namespace AMDGPU::VOP3PEncoding;
389
390 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::op_sel_hi)) {
391 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src2))
392 return 0;
393 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src1))
394 return OP_SEL_HI_2;
395 if (AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::src0))
396 return OP_SEL_HI_1 | OP_SEL_HI_2;
397 }
399}
400
401void AMDGPUMCCodeEmitter::encodeInstruction(const MCInst &MI,
402 SmallVectorImpl<char> &CB,
403 SmallVectorImpl<MCFixup> &Fixups,
404 const MCSubtargetInfo &STI) const {
405 int Opcode = MI.getOpcode();
406 APInt Encoding, Scratch;
407 getBinaryCodeForInstr(MI, Fixups, Encoding, Scratch, STI);
408 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
409 unsigned bytes = Desc.getSize();
410
411 // Set unused op_sel_hi bits to 1 for VOP3P and MAI instructions.
412 // Note that accvgpr_read/write are MAI, have src0, but do not use op_sel.
413 if ((SIInstrFlags::isVOP3P(Desc) || Opcode == AMDGPU::V_ACCVGPR_READ_B32_vi ||
414 Opcode == AMDGPU::V_ACCVGPR_WRITE_B32_vi) &&
415 // Matrix B format operand reuses op_sel_hi.
416 !AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::matrix_b_fmt) &&
417 // Matrix B scale operand reuses op_sel_hi.
418 !AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::matrix_b_scale) &&
419 // Matrix B reuse operand reuses op_sel_hi.
420 !AMDGPU::hasNamedOperand(Opcode, AMDGPU::OpName::matrix_b_reuse)) {
421 Encoding |= getImplicitOpSelHiEncoding(Opcode);
422 }
423
424 for (unsigned i = 0; i < bytes; i++) {
425 CB.push_back((uint8_t)Encoding.extractBitsAsZExtValue(8, 8 * i));
426 }
427
428 // NSA encoding.
430 int vaddr0 = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
431 AMDGPU::OpName::vaddr0);
432 int srsrc = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
433 AMDGPU::OpName::srsrc);
434 assert(vaddr0 >= 0 && srsrc > vaddr0);
435 unsigned NumExtraAddrs = srsrc - vaddr0 - 1;
436 unsigned NumPadding = (-NumExtraAddrs) & 3;
437
438 for (unsigned i = 0; i < NumExtraAddrs; ++i) {
439 getMachineOpValue(MI, MI.getOperand(vaddr0 + 1 + i), Encoding, Fixups,
440 STI);
441 CB.push_back((uint8_t)Encoding.getLimitedValue());
442 }
443 CB.append(NumPadding, 0);
444 }
445
446 if ((bytes > 8 && STI.hasFeature(AMDGPU::FeatureVOP3Literal)) ||
447 (bytes > 4 && !STI.hasFeature(AMDGPU::FeatureVOP3Literal)))
448 return;
449
450 // Do not print literals from SISrc Operands for insts with mandatory literals
451 if (AMDGPU::hasNamedOperand(MI.getOpcode(), AMDGPU::OpName::imm))
452 return;
453
454 // Check for additional literals
455 for (unsigned i = 0, e = Desc.getNumOperands(); i < e; ++i) {
456
457 // Check if this operand should be encoded as [SV]Src
459 continue;
460
461 // Is this operand a literal immediate?
462 const MCOperand &Op = MI.getOperand(i);
463 auto Enc = getLitEncoding(Desc, Op, i, STI);
464 if (!Enc || (*Enc != 255 && *Enc != 254))
465 continue;
466
467 // Yes! Encode it
468 int64_t Imm = 0;
469
470 bool IsLit = false;
471 if (Op.isImm())
472 Imm = Op.getImm();
473 else if (Op.isExpr()) {
474 if (const auto *C = dyn_cast<MCConstantExpr>(Op.getExpr())) {
475 Imm = C->getValue();
476 } else if (AMDGPU::isLitExpr(Op.getExpr())) {
477 IsLit = true;
478 Imm = AMDGPU::getLitValue(Op.getExpr());
479 }
480 } else // Exprs will be replaced with a fixup value.
481 llvm_unreachable("Must be immediate or expr");
482
483 if (*Enc == 254) {
484 assert(STI.hasFeature(AMDGPU::Feature64BitLiterals));
486 } else {
487 auto OpType =
488 static_cast<AMDGPU::OperandType>(Desc.operands()[i].OperandType);
489 Imm = AMDGPU::encode32BitLiteral(Imm, OpType, IsLit);
491 }
492
493 // Only one literal value allowed
494 break;
495 }
496}
497
498void AMDGPUMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
499 APInt &Op,
500 SmallVectorImpl<MCFixup> &Fixups,
501 const MCSubtargetInfo &STI) const {
502 const MCOperand &MO = MI.getOperand(OpNo);
503
504 if (MO.isExpr()) {
505 const MCExpr *Expr = MO.getExpr();
506 addFixup(Fixups, 0, Expr, AMDGPU::fixup_si_sopp_br, true);
507 Op = APInt::getZero(96);
508 } else {
509 getMachineOpValue(MI, MO, Op, Fixups, STI);
510 }
511}
512
513void AMDGPUMCCodeEmitter::getSMEMOffsetEncoding(
514 const MCInst &MI, unsigned OpNo, APInt &Op,
515 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
516 auto Offset = MI.getOperand(OpNo).getImm();
517 // VI only supports 20-bit unsigned offsets.
519 Op = Offset;
520}
521
522void AMDGPUMCCodeEmitter::getSDWASrcEncoding(const MCInst &MI, unsigned OpNo,
523 APInt &Op,
524 SmallVectorImpl<MCFixup> &Fixups,
525 const MCSubtargetInfo &STI) const {
526 using namespace AMDGPU::SDWA;
527
528 uint64_t RegEnc = 0;
529
530 const MCOperand &MO = MI.getOperand(OpNo);
531
532 if (MO.isReg()) {
533 MCRegister Reg = MO.getReg();
534 RegEnc |= MRI.getEncodingValue(Reg);
535 RegEnc &= SDWA9EncValues::SRC_VGPR_MASK;
537 RegEnc |= SDWA9EncValues::SRC_SGPR_MASK;
538 }
539 Op = RegEnc;
540 return;
541 } else {
542 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
543 auto Enc = getLitEncoding(Desc, MO, OpNo, STI);
544 if (Enc && *Enc != 255) {
545 Op = *Enc | SDWA9EncValues::SRC_SGPR_MASK;
546 return;
547 }
548 }
549
550 llvm_unreachable("Unsupported operand kind");
551}
552
553void AMDGPUMCCodeEmitter::getSDWAVopcDstEncoding(
554 const MCInst &MI, unsigned OpNo, APInt &Op,
555 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
556 using namespace AMDGPU::SDWA;
557
558 uint64_t RegEnc = 0;
559
560 const MCOperand &MO = MI.getOperand(OpNo);
561
562 MCRegister Reg = MO.getReg();
563 if (Reg != AMDGPU::VCC && Reg != AMDGPU::VCC_LO) {
564 RegEnc |= MRI.getEncodingValue(Reg);
565 RegEnc &= SDWA9EncValues::VOPC_DST_SGPR_MASK;
566 RegEnc |= SDWA9EncValues::VOPC_DST_VCC_MASK;
567 }
568 Op = RegEnc;
569}
570
571void AMDGPUMCCodeEmitter::getAVOperandEncoding(
572 const MCInst &MI, unsigned OpNo, APInt &Op,
573 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
574 MCRegister Reg = MI.getOperand(OpNo).getReg();
575 unsigned Enc = MRI.getEncodingValue(Reg);
576 unsigned Idx = Enc & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
577 bool IsVGPROrAGPR =
579
580 // VGPR and AGPR have the same encoding, but SrcA and SrcB operands of mfma
581 // instructions use acc[0:1] modifier bits to distinguish. These bits are
582 // encoded as a virtual 9th bit of the register for these operands.
583 bool IsAGPR = Enc & AMDGPU::HWEncoding::IS_AGPR;
584
585 Op = Idx | (IsVGPROrAGPR << 8) | (IsAGPR << 9);
586}
587
588static bool needsPCRel(const MCExpr *Expr) {
589 switch (Expr->getKind()) {
590 case MCExpr::SymbolRef: {
591 auto *SE = cast<MCSymbolRefExpr>(Expr);
592 auto Spec = AMDGPU::getSpecifier(SE);
593 return Spec != AMDGPUMCExpr::S_ABS32_LO &&
595 }
596 case MCExpr::Binary: {
597 auto *BE = cast<MCBinaryExpr>(Expr);
598 if (BE->getOpcode() == MCBinaryExpr::Sub)
599 return false;
600 return needsPCRel(BE->getLHS()) || needsPCRel(BE->getRHS());
601 }
602 case MCExpr::Unary:
603 return needsPCRel(cast<MCUnaryExpr>(Expr)->getSubExpr());
605 case MCExpr::Target:
606 case MCExpr::Constant:
607 return false;
608 }
609 llvm_unreachable("invalid kind");
610}
611
612void AMDGPUMCCodeEmitter::getMachineOpValue(const MCInst &MI,
613 const MCOperand &MO, APInt &Op,
614 SmallVectorImpl<MCFixup> &Fixups,
615 const MCSubtargetInfo &STI) const {
616 if (MO.isReg()){
617 unsigned Enc = MRI.getEncodingValue(MO.getReg());
618 unsigned Idx = Enc & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
619 bool IsVGPROrAGPR =
621 Op = Idx | (IsVGPROrAGPR << 8);
622 return;
623 }
624 unsigned OpNo = &MO - MI.begin();
625 getMachineOpValueCommon(MI, MO, OpNo, Op, Fixups, STI);
626}
627
628void AMDGPUMCCodeEmitter::getMachineOpValueT16(
629 const MCInst &MI, unsigned OpNo, APInt &Op,
630 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
631 const MCOperand &MO = MI.getOperand(OpNo);
632 if (MO.isReg()) {
633 unsigned Enc = MRI.getEncodingValue(MO.getReg());
634 unsigned Idx = Enc & AMDGPU::HWEncoding::REG_IDX_MASK;
635 bool IsVGPR = Enc & AMDGPU::HWEncoding::IS_VGPR;
636 Op = Idx | (IsVGPR << 8);
637 return;
638 }
639 getMachineOpValueCommon(MI, MO, OpNo, Op, Fixups, STI);
640 // VGPRs include the suffix/op_sel bit in the register encoding, but
641 // immediates and SGPRs include it in src_modifiers. Therefore, copy the
642 // op_sel bit from the src operands into src_modifier operands if Op is
643 // src_modifiers and the corresponding src is a VGPR
644 int SrcMOIdx = -1;
645 assert(OpNo < INT_MAX);
646 if ((int)OpNo == AMDGPU::getNamedOperandIdx(MI.getOpcode(),
647 AMDGPU::OpName::src0_modifiers)) {
648 SrcMOIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
649 int VDstMOIdx =
650 AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vdst);
651 if (VDstMOIdx != -1) {
652 auto DstReg = MI.getOperand(VDstMOIdx).getReg();
653 if (AMDGPU::isHi16Reg(DstReg, MRI))
655 }
656 } else if ((int)OpNo == AMDGPU::getNamedOperandIdx(
657 MI.getOpcode(), AMDGPU::OpName::src1_modifiers))
658 SrcMOIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src1);
659 else if ((int)OpNo == AMDGPU::getNamedOperandIdx(
660 MI.getOpcode(), AMDGPU::OpName::src2_modifiers))
661 SrcMOIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src2);
662 if (SrcMOIdx == -1)
663 return;
664
665 const MCOperand &SrcMO = MI.getOperand(SrcMOIdx);
666 if (!SrcMO.isReg())
667 return;
668 auto SrcReg = SrcMO.getReg();
669 if (AMDGPU::isSGPR(SrcReg, &MRI))
670 return;
671 if (AMDGPU::isHi16Reg(SrcReg, MRI))
673}
674
675void AMDGPUMCCodeEmitter::getMachineOpValueT16Lo128(
676 const MCInst &MI, unsigned OpNo, APInt &Op,
677 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
678 const MCOperand &MO = MI.getOperand(OpNo);
679 if (MO.isReg()) {
680 uint16_t Encoding = MRI.getEncodingValue(MO.getReg());
681 unsigned RegIdx = Encoding & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
682 bool IsHi = Encoding & AMDGPU::HWEncoding::IS_HI16;
683 bool IsVGPR = Encoding & AMDGPU::HWEncoding::IS_VGPR;
684 assert((!IsVGPR || isUInt<7>(RegIdx)) && "VGPR0-VGPR127 expected!");
685 Op = (IsVGPR ? 0x100 : 0) | (IsHi ? 0x80 : 0) | RegIdx;
686 return;
687 }
688 getMachineOpValueCommon(MI, MO, OpNo, Op, Fixups, STI);
689}
690
691// Encode an indexed-resource (rsrcidx) operand into the 9-bit srsrc field:
692// bit 8 selects a VGPR (or AGPR) index register, bit 7 selects a 32-bit SGPR
693// index register, and bits 6-0 hold the register index.
694void AMDGPUMCCodeEmitter::getMachineOpValueRsrcRegOp(
695 const MCInst &MI, unsigned OpNo, APInt &Op,
696 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
697 const MCOperand &MO = MI.getOperand(OpNo);
698 bool IsSReg32 =
699 MRI.getRegClass(AMDGPU::SReg_32RegClassID).contains(MO.getReg());
700 unsigned Enc = MRI.getEncodingValue(MO.getReg());
701 unsigned Idx = Enc & AMDGPU::HWEncoding::LO256_REG_IDX_MASK;
702 bool IsVGPROrAGPR =
704 Op = Idx | IsVGPROrAGPR << 8 | IsSReg32 << 7;
705}
706
707void AMDGPUMCCodeEmitter::getMachineOpValueCommon(
708 const MCInst &MI, const MCOperand &MO, unsigned OpNo, APInt &Op,
709 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
710 bool isLikeImm = false;
711 int64_t Val;
712
713 if (MO.isImm()) {
714 Val = MO.getImm();
715 isLikeImm = true;
716 } else if (MO.isExpr() && MO.getExpr()->evaluateAsAbsolute(Val)) {
717 isLikeImm = true;
718 } else if (MO.isExpr()) {
719 // FIXME: If this is expression is PCRel or not should not depend on what
720 // the expression looks like. Given that this is just a general expression,
721 // it should probably be FK_Data_4 and whatever is producing
722 //
723 // s_add_u32 s2, s2, (extern_const_addrspace+16
724 //
725 // And expecting a PCRel should instead produce
726 //
727 // .Ltmp1:
728 // s_add_u32 s2, s2, (extern_const_addrspace+16)-.Ltmp1
729 bool PCRel = needsPCRel(MO.getExpr());
730 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
731 uint32_t Offset = Desc.getSize();
732 assert(Offset == 4 || Offset == 8);
733 unsigned Size = AMDGPU::getOperandSize(Desc, OpNo);
735 addFixup(Fixups, Offset, MO.getExpr(), Kind, PCRel);
736 }
737
738 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
739 if (AMDGPU::isSISrcOperand(Desc, OpNo)) {
740 bool HasMandatoryLiteral =
741 AMDGPU::hasNamedOperand(MI.getOpcode(), AMDGPU::OpName::imm);
742 if (auto Enc = getLitEncoding(Desc, MO, OpNo, STI, HasMandatoryLiteral)) {
743 Op = *Enc;
744 return;
745 }
746
747 llvm_unreachable("Operand not supported for SISrc");
748 }
749
750 if (isLikeImm) {
751 Op = Val;
752 return;
753 }
754
755 llvm_unreachable("Encoding of this operand type is not supported yet.");
756}
757
758template <bool HasSrc0, bool HasSrc1, bool HasSrc2>
759APInt AMDGPUMCCodeEmitter::postEncodeVOP3(const MCInst &MI, APInt EncodedValue,
760 const MCSubtargetInfo &STI) const {
761 if (!AMDGPU::isGFX10Plus(STI))
762 return EncodedValue;
763 // Set unused source fields in VOP3 encodings to inline immediate 0 to avoid
764 // hardware conservatively assuming the instruction reads SGPRs.
765 constexpr uint64_t InlineImmediate0 = 0x80;
766 if (!HasSrc0)
767 EncodedValue |= InlineImmediate0 << 32;
768 if (!HasSrc1)
769 EncodedValue |= InlineImmediate0 << 41;
770 if (!HasSrc2)
771 EncodedValue |= InlineImmediate0 << 50;
772 return EncodedValue;
773}
774
775APInt AMDGPUMCCodeEmitter::postEncodeVOPCX(const MCInst &MI, APInt EncodedValue,
776 const MCSubtargetInfo &STI) const {
777 // GFX10+ v_cmpx opcodes promoted to VOP3 have implied dst=EXEC.
778 // Documentation requires dst to be encoded as EXEC (0x7E),
779 // but it looks like the actual value encoded for dst operand
780 // is ignored by HW. It was decided to define dst as "do not care"
781 // in td files to allow disassembler accept any dst value.
782 // However, dst is encoded as EXEC for compatibility with SP3.
784 MCII.get(MI.getOpcode()).hasImplicitDefOfPhysReg(AMDGPU::EXEC));
785 EncodedValue |= MRI.getEncodingValue(AMDGPU::EXEC_LO) &
787 return postEncodeVOP3<true, true, false>(MI, EncodedValue, STI);
788}
789
790#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!")
unsigned Imm
unsigned uint64_t
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...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
IRTranslator LLVM IR MI
Register Reg
LLVM_ABI uint64_t extractBitsAsZExtValue(unsigned numBits, unsigned bitPosition) const
Definition APInt.cpp:517
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:472
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:197
@ Sub
Subtraction.
Definition MCExpr.h:323
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.
LLVM_ABI bool hasImplicitDefOfPhysReg(MCRegister Reg, const MCRegisterInfo *MRI=nullptr) const
Return true if this instruction implicitly defines the specified physical register.
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:89
uint8_t OperandType
Information about the type of the operand.
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
bool contains(MCRegister Reg) const
contains - Return true if the specified register is included in this register class.
uint16_t getEncodingValue(MCRegister Reg) const
Returns the encoding for Reg.
const MCRegisterClass & getRegClass(unsigned i) const
Returns the register class associated with the enumeration value.
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_REG_IMM_V2FP64
Definition SIDefines.h:447
@ OPERAND_KIMM32
Operand with 32-bit immediate that uses the constant bus.
Definition SIDefines.h:465
@ OPERAND_REG_IMM_INT64
Definition SIDefines.h:432
@ OPERAND_REG_IMM_V2FP16
Definition SIDefines.h:440
@ OPERAND_REG_INLINE_C_FP64
Definition SIDefines.h:456
@ OPERAND_REG_IMM_NOINLINE_FP16
Definition SIDefines.h:438
@ OPERAND_REG_INLINE_C_BF16
Definition SIDefines.h:453
@ OPERAND_REG_INLINE_C_V2BF16
Definition SIDefines.h:458
@ OPERAND_REG_IMM_V2INT64
Definition SIDefines.h:443
@ OPERAND_REG_IMM_V2INT16
Definition SIDefines.h:442
@ OPERAND_REG_IMM_BF16
Definition SIDefines.h:436
@ OPERAND_REG_IMM_INT32
Operands with register, 32-bit, or 64-bit immediate.
Definition SIDefines.h:431
@ OPERAND_REG_IMM_V2BF16
Definition SIDefines.h:439
@ OPERAND_REG_IMM_FP16
Definition SIDefines.h:437
@ OPERAND_REG_IMM_V2FP16_SPLAT
Definition SIDefines.h:441
@ OPERAND_REG_INLINE_C_INT64
Definition SIDefines.h:452
@ OPERAND_REG_INLINE_C_INT16
Operands with register or inline constant.
Definition SIDefines.h:450
@ OPERAND_REG_IMM_NOINLINE_V2FP16
Definition SIDefines.h:444
@ OPERAND_REG_IMM_FP64
Definition SIDefines.h:435
@ OPERAND_REG_INLINE_C_V2FP16
Definition SIDefines.h:459
@ OPERAND_REG_INLINE_AC_INT32
Operands with an AccVGPR register or inline constant.
Definition SIDefines.h:470
@ OPERAND_REG_INLINE_AC_FP32
Definition SIDefines.h:471
@ OPERAND_REG_IMM_V2INT32
Definition SIDefines.h:445
@ OPERAND_REG_IMM_FP32
Definition SIDefines.h:434
@ OPERAND_REG_INLINE_C_FP32
Definition SIDefines.h:455
@ OPERAND_REG_INLINE_C_INT32
Definition SIDefines.h:451
@ OPERAND_REG_INLINE_C_V2INT16
Definition SIDefines.h:457
@ OPERAND_REG_IMM_V2FP32
Definition SIDefines.h:446
@ OPERAND_REG_INLINE_AC_FP64
Definition SIDefines.h:472
@ OPERAND_REG_INLINE_C_FP16
Definition SIDefines.h:454
@ OPERAND_REG_IMM_INT16
Definition SIDefines.h:433
@ OPERAND_INLINE_SPLIT_BARRIER_INT32
Definition SIDefines.h:462
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)
constexpr bool isVOP3(const T &...O)
Definition SIDefines.h:239
constexpr bool isVOP3P(const T &...O)
Definition SIDefines.h:242
constexpr bool isVOP3Like(const T &...O)
Definition SIDefines.h:245
constexpr bool isMIMG(const T &...O)
Definition SIDefines.h:274
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:82
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
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:190
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
Definition MathExtras.h:156
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)