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