Add extended mnemonics to paddis: ``` paddis RT,RA,SI -> paddis RT,RA,SI,0 plis RT,SI -> paddis RT,0,SI,0 psubis RT,RA,si -> paddis RT,RA,-si,0 ``` Assisted by AI.
433 lines
17 KiB
TableGen
433 lines
17 KiB
TableGen
//===-- PPCOperands.td - PowerPC instruction operands -------*- tablegen -*-==//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines PowerPC instruction operands, including immediate
|
|
// operands and addressing modes.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Immediate operand base classes
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Base class for immediate AsmOperandClass definitions.
|
|
class ImmediateAsmOperand<string predicate, string render="addImmOperands">
|
|
: AsmOperandClass {
|
|
let Name = NAME;
|
|
let PredicateMethod = predicate;
|
|
let RenderMethod = render;
|
|
}
|
|
|
|
// 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";
|
|
}
|
|
|
|
// 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).
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
multiclass ImmPatterns<ValueType vt, code pred, SDNodeXForm xform> {
|
|
def _pat : ImmLeaf<vt, pred, xform>;
|
|
def _timm : TImmLeaf<vt, pred, xform>;
|
|
}
|
|
|
|
multiclass SignedImmediate<ValueType vt, code pred, SDNodeXForm xform,
|
|
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,
|
|
string 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>;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Immediate transformation functions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// NEG_S32 - Negate a signed 32-bit immediate value
|
|
def NEG_S32 : SDNodeXForm<imm, [{
|
|
// Transformation function: -imm
|
|
return getI32Imm(-N->getSExtValue(), SDLoc(N));
|
|
}]>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Immediate AsmOperand definitions
|
|
//===----------------------------------------------------------------------===//
|
|
def U1Imm : ImmediateAsmOperand<"isUImm<1>">;
|
|
def U2Imm : ImmediateAsmOperand<"isUImm<2>">;
|
|
def U3Imm : ImmediateAsmOperand<"isUImm<3>">;
|
|
def U4Imm : ImmediateAsmOperand<"isUImm<4>">;
|
|
def U5Imm : ImmediateAsmOperand<"isUImm<5>">;
|
|
def U6Imm : ImmediateAsmOperand<"isUImm<6>">;
|
|
def U7Imm : ImmediateAsmOperand<"isUImm<7>">;
|
|
def U8Imm : ImmediateAsmOperand<"isUImm<8>">;
|
|
def U10Imm : ImmediateAsmOperand<"isUImm<10>">;
|
|
def U12Imm : ImmediateAsmOperand<"isUImm<12>">;
|
|
def U32Imm : ImmediateAsmOperand<"isUImm<32>">;
|
|
def S5Imm : ImmediateAsmOperand<"isSImm<5>">;
|
|
|
|
// Special cases that have custom predicat and/or render method.
|
|
def ATBitsAsHint : ImmediateAsmOperand<"isATBitsAsHint">; //Predicate always fails.
|
|
def ImmZero : ImmediateAsmOperand<"isImmZero">;
|
|
def U16Imm : ImmediateAsmOperand<"isU16Imm","addU16ImmOperands">;
|
|
def S16Imm : ImmediateAsmOperand<"isS16Imm","addS16ImmOperands">;
|
|
def S17Imm : ImmediateAsmOperand<"isS17Imm","addS16ImmOperands">;
|
|
def S32Imm : ImmediateAsmOperand<"isS32Imm">;
|
|
def S34Imm : ImmediateAsmOperand<"isS34Imm">;
|
|
def NegS32Imm : ImmediateAsmOperand<"isS32Imm","addNegImmOperands">;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// i32 immediate operands
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
defm u1imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<1>(Imm); }], NOOP_SDNodeXForm,
|
|
"U1Imm", 1>;
|
|
defm u2imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<2>(Imm); }], NOOP_SDNodeXForm,
|
|
"U2Imm", 2>;
|
|
defm u3imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<3>(Imm); }], NOOP_SDNodeXForm,
|
|
"U3Imm", 3>;
|
|
defm u4imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<4>(Imm); }], NOOP_SDNodeXForm,
|
|
"U4Imm", 4>;
|
|
defm u5imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<5>(Imm); }], NOOP_SDNodeXForm,
|
|
"U5Imm", 5>;
|
|
defm u6imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<6>(Imm); }], NOOP_SDNodeXForm,
|
|
"U6Imm", 6>;
|
|
defm u7imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<7>(Imm); }], NOOP_SDNodeXForm,
|
|
"U7Imm", 7>;
|
|
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>;
|
|
defm u12imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<12>(Imm); }], NOOP_SDNodeXForm,
|
|
"U12Imm", 12>;
|
|
defm u32imm : UnsignedImmediate<i32,
|
|
[{ return isUInt<32>(Imm); }], NOOP_SDNodeXForm,
|
|
"U32Imm", 32>;
|
|
|
|
defm s5imm : SignedImmediate<i32,
|
|
[{ return isInt<5>(Imm); }], NOOP_SDNodeXForm,
|
|
"S5Imm", 5>;
|
|
|
|
defm s32imm : SignedImmediateWithPCRel<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">;
|
|
defm neg_s32imm : SignedImmediateReloc<i32,
|
|
[{ return isInt<32>(Imm); }], NEG_S32,
|
|
"NegS32Imm", 32, "PPC::fixup_ppc_imm32">;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// i64 immediate operands
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
defm s32imm64 : SignedImmediateWithPCRel<i64,
|
|
[{ return isInt<32>(Imm); }], NOOP_SDNodeXForm,
|
|
"S32Imm", 32, "PPC::fixup_ppc_imm32", "PPC::fixup_ppc_pcrel32">;
|
|
defm s34imm64 : SignedImmediateWithPCRel<i64,
|
|
[{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
|
|
"S34Imm", 34, "PPC::fixup_ppc_imm34", "PPC::fixup_ppc_pcrel34">;
|
|
defm neg_s32imm64 : SignedImmediateReloc<i64,
|
|
[{ return isInt<32>(Imm); }], NEG_S32,
|
|
"NegS32Imm", 32, "PPC::fixup_ppc_imm32">;
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Special case immediate operands
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// immZero represents a hardcoded zero register encoding, it is NOT used in DAG
|
|
// patterns. It is only used as an instruction operand for assembly/disassembly,
|
|
// specifically to represent a hardcoded zero register value in PC-relative
|
|
// addressing modes.
|
|
def immZero : Operand<i32> {
|
|
let PrintMethod = "printImmZeroOperand";
|
|
let ParserMatchClass = ImmZero;
|
|
let DecoderMethod = "decodeImmZeroOperand";
|
|
let OperandType = "OPERAND_IMMEDIATE";
|
|
}
|
|
|
|
// atimm is used to represent branch prediction hints, not a general immediate
|
|
// value. It's a 2-bit AT (Address Translation) field in PPC branch instructions
|
|
// and is an assembly-only operand that prints as `+` or `-` symbols, not
|
|
// numeric values.
|
|
def atimm : Operand<i32> {
|
|
let PrintMethod = "printATBitsAsHint";
|
|
let ParserMatchClass = ATBitsAsHint;
|
|
let OperandType = "OPERAND_IMMEDIATE";
|
|
}
|
|
|
|
// Special cases: s16imm and u16imm have custom encoder methods.
|
|
defm s16imm : SignedImmediateReloc<i32,
|
|
[{ return isInt<16>(Imm); }], NOOP_SDNodeXForm,
|
|
"S16Imm", 16, "PPC::fixup_ppc_half16">;
|
|
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 : 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 : 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 : ImmediateRelocOp<i32, "S17Imm", 16, "PPC::fixup_ppc_half16"> {
|
|
let PrintMethod = "printS16ImmOperand";
|
|
}
|
|
def s17imm64 : ImmediateRelocOp<i64, "S17Imm", 16, "PPC::fixup_ppc_half16"> {
|
|
let PrintMethod = "printS16ImmOperand";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Branch target operands
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PPCDirectBrAsmOperand : AsmOperandClass {
|
|
let Name = "DirectBr"; let PredicateMethod = "isDirectBr";
|
|
let RenderMethod = "addBranchTargetOperands";
|
|
}
|
|
def directbrtarget : Operand<OtherVT> {
|
|
let PrintMethod = "printBranchOperand";
|
|
let EncoderMethod = "getDirectBrEncoding";
|
|
let DecoderMethod = "decodeDirectBrTarget";
|
|
let ParserMatchClass = PPCDirectBrAsmOperand;
|
|
let OperandType = "OPERAND_PCREL";
|
|
}
|
|
def absdirectbrtarget : Operand<OtherVT> {
|
|
let PrintMethod = "printAbsBranchOperand";
|
|
let EncoderMethod = "getAbsDirectBrEncoding";
|
|
let DecoderMethod = "decodeDirectBrTarget";
|
|
let ParserMatchClass = PPCDirectBrAsmOperand;
|
|
}
|
|
def PPCCondBrAsmOperand : AsmOperandClass {
|
|
let Name = "CondBr"; let PredicateMethod = "isCondBr";
|
|
let RenderMethod = "addBranchTargetOperands";
|
|
}
|
|
def condbrtarget : Operand<OtherVT> {
|
|
let PrintMethod = "printBranchOperand";
|
|
let EncoderMethod = "getCondBrEncoding";
|
|
let DecoderMethod = "decodeCondBrTarget";
|
|
let ParserMatchClass = PPCCondBrAsmOperand;
|
|
let OperandType = "OPERAND_PCREL";
|
|
}
|
|
def abscondbrtarget : Operand<OtherVT> {
|
|
let PrintMethod = "printAbsBranchOperand";
|
|
let EncoderMethod = "getAbsCondBrEncoding";
|
|
let DecoderMethod = "decodeCondBrTarget";
|
|
let ParserMatchClass = PPCCondBrAsmOperand;
|
|
}
|
|
def calltarget : Operand<iPTR> {
|
|
let PrintMethod = "printBranchOperand";
|
|
let EncoderMethod = "getDirectBrEncoding";
|
|
let DecoderMethod = "decodeDirectBrTarget";
|
|
let ParserMatchClass = PPCDirectBrAsmOperand;
|
|
let OperandType = "OPERAND_PCREL";
|
|
}
|
|
def abscalltarget : Operand<iPTR> {
|
|
let PrintMethod = "printAbsBranchOperand";
|
|
let EncoderMethod = "getAbsDirectBrEncoding";
|
|
let DecoderMethod = "decodeDirectBrTarget";
|
|
let ParserMatchClass = PPCDirectBrAsmOperand;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CR bit mask operand
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PPCCRBitMaskOperand : AsmOperandClass {
|
|
let Name = "CRBitMask"; let PredicateMethod = "isCRBitMask";
|
|
}
|
|
def crbitm: Operand<i8> {
|
|
let PrintMethod = "printcrbitm";
|
|
let EncoderMethod = "get_crbitm_encoding";
|
|
let DecoderMethod = "decodeCRBitMOperand";
|
|
let ParserMatchClass = PPCCRBitMaskOperand;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Displacement operands
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PPCDispRI34Operand : AsmOperandClass {
|
|
let Name = "DispRI34"; let PredicateMethod = "isS34Imm";
|
|
let RenderMethod = "addImmOperands";
|
|
}
|
|
def dispRI34 : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispRI34Operand;
|
|
let EncoderMethod = "getDispRI34Encoding";
|
|
let DecoderMethod = "decodeSImmOperand<34>";
|
|
}
|
|
def dispRI34_pcrel : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispRI34Operand;
|
|
let EncoderMethod = "getDispRI34PCRelEncoding";
|
|
let DecoderMethod = "decodeSImmOperand<34>";
|
|
}
|
|
def PPCDispRIOperand : AsmOperandClass {
|
|
let Name = "DispRI"; let PredicateMethod = "isS16Imm";
|
|
let RenderMethod = "addS16ImmOperands";
|
|
}
|
|
def dispRI : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispRIOperand;
|
|
let EncoderMethod = "getDispRIEncoding";
|
|
}
|
|
def PPCDispRIXOperand : AsmOperandClass {
|
|
let Name = "DispRIX"; let PredicateMethod = "isS16ImmX4";
|
|
let RenderMethod = "addS16ImmOperands";
|
|
}
|
|
def dispRIX : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispRIXOperand;
|
|
let EncoderMethod = "getDispRIXEncoding";
|
|
let DecoderMethod = "decodeDispRIXOperand";
|
|
}
|
|
def PPCDispRIHashOperand : AsmOperandClass {
|
|
let Name = "DispRIHash"; let PredicateMethod = "isHashImmX8";
|
|
let RenderMethod = "addImmOperands";
|
|
}
|
|
def dispRIHash : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispRIHashOperand;
|
|
let EncoderMethod = "getDispRIHashEncoding";
|
|
let DecoderMethod = "decodeDispRIHashOperand";
|
|
}
|
|
def PPCDispRIX16Operand : AsmOperandClass {
|
|
let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16";
|
|
let RenderMethod = "addS16ImmOperands";
|
|
}
|
|
def dispRIX16 : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispRIX16Operand;
|
|
let EncoderMethod = "getDispRIX16Encoding";
|
|
let DecoderMethod = "decodeDispRIX16Operand";
|
|
}
|
|
def PPCDispSPE8Operand : AsmOperandClass {
|
|
let Name = "DispSPE8"; let PredicateMethod = "isU8ImmX8";
|
|
let RenderMethod = "addImmOperands";
|
|
}
|
|
def dispSPE8 : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispSPE8Operand;
|
|
let DecoderMethod = "decodeDispSPE8Operand";
|
|
let EncoderMethod = "getDispSPE8Encoding";
|
|
}
|
|
def PPCDispSPE4Operand : AsmOperandClass {
|
|
let Name = "DispSPE4"; let PredicateMethod = "isU7ImmX4";
|
|
let RenderMethod = "addImmOperands";
|
|
}
|
|
def dispSPE4 : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispSPE4Operand;
|
|
let DecoderMethod = "decodeDispSPE4Operand";
|
|
let EncoderMethod = "getDispSPE4Encoding";
|
|
}
|
|
def PPCDispSPE2Operand : AsmOperandClass {
|
|
let Name = "DispSPE2"; let PredicateMethod = "isU6ImmX2";
|
|
let RenderMethod = "addImmOperands";
|
|
}
|
|
def dispSPE2 : Operand<iPTR> {
|
|
let ParserMatchClass = PPCDispSPE2Operand;
|
|
let DecoderMethod = "decodeDispSPE2Operand";
|
|
let EncoderMethod = "getDispSPE2Encoding";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// TLS operands
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def PPCTLSRegOperand : AsmOperandClass {
|
|
let Name = "TLSReg"; let PredicateMethod = "isTLSReg";
|
|
let RenderMethod = "addTLSRegOperands";
|
|
}
|
|
def tlsreg32 : Operand<i32> {
|
|
let EncoderMethod = "getTLSRegEncoding";
|
|
let ParserMatchClass = PPCTLSRegOperand;
|
|
}
|
|
def tlsgd32 : Operand<i32> {}
|
|
def tlscall32 : Operand<i32> {
|
|
let PrintMethod = "printTLSCall";
|
|
let MIOperandInfo = (ops calltarget:$func, tlsgd32:$sym);
|
|
let EncoderMethod = "getTLSCallEncoding";
|
|
}
|