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