[PowerPC] Refactor immediate operand part 2 (#180289)

Contiue with immediate operand refactoring:
* consolidate printU##Imm into a template function resulting in simpler
class def
* separate imm and relocation classes to clearly reflect what they are
This commit is contained in:
Lei Huang 2026-03-11 16:07:19 -04:00 committed by GitHub
parent e1cea97e28
commit e868e45a75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 110 additions and 152 deletions

View File

@ -323,43 +323,25 @@ void PPCInstPrinter::printATBitsAsHint(const MCInst *MI, unsigned OpNo,
O << "+";
}
void PPCInstPrinter::printU1ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
// Template for unsigned immediate operands with validation.
// Validates that the value fits within the specified width and prints it.
template <unsigned Width>
void PPCInstPrinter::printUImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 1 && "Invalid u1imm argument!");
assert(Value <= ((1U << Width) - 1) && "Invalid uimm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU2ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 3 && "Invalid u2imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU3ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 8 && "Invalid u3imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 15 && "Invalid u4imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
// Template for signed immediate operands with sign extension.
// Sign-extends the value to the specified width and prints it.
template <unsigned Width>
void PPCInstPrinter::printSImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
int Value = MI->getOperand(OpNo).getImm();
Value = SignExtend32<5>(Value);
Value = SignExtend32<Width>(Value);
O << (int)Value;
}
@ -371,56 +353,16 @@ void PPCInstPrinter::printImmZeroOperand(const MCInst *MI, unsigned OpNo,
O << (unsigned int)Value;
}
void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 31 && "Invalid u5imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU6ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 63 && "Invalid u6imm argument!");
O << (unsigned int)Value;
}
void PPCInstPrinter::printU7ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned int Value = MI->getOperand(OpNo).getImm();
assert(Value <= 127 && "Invalid u7imm argument!");
O << (unsigned int)Value;
}
// Operands of BUILD_VECTOR are signed and we use this to print operands
// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and
// print as unsigned.
void PPCInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
// Truncating version specifically for BUILD_VECTOR operands that may be
// sign-extended (e.g., -1 becomes 0xFFFFFFFF). Truncates to 8 bits without
// validation, unlike the standard printUImmOperand<8> which validates.
void PPCInstPrinter::printU8ImmOperandTrunc(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned char Value = MI->getOperand(OpNo).getImm();
O << (unsigned int)Value;
}
void PPCInstPrinter::printU10ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned short Value = MI->getOperand(OpNo).getImm();
assert(Value <= 1023 && "Invalid u10imm argument!");
O << (unsigned short)Value;
}
void PPCInstPrinter::printU12ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned short Value = MI->getOperand(OpNo).getImm();
assert(Value <= 4095 && "Invalid u12imm argument!");
O << (unsigned short)Value;
}
void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {

View File

@ -56,28 +56,18 @@ public:
void printATBitsAsHint(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU1ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU2ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU3ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU4ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printS5ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU5ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU6ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU7ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU8ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU10ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU12ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
// Template for unsigned immediate operands with validation.
template <unsigned Width>
void printUImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
// Template for signed immediate operands with sign extension.
template <unsigned Width>
void printSImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printU8ImmOperandTrunc(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printS16ImmOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printS32ImmOperand(const MCInst *MI, unsigned OpNo,

View File

@ -1707,7 +1707,7 @@ let Predicates = [HasVSX, HasP9Vector] in {
RegConstraint<"$XTi = $XT">;
// Vector Splat Immediate Byte
def XXSPLTIB : X_RD6_IMM8<60, 360, (outs vsrc:$XT), (ins u8imm:$IMM8),
def XXSPLTIB : X_RD6_IMM8<60, 360, (outs vsrc:$XT), (ins u8imm_trunc:$IMM8),
"xxspltib $XT, $IMM8", IIC_VecPerm, []>;
// When adding new D-Form loads/stores, be sure to update the ImmToIdxMap in

View File

@ -17,71 +17,90 @@
// Base class for immediate AsmOperandClass definitions.
class ImmediateAsmOperand<string predicate, string render="addImmOperands">
: AsmOperandClass {
: AsmOperandClass {
let Name = NAME;
let PredicateMethod = predicate;
let RenderMethod = render;
}
// Base class for immediate operands with optional encoder.
class ImmediateOp<ValueType vt, string asmop, int width, bit is_signed = 0,
string encoder = "", string decoder = ""> : Operand<vt> {
let PrintMethod = "print"#asmop#"Operand";
// Base class for signed immediate operands.
class ImmediateOp<ValueType vt, string asmop, int width> : Operand<vt> {
let PrintMethod = "printSImmOperand<"#width#">";
let DecoderMethod = "decodeSImmOperand<"#width#">";
let ParserMatchClass = !cast<AsmOperandClass>(asmop);
let OperandType = "OPERAND_IMMEDIATE";
// Set decoder method based on signedness if not explicitly provided
let DecoderMethod = !if(!eq(decoder, ""),
!if(is_signed,
"decodeSImmOperand<"#width#">",
"decodeUImmOperand<"#width#">"),
decoder);
// Set encoder method if provided
let EncoderMethod = !if(!eq(encoder, ""),
"",
"getImmEncoding<" # encoder # ">");
}
// Base class for unsigned immediate operands.
class UImmediateOp<ValueType vt, string asmop, int width>
: ImmediateOp<vt, asmop, width> {
let PrintMethod = "printUImmOperand<"#width#">";
let DecoderMethod = "decodeUImmOperand<"#width#">";
}
// Base class for signed immediate operands with relocation.
class ImmediateRelocOp<ValueType vt, string asmop, int width, string fixup,
string decoder = ""> : Operand<vt> {
let PrintMethod = "print"#asmop#"Operand";
let DecoderMethod = !if(!eq(decoder, ""),
"decodeSImmOperand<"#width#">",
decoder);
let ParserMatchClass = !cast<AsmOperandClass>(asmop);
let EncoderMethod = "getImmEncoding<" # fixup # ">";
let OperandType = "OPERAND_IMMEDIATE";
}
// Base class for unsigned immediate operands with relocation.
class UImmediateRelocOp<ValueType vt, string asmop, int width, string fixup,
string decoder = "">
: ImmediateRelocOp<vt, asmop, width, fixup> {
let DecoderMethod = !if(!eq(decoder, ""),
"decodeUImmOperand<"#width#">",
decoder);
}
//===----------------------------------------------------------------------===//
// Multiclasses for complete immediate definitions
// (AsmOperand + Operand + ImmLeaf).
//===----------------------------------------------------------------------===//
// Helper multiclass that generates operand + patterns together while keeping
// them as separate definitions for GlobalISel compatibility.
multiclass ImmOpWithPatterns<ValueType vt, string asmop, int width,
bit is_signed, code pred, SDNodeXForm xform,
string encoder = ""> {
// Operand definition (for instruction operands)
def "" : ImmediateOp<vt, asmop, width, is_signed, encoder>;
// ImmLeaf for imm nodes (for DAG pattern matching)
multiclass ImmPatterns<ValueType vt, code pred, SDNodeXForm xform> {
def _pat : ImmLeaf<vt, pred, xform>;
// TImmLeaf for timm nodes (for target-specific pattern matching, e.g., intrinsics)
def _timm : TImmLeaf<vt, pred, xform>;
}
// Creates Operand and separate ImmLeaf definitions for unsigned immediates.
multiclass UnsignedImmediate<ValueType vt, code pred, SDNodeXForm xform,
string asmop, int width, string encoder = "">
: ImmOpWithPatterns<vt, asmop, width, 0, pred, xform, encoder>;
// Creates Operand and separate ImmLeaf definitions for signed immediates.
multiclass SignedImmediate<ValueType vt, code pred, SDNodeXForm xform,
string asmop, int width, string encoder = "">
: ImmOpWithPatterns<vt, asmop, width, 1, pred, xform, encoder>;
string asmop, int width >
: ImmPatterns<vt, pred, xform> {
def "" : ImmediateOp<vt, asmop, width>;
}
multiclass UnsignedImmediate<ValueType vt, code pred, SDNodeXForm xform,
string asmop, int width >
: ImmPatterns<vt, pred, xform> {
def "" : UImmediateOp<vt, asmop, width>;
}
multiclass SignedImmediateReloc<ValueType vt, code pred, SDNodeXForm xform,
string asmop, int width, string fixup>
: ImmPatterns<vt, pred, xform> {
def "" : ImmediateRelocOp<vt, asmop, width, fixup>;
}
// Helper multiclass for unsigned immediates with relocation fixup string.
multiclass UnsignedImmediateReloc<ValueType vt, code pred, SDNodeXForm xform,
string asmop, int width, string fixup>
: ImmPatterns<vt, pred, xform> {
def "" : UImmediateRelocOp<vt, asmop, width, fixup>;
}
// Multiclass for signed immediate operands with both regular and
// PC-relative versions.
multiclass SignedImmediateWithPCRel<ValueType vt, code pred,
SDNodeXForm xform, string asmop,
int width, string fixup_imm,
multiclass SignedImmediateWithPCRel<ValueType vt, code pred, SDNodeXForm xform,
string asmop, int width, string fixup_imm,
string fixup_pcrel>
: SignedImmediate<vt, pred, xform, asmop, width, fixup_imm> {
// PC-relative immediate: instantiate SignedImmediate with PC-relative fixup
defm _pcrel : SignedImmediate<vt, pred, xform, asmop, width, fixup_pcrel>;
: SignedImmediateReloc<vt, pred, xform, asmop, width, fixup_imm> {
// PC-relative immediate: instantiate with PC-relative fixup
defm _pcrel : SignedImmediateReloc<vt, pred, xform, asmop, width, fixup_pcrel>;
}
//===----------------------------------------------------------------------===//
@ -136,6 +155,12 @@ defm u7imm : UnsignedImmediate<i32,
defm u8imm : UnsignedImmediate<i32,
[{ return isUInt<8>(Imm); }], NOOP_SDNodeXForm,
"U8Imm", 8>;
// Truncating version for BUILD_VECTOR operands that may be sign-extended.
// Uses the same parser class as u8imm but with a truncating print method.
def u8imm_trunc : UImmediateOp<i32, "U8Imm", 8> {
let PrintMethod = "printU8ImmOperandTrunc";
}
defm u10imm : UnsignedImmediate<i32,
[{ return isUInt<10>(Imm); }], NOOP_SDNodeXForm,
"U10Imm", 10>;
@ -148,9 +173,10 @@ defm s5imm : SignedImmediate<i32,
"S5Imm", 5>;
defm s32imm : SignedImmediateWithPCRel<i32,
[{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
"S34Imm", 34, "PPC::fixup_ppc_imm32", "PPC::fixup_ppc_pcrel32">;
defm s34imm : SignedImmediate<i32,
[{ return isInt<32>(Imm); }], NOOP_SDNodeXForm,
"S32Imm", 32, "PPC::fixup_ppc_imm32", "PPC::fixup_ppc_pcrel32">;
defm s34imm : SignedImmediateReloc<i32,
[{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
"S34Imm", 34, "PPC::fixup_ppc_imm34">;
@ -191,29 +217,29 @@ def atimm : Operand<i32> {
}
// Special cases: s16imm and u16imm have custom encoder methods.
defm s16imm : SignedImmediate<i32,
defm s16imm : SignedImmediateReloc<i32,
[{ return isInt<16>(Imm); }], NOOP_SDNodeXForm,
"S16Imm", 16, "PPC::fixup_ppc_half16">;
defm u16imm : UnsignedImmediate<i32,
defm u16imm : UnsignedImmediateReloc<i32,
[{ return isUInt<16>(Imm); }], NOOP_SDNodeXForm,
"U16Imm", 16, "PPC::fixup_ppc_half16">;
// s16imm64 uses imm64SExt16 pattern to match the operand type.
def s16imm64 : ImmediateOp<i64, "S16Imm", 16, 1, "PPC::fixup_ppc_half16">;
def s16imm64 : ImmediateRelocOp<i64, "S16Imm", 16, "PPC::fixup_ppc_half16">;
// u16imm64 uses two different patterns depending on the instruction context:
// * immZExt16 - For low 16-bit immediates
// * imm16ShiftedZExt - For high 16-bit immediates (shifted)
def u16imm64 : ImmediateOp<i64, "U16Imm", 16, 0, "PPC::fixup_ppc_half16">;
def u16imm64 : UImmediateRelocOp<i64, "U16Imm", 16, "PPC::fixup_ppc_half16">;
// Special case: s17imm uses S16Imm print method but accepts wider range.
// This operand type is used for addis/lis to allow the assembler parser
// to accept immediates in the range -65536..65535 for compatibility
// with the GNU assembler. The operand is treated as 16-bit otherwise.
def s17imm : ImmediateOp<i32, "S17Imm", 16, 1, "PPC::fixup_ppc_half16"> {
def s17imm : ImmediateRelocOp<i32, "S17Imm", 16, "PPC::fixup_ppc_half16"> {
let PrintMethod = "printS16ImmOperand";
}
def s17imm64 : ImmediateOp<i64, "S17Imm", 16, 1, "PPC::fixup_ppc_half16"> {
def s17imm64 : ImmediateRelocOp<i64, "S17Imm", 16, "PPC::fixup_ppc_half16"> {
let PrintMethod = "printS16ImmOperand";
}