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