-// The trickiest of those constraints is that Rm can be either GPR32 or GPR64,
-// which will need separate instructions for LLVM type-consistency. We'll also
-// need separate operands, of course.
-multiclass regexts<int MemSize, int RmSize, RegisterClass GPR,
- string Rm, string prefix> {
- def regext_asmoperand : AsmOperandClass {
- let Name = "AddrRegExtend_" # MemSize # "_" # Rm;
- let PredicateMethod = "isAddrRegExtend<" # MemSize # "," # RmSize # ">";
- let RenderMethod = "addAddrRegExtendOperands<" # MemSize # ">";
- let DiagnosticType = "LoadStoreExtend" # RmSize # "_" # MemSize;
- }
-
- def regext : Operand<i64> {
- let PrintMethod
- = "printAddrRegExtendOperand<" # MemSize # ", " # RmSize # ">";
-
- let DecoderMethod = "DecodeAddrRegExtendOperand";
- let ParserMatchClass
- = !cast<AsmOperandClass>(prefix # regext_asmoperand);
- }
-}
-
-multiclass regexts_wx<int MemSize, string prefix> {
- // Rm is an X-register if LSL or SXTX are specified as the shift.
- defm Xm_ : regexts<MemSize, 64, GPR64, "Xm", prefix # "Xm_">;
-
- // Rm is a W-register if UXTW or SXTW are specified as the shift.
- defm Wm_ : regexts<MemSize, 32, GPR32, "Wm", prefix # "Wm_">;
-}
-
-defm byte_ : regexts_wx<1, "byte_">;
-defm hword_ : regexts_wx<2, "hword_">;
-defm word_ : regexts_wx<4, "word_">;
-defm dword_ : regexts_wx<8, "dword_">;
-defm qword_ : regexts_wx<16, "qword_">;
-
-
-//===------------------------------
-// 2. The instructions themselves.
-//===------------------------------
-
-// We have the following instructions to implement:
-// | | B | H | W | X |
-// |-----------------+-------+-------+-------+--------|
-// | unsigned str | STRB | STRH | STR | STR |
-// | unsigned ldr | LDRB | LDRH | LDR | LDR |
-// | signed ldr to W | LDRSB | LDRSH | - | - |
-// | signed ldr to X | LDRSB | LDRSH | LDRSW | (PRFM) |
-
-// This will instantiate the LDR/STR instructions you'd expect to use for an
-// unsigned datatype (first two rows above) or floating-point register, which is
-// reasonably uniform across all access sizes.
-
-
-//===------------------------------
-// 2.1 Regular instructions
-//===------------------------------
-
-// This class covers the basic unsigned or irrelevantly-signed loads and stores,
-// to general-purpose and floating-point registers.
-
-class AddrParams<string prefix> {
- Operand uimm12 = !cast<Operand>(prefix # "_uimm12");
-
- Operand regextWm = !cast<Operand>(prefix # "_Wm_regext");
- Operand regextXm = !cast<Operand>(prefix # "_Xm_regext");
-}
-
-def byte_addrparams : AddrParams<"byte">;
-def hword_addrparams : AddrParams<"hword">;
-def word_addrparams : AddrParams<"word">;
-def dword_addrparams : AddrParams<"dword">;
-def qword_addrparams : AddrParams<"qword">;
-
-multiclass A64I_LDRSTR_unsigned<string prefix, bits<2> size, bit v,
- bit high_opc, string asmsuffix,
- RegisterClass GPR, AddrParams params> {
- // Unsigned immediate
- def _STR : A64I_LSunsigimm<size, v, {high_opc, 0b0},
- (outs), (ins GPR:$Rt, GPR64xsp:$Rn, params.uimm12:$UImm12),
- "str" # asmsuffix # "\t$Rt, [$Rn, $UImm12]",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt]> {
- let mayStore = 1;
- }
- def : InstAlias<"str" # asmsuffix # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "_STR") GPR:$Rt, GPR64xsp:$Rn, 0)>;
-
- def _LDR : A64I_LSunsigimm<size, v, {high_opc, 0b1},
- (outs GPR:$Rt), (ins GPR64xsp:$Rn, params.uimm12:$UImm12),
- "ldr" # asmsuffix # "\t$Rt, [$Rn, $UImm12]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
- }
- def : InstAlias<"ldr" # asmsuffix # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "_LDR") GPR:$Rt, GPR64xsp:$Rn, 0)>;
-
- // Register offset (four of these: load/store and Wm/Xm).
- let mayLoad = 1 in {
- def _Wm_RegOffset_LDR : A64I_LSregoff<size, v, {high_opc, 0b1}, 0b0,
- (outs GPR:$Rt),
- (ins GPR64xsp:$Rn, GPR32:$Rm, params.regextWm:$Ext),
- "ldr" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
-
- def _Xm_RegOffset_LDR : A64I_LSregoff<size, v, {high_opc, 0b1}, 0b1,
- (outs GPR:$Rt),
- (ins GPR64xsp:$Rn, GPR64:$Rm, params.regextXm:$Ext),
- "ldr" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
- }
- def : InstAlias<"ldr" # asmsuffix # " $Rt, [$Rn, $Rm]",
- (!cast<Instruction>(prefix # "_Xm_RegOffset_LDR") GPR:$Rt, GPR64xsp:$Rn,
- GPR64:$Rm, 2)>;
-
- let mayStore = 1 in {
- def _Wm_RegOffset_STR : A64I_LSregoff<size, v, {high_opc, 0b0}, 0b0,
- (outs), (ins GPR:$Rt, GPR64xsp:$Rn, GPR32:$Rm,
- params.regextWm:$Ext),
- "str" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt, ReadSt]>;
-
- def _Xm_RegOffset_STR : A64I_LSregoff<size, v, {high_opc, 0b0}, 0b1,
- (outs), (ins GPR:$Rt, GPR64xsp:$Rn, GPR64:$Rm,
- params.regextXm:$Ext),
- "str" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt, ReadSt]>;
- }
- def : InstAlias<"str" # asmsuffix # " $Rt, [$Rn, $Rm]",
- (!cast<Instruction>(prefix # "_Xm_RegOffset_STR") GPR:$Rt, GPR64xsp:$Rn,
- GPR64:$Rm, 2)>;
-
- // Unaligned immediate
- def _STUR : A64I_LSunalimm<size, v, {high_opc, 0b0},
- (outs), (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9),
- "stur" # asmsuffix # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt]> {
- let mayStore = 1;
- }
- def : InstAlias<"stur" # asmsuffix # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "_STUR") GPR:$Rt, GPR64xsp:$Rn, 0)>;
-
- def _LDUR : A64I_LSunalimm<size, v, {high_opc, 0b1},
- (outs GPR:$Rt), (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldur" # asmsuffix # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
- }
- def : InstAlias<"ldur" # asmsuffix # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "_LDUR") GPR:$Rt, GPR64xsp:$Rn, 0)>;
-
- // Post-indexed
- def _PostInd_STR : A64I_LSpostind<size, v, {high_opc, 0b0},
- (outs GPR64xsp:$Rn_wb),
- (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9),
- "str" # asmsuffix # "\t$Rt, [$Rn], $SImm9",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt]> {
- let Constraints = "$Rn = $Rn_wb";
- let mayStore = 1;
-
- // Decoder only needed for unpredictability checking (FIXME).
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
- def _PostInd_LDR : A64I_LSpostind<size, v, {high_opc, 0b1},
- (outs GPR:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldr" # asmsuffix # "\t$Rt, [$Rn], $SImm9",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
- // Pre-indexed
- def _PreInd_STR : A64I_LSpreind<size, v, {high_opc, 0b0},
- (outs GPR64xsp:$Rn_wb),
- (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9),
- "str" # asmsuffix # "\t$Rt, [$Rn, $SImm9]!",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt]> {
- let Constraints = "$Rn = $Rn_wb";
- let mayStore = 1;
-
- // Decoder only needed for unpredictability checking (FIXME).
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
- def _PreInd_LDR : A64I_LSpreind<size, v, {high_opc, 0b1},
- (outs GPR:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldr" # asmsuffix # "\t$Rt, [$Rn, $SImm9]!",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
-}
-
-// STRB/LDRB: First define the instructions
-defm LS8
- : A64I_LDRSTR_unsigned<"LS8", 0b00, 0b0, 0b0, "b", GPR32, byte_addrparams>;
-
-// STRH/LDRH
-defm LS16
- : A64I_LDRSTR_unsigned<"LS16", 0b01, 0b0, 0b0, "h", GPR32, hword_addrparams>;
-
-
-// STR/LDR to/from a W register
-defm LS32
- : A64I_LDRSTR_unsigned<"LS32", 0b10, 0b0, 0b0, "", GPR32, word_addrparams>;
-
-// STR/LDR to/from an X register
-defm LS64
- : A64I_LDRSTR_unsigned<"LS64", 0b11, 0b0, 0b0, "", GPR64, dword_addrparams>;
-
-let Predicates = [HasFPARMv8] in {
-// STR/LDR to/from a B register
-defm LSFP8
- : A64I_LDRSTR_unsigned<"LSFP8", 0b00, 0b1, 0b0, "", FPR8, byte_addrparams>;
-
-// STR/LDR to/from an H register
-defm LSFP16
- : A64I_LDRSTR_unsigned<"LSFP16", 0b01, 0b1, 0b0, "", FPR16, hword_addrparams>;
-
-// STR/LDR to/from an S register
-defm LSFP32
- : A64I_LDRSTR_unsigned<"LSFP32", 0b10, 0b1, 0b0, "", FPR32, word_addrparams>;
-// STR/LDR to/from a D register
-defm LSFP64
- : A64I_LDRSTR_unsigned<"LSFP64", 0b11, 0b1, 0b0, "", FPR64, dword_addrparams>;
-// STR/LDR to/from a Q register
-defm LSFP128
- : A64I_LDRSTR_unsigned<"LSFP128", 0b00, 0b1, 0b1, "", FPR128,
- qword_addrparams>;
-}
-
-//===------------------------------
-// 2.3 Signed loads
-//===------------------------------
-
-// Byte and half-word signed loads can both go into either an X or a W register,
-// so it's worth factoring out. Signed word loads don't fit because there is no
-// W version.
-multiclass A64I_LDR_signed<bits<2> size, string asmopcode, AddrParams params,
- string prefix> {
- // Unsigned offset
- def w : A64I_LSunsigimm<size, 0b0, 0b11,
- (outs GPR32:$Rt),
- (ins GPR64xsp:$Rn, params.uimm12:$UImm12),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $UImm12]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
- }
- def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # w) GPR32:$Rt, GPR64xsp:$Rn, 0)>;
-
- def x : A64I_LSunsigimm<size, 0b0, 0b10,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, params.uimm12:$UImm12),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $UImm12]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
- }
- def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # x) GPR64:$Rt, GPR64xsp:$Rn, 0)>;
-
- // Register offset
- let mayLoad = 1 in {
- def w_Wm_RegOffset : A64I_LSregoff<size, 0b0, 0b11, 0b0,
- (outs GPR32:$Rt),
- (ins GPR64xsp:$Rn, GPR32:$Rm, params.regextWm:$Ext),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
-
- def w_Xm_RegOffset : A64I_LSregoff<size, 0b0, 0b11, 0b1,
- (outs GPR32:$Rt),
- (ins GPR64xsp:$Rn, GPR64:$Rm, params.regextXm:$Ext),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
-
- def x_Wm_RegOffset : A64I_LSregoff<size, 0b0, 0b10, 0b0,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, GPR32:$Rm, params.regextWm:$Ext),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
-
- def x_Xm_RegOffset : A64I_LSregoff<size, 0b0, 0b10, 0b1,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, GPR64:$Rm, params.regextXm:$Ext),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
- }
- def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn, $Rm]",
- (!cast<Instruction>(prefix # "w_Xm_RegOffset") GPR32:$Rt, GPR64xsp:$Rn,
- GPR64:$Rm, 2)>;
-
- def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn, $Rm]",
- (!cast<Instruction>(prefix # "x_Xm_RegOffset") GPR64:$Rt, GPR64xsp:$Rn,
- GPR64:$Rm, 2)>;
-
-
- let mayLoad = 1 in {
- // Unaligned offset
- def w_U : A64I_LSunalimm<size, 0b0, 0b11,
- (outs GPR32:$Rt),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldurs" # asmopcode # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]>;
-
- def x_U : A64I_LSunalimm<size, 0b0, 0b10,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldurs" # asmopcode # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]>;
-
-
- // Post-indexed
- def w_PostInd : A64I_LSpostind<size, 0b0, 0b11,
- (outs GPR32:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldrs" # asmopcode # "\t$Rt, [$Rn], $SImm9",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
- def x_PostInd : A64I_LSpostind<size, 0b0, 0b10,
- (outs GPR64:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldrs" # asmopcode # "\t$Rt, [$Rn], $SImm9",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
- // Pre-indexed
- def w_PreInd : A64I_LSpreind<size, 0b0, 0b11,
- (outs GPR32:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]!",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
-
- def x_PreInd : A64I_LSpreind<size, 0b0, 0b10,
- (outs GPR64:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]!",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
- }
- } // let mayLoad = 1
-}
-
-// LDRSB
-defm LDRSB : A64I_LDR_signed<0b00, "b", byte_addrparams, "LDRSB">;
-// LDRSH
-defm LDRSH : A64I_LDR_signed<0b01, "h", hword_addrparams, "LDRSH">;
-
-// LDRSW: load a 32-bit register, sign-extending to 64-bits.
-def LDRSWx
- : A64I_LSunsigimm<0b10, 0b0, 0b10,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, word_uimm12:$UImm12),
- "ldrsw\t$Rt, [$Rn, $UImm12]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
-}
-def : InstAlias<"ldrsw $Rt, [$Rn]", (LDRSWx GPR64:$Rt, GPR64xsp:$Rn, 0)>;
-
-let mayLoad = 1 in {
- def LDRSWx_Wm_RegOffset : A64I_LSregoff<0b10, 0b0, 0b10, 0b0,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, GPR32:$Rm, word_Wm_regext:$Ext),
- "ldrsw\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
-
- def LDRSWx_Xm_RegOffset : A64I_LSregoff<0b10, 0b0, 0b10, 0b1,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, GPR64:$Rm, word_Xm_regext:$Ext),
- "ldrsw\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd, ReadLd]>;
-}
-def : InstAlias<"ldrsw $Rt, [$Rn, $Rm]",
- (LDRSWx_Xm_RegOffset GPR64:$Rt, GPR64xsp:$Rn, GPR64:$Rm, 2)>;
-
-
-def LDURSWx
- : A64I_LSunalimm<0b10, 0b0, 0b10,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldursw\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
-}
-def : InstAlias<"ldursw $Rt, [$Rn]", (LDURSWx GPR64:$Rt, GPR64xsp:$Rn, 0)>;
-
-def LDRSWx_PostInd
- : A64I_LSpostind<0b10, 0b0, 0b10,
- (outs GPR64:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldrsw\t$Rt, [$Rn], $SImm9",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
-}
-
-def LDRSWx_PreInd : A64I_LSpreind<0b10, 0b0, 0b10,
- (outs GPR64:$Rt, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldrsw\t$Rt, [$Rn, $SImm9]!",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeSingleIndexedInstruction";
-}
-
-//===------------------------------
-// 2.4 Prefetch operations
-//===------------------------------
-
-def PRFM : A64I_LSunsigimm<0b11, 0b0, 0b10, (outs),
- (ins prefetch_op:$Rt, GPR64xsp:$Rn, dword_uimm12:$UImm12),
- "prfm\t$Rt, [$Rn, $UImm12]",
- [], NoItinerary>,
- Sched<[WritePreLd, ReadPreLd]> {
- let mayLoad = 1;
-}
-def : InstAlias<"prfm $Rt, [$Rn]",
- (PRFM prefetch_op:$Rt, GPR64xsp:$Rn, 0)>;
-
-let mayLoad = 1 in {
- def PRFM_Wm_RegOffset : A64I_LSregoff<0b11, 0b0, 0b10, 0b0, (outs),
- (ins prefetch_op:$Rt, GPR64xsp:$Rn,
- GPR32:$Rm, dword_Wm_regext:$Ext),
- "prfm\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WritePreLd, ReadPreLd]>;
- def PRFM_Xm_RegOffset : A64I_LSregoff<0b11, 0b0, 0b10, 0b1, (outs),
- (ins prefetch_op:$Rt, GPR64xsp:$Rn,
- GPR64:$Rm, dword_Xm_regext:$Ext),
- "prfm\t$Rt, [$Rn, $Rm, $Ext]",
- [], NoItinerary>,
- Sched<[WritePreLd, ReadPreLd]>;
-}
-
-def : InstAlias<"prfm $Rt, [$Rn, $Rm]",
- (PRFM_Xm_RegOffset prefetch_op:$Rt, GPR64xsp:$Rn,
- GPR64:$Rm, 2)>;
-
-
-def PRFUM : A64I_LSunalimm<0b11, 0b0, 0b10, (outs),
- (ins prefetch_op:$Rt, GPR64xsp:$Rn, simm9:$SImm9),
- "prfum\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WritePreLd, ReadPreLd]> {
- let mayLoad = 1;
-}
-def : InstAlias<"prfum $Rt, [$Rn]",
- (PRFUM prefetch_op:$Rt, GPR64xsp:$Rn, 0)>;
-
-//===----------------------------------------------------------------------===//
-// Load-store register (unprivileged) instructions
-//===----------------------------------------------------------------------===//
-// Contains: LDTRB, LDTRH, LDTRSB, LDTRSH, LDTRSW, STTR, STTRB and STTRH
-
-// These instructions very much mirror the "unscaled immediate" loads, but since
-// there are no floating-point variants we need to split them out into their own
-// section to avoid instantiation of "ldtr d0, [sp]" etc.
-
-multiclass A64I_LDTRSTTR<bits<2> size, string asmsuffix, RegisterClass GPR,
- string prefix> {
- def _UnPriv_STR : A64I_LSunpriv<size, 0b0, 0b00,
- (outs), (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9),
- "sttr" # asmsuffix # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayStore = 1;
- }
-
- def : InstAlias<"sttr" # asmsuffix # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "_UnPriv_STR") GPR:$Rt, GPR64xsp:$Rn, 0)>;
-
- def _UnPriv_LDR : A64I_LSunpriv<size, 0b0, 0b01,
- (outs GPR:$Rt), (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldtr" # asmsuffix # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
- }
-
- def : InstAlias<"ldtr" # asmsuffix # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "_UnPriv_LDR") GPR:$Rt, GPR64xsp:$Rn, 0)>;
-
-}
-
-// STTRB/LDTRB: First define the instructions
-defm LS8 : A64I_LDTRSTTR<0b00, "b", GPR32, "LS8">;
-
-// STTRH/LDTRH
-defm LS16 : A64I_LDTRSTTR<0b01, "h", GPR32, "LS16">;
-
-// STTR/LDTR to/from a W register
-defm LS32 : A64I_LDTRSTTR<0b10, "", GPR32, "LS32">;
-
-// STTR/LDTR to/from an X register
-defm LS64 : A64I_LDTRSTTR<0b11, "", GPR64, "LS64">;
-
-// Now a class for the signed instructions that can go to either 32 or 64
-// bits...
-multiclass A64I_LDTR_signed<bits<2> size, string asmopcode, string prefix> {
- let mayLoad = 1 in {
- def w : A64I_LSunpriv<size, 0b0, 0b11,
- (outs GPR32:$Rt),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldtrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]>;
-
- def x : A64I_LSunpriv<size, 0b0, 0b10,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldtrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]>;
- }
-
- def : InstAlias<"ldtrs" # asmopcode # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "w") GPR32:$Rt, GPR64xsp:$Rn, 0)>;
-
- def : InstAlias<"ldtrs" # asmopcode # " $Rt, [$Rn]",
- (!cast<Instruction>(prefix # "x") GPR64:$Rt, GPR64xsp:$Rn, 0)>;
-
-}
-
-// LDTRSB
-defm LDTRSB : A64I_LDTR_signed<0b00, "b", "LDTRSB">;
-// LDTRSH
-defm LDTRSH : A64I_LDTR_signed<0b01, "h", "LDTRSH">;
-
-// And finally LDTRSW which only goes to 64 bits.
-def LDTRSWx : A64I_LSunpriv<0b10, 0b0, 0b10,
- (outs GPR64:$Rt),
- (ins GPR64xsp:$Rn, simm9:$SImm9),
- "ldtrsw\t$Rt, [$Rn, $SImm9]",
- [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayLoad = 1;
-}
-def : InstAlias<"ldtrsw $Rt, [$Rn]", (LDTRSWx GPR64:$Rt, GPR64xsp:$Rn, 0)>;
-
-//===----------------------------------------------------------------------===//
-// Load-store register pair (offset) instructions
-//===----------------------------------------------------------------------===//
-//
-// and
-//
-//===----------------------------------------------------------------------===//
-// Load-store register pair (post-indexed) instructions
-//===----------------------------------------------------------------------===//
-// Contains: STP, LDP, LDPSW
-//
-// and
-//
-//===----------------------------------------------------------------------===//
-// Load-store register pair (pre-indexed) instructions
-//===----------------------------------------------------------------------===//
-// Contains: STP, LDP, LDPSW
-//
-// and
-//
-//===----------------------------------------------------------------------===//
-// Load-store non-temporal register pair (offset) instructions
-//===----------------------------------------------------------------------===//
-// Contains: STNP, LDNP
-
-
-// Anything that creates an MCInst (Decoding, selection and AsmParsing) has to
-// know the access size via some means. An isolated operand does not have this
-// information unless told from here, which means we need separate tablegen
-// Operands for each access size. This multiclass takes care of instantiating
-// the correct template functions in the rest of the backend.
-
-multiclass offsets_simm7<string MemSize, string prefix> {
- // The bare signed 7-bit immediate is used in post-indexed instructions, but
- // because of the scaling performed a generic "simm7" operand isn't
- // appropriate here either.
- def simm7_asmoperand : AsmOperandClass {
- let Name = "SImm7_Scaled" # MemSize;
- let PredicateMethod = "isSImm7Scaled<" # MemSize # ">";
- let RenderMethod = "addSImm7ScaledOperands<" # MemSize # ">";
- let DiagnosticType = "LoadStoreSImm7_" # MemSize;
- }
-
- def simm7 : Operand<i64> {
- let PrintMethod = "printSImm7ScaledOperand<" # MemSize # ">";
- let ParserMatchClass = !cast<AsmOperandClass>(prefix # "simm7_asmoperand");
- }
-}
-
-defm word_ : offsets_simm7<"4", "word_">;
-defm dword_ : offsets_simm7<"8", "dword_">;
-defm qword_ : offsets_simm7<"16", "qword_">;
-
-multiclass A64I_LSPsimple<bits<2> opc, bit v, RegisterClass SomeReg,
- Operand simm7, string prefix> {
- def _STR : A64I_LSPoffset<opc, v, 0b0, (outs),
- (ins SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn, simm7:$SImm7),
- "stp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary>,
- Sched<[WriteLd, ReadLd]> {
- let mayStore = 1;
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
- def : InstAlias<"stp $Rt, $Rt2, [$Rn]",
- (!cast<Instruction>(prefix # "_STR") SomeReg:$Rt,
- SomeReg:$Rt2, GPR64xsp:$Rn, 0)>;
-
- def _LDR : A64I_LSPoffset<opc, v, 0b1,
- (outs SomeReg:$Rt, SomeReg:$Rt2),
- (ins GPR64xsp:$Rn, simm7:$SImm7),
- "ldp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
- def : InstAlias<"ldp $Rt, $Rt2, [$Rn]",
- (!cast<Instruction>(prefix # "_LDR") SomeReg:$Rt,
- SomeReg:$Rt2, GPR64xsp:$Rn, 0)>;
-
- def _PostInd_STR : A64I_LSPpostind<opc, v, 0b0,
- (outs GPR64xsp:$Rn_wb),
- (ins SomeReg:$Rt, SomeReg:$Rt2,
- GPR64xsp:$Rn,
- simm7:$SImm7),
- "stp\t$Rt, $Rt2, [$Rn], $SImm7",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt, ReadSt]> {
- let mayStore = 1;
- let Constraints = "$Rn = $Rn_wb";
-
- // Decoder only needed for unpredictability checking (FIXME).
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
-
- def _PostInd_LDR : A64I_LSPpostind<opc, v, 0b1,
- (outs SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm7:$SImm7),
- "ldp\t$Rt, $Rt2, [$Rn], $SImm7",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
-
- def _PreInd_STR : A64I_LSPpreind<opc, v, 0b0, (outs GPR64xsp:$Rn_wb),
- (ins SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn, simm7:$SImm7),
- "stp\t$Rt, $Rt2, [$Rn, $SImm7]!",
- [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt, ReadSt]> {
- let mayStore = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
-
- def _PreInd_LDR : A64I_LSPpreind<opc, v, 0b1,
- (outs SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn_wb),
- (ins GPR64xsp:$Rn, simm7:$SImm7),
- "ldp\t$Rt, $Rt2, [$Rn, $SImm7]!",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
-
- def _NonTemp_STR : A64I_LSPnontemp<opc, v, 0b0, (outs),
- (ins SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn, simm7:$SImm7),
- "stnp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary>,
- Sched<[WriteSt, ReadSt, ReadSt, ReadSt]> {
- let mayStore = 1;
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
- def : InstAlias<"stnp $Rt, $Rt2, [$Rn]",
- (!cast<Instruction>(prefix # "_NonTemp_STR") SomeReg:$Rt,
- SomeReg:$Rt2, GPR64xsp:$Rn, 0)>;
-
- def _NonTemp_LDR : A64I_LSPnontemp<opc, v, 0b1,
- (outs SomeReg:$Rt, SomeReg:$Rt2),
- (ins GPR64xsp:$Rn, simm7:$SImm7),
- "ldnp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let DecoderMethod = "DecodeLDSTPairInstruction";
- }
- def : InstAlias<"ldnp $Rt, $Rt2, [$Rn]",
- (!cast<Instruction>(prefix # "_NonTemp_LDR") SomeReg:$Rt,
- SomeReg:$Rt2, GPR64xsp:$Rn, 0)>;
-
-}
-
-
-defm LSPair32 : A64I_LSPsimple<0b00, 0b0, GPR32, word_simm7, "LSPair32">;
-defm LSPair64 : A64I_LSPsimple<0b10, 0b0, GPR64, dword_simm7, "LSPair64">;
-
-let Predicates = [HasFPARMv8] in {
-defm LSFPPair32 : A64I_LSPsimple<0b00, 0b1, FPR32, word_simm7, "LSFPPair32">;
-defm LSFPPair64 : A64I_LSPsimple<0b01, 0b1, FPR64, dword_simm7, "LSFPPair64">;
-defm LSFPPair128 : A64I_LSPsimple<0b10, 0b1, FPR128, qword_simm7,
- "LSFPPair128">;
-}
-
-
-def LDPSWx : A64I_LSPoffset<0b01, 0b0, 0b1,
- (outs GPR64:$Rt, GPR64:$Rt2),
- (ins GPR64xsp:$Rn, word_simm7:$SImm7),
- "ldpsw\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary>,
- Sched<[WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let DecoderMethod = "DecodeLDSTPairInstruction";
-}
-def : InstAlias<"ldpsw $Rt, $Rt2, [$Rn]",
- (LDPSWx GPR64:$Rt, GPR64:$Rt2, GPR64xsp:$Rn, 0)>;
-
-def LDPSWx_PostInd : A64I_LSPpostind<0b01, 0b0, 0b1,
- (outs GPR64:$Rt, GPR64:$Rt2, GPR64:$Rn_wb),
- (ins GPR64xsp:$Rn, word_simm7:$SImm7),
- "ldpsw\t$Rt, $Rt2, [$Rn], $SImm7",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeLDSTPairInstruction";
-}
-
-def LDPSWx_PreInd : A64I_LSPpreind<0b01, 0b0, 0b1,
- (outs GPR64:$Rt, GPR64:$Rt2, GPR64:$Rn_wb),
- (ins GPR64xsp:$Rn, word_simm7:$SImm7),
- "ldpsw\t$Rt, $Rt2, [$Rn, $SImm7]!",
- [], NoItinerary>,
- Sched<[WriteLd, WriteLd, WriteLd, ReadLd]> {
- let mayLoad = 1;
- let Constraints = "$Rn = $Rn_wb";
- let DecoderMethod = "DecodeLDSTPairInstruction";
-}
-
-//===----------------------------------------------------------------------===//
-// Logical (immediate) instructions
-//===----------------------------------------------------------------------===//
-// Contains: AND, ORR, EOR, ANDS, + aliases TST, MOV
-
-multiclass logical_imm_operands<string prefix, string note,
- int size, ValueType VT> {
- def _asmoperand : AsmOperandClass {
- let Name = "LogicalImm" # note # size;
- let PredicateMethod = "isLogicalImm" # note # "<" # size # ">";
- let RenderMethod = "addLogicalImmOperands<" # size # ">";
- let DiagnosticType = "LogicalSecondSource";
- }
-
- def _operand
- : Operand<VT>, ComplexPattern<VT, 1, "SelectLogicalImm", [imm]> {
- let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_asmoperand");
- let PrintMethod = "printLogicalImmOperand<" # size # ">";
- let DecoderMethod = "DecodeLogicalImmOperand<" # size # ">";
- }
-}
-
-defm logical_imm32 : logical_imm_operands<"logical_imm32", "", 32, i32>;
-defm logical_imm64 : logical_imm_operands<"logical_imm64", "", 64, i64>;
-
-// The mov versions only differ in assembly parsing, where they
-// exclude values representable with either MOVZ or MOVN.
-defm logical_imm32_mov
- : logical_imm_operands<"logical_imm32_mov", "MOV", 32, i32>;
-defm logical_imm64_mov
- : logical_imm_operands<"logical_imm64_mov", "MOV", 64, i64>;
-
-
-multiclass A64I_logimmSizes<bits<2> opc, string asmop, SDNode opnode> {
- def wwi : A64I_logicalimm<0b0, opc, (outs GPR32wsp:$Rd),
- (ins GPR32:$Rn, logical_imm32_operand:$Imm),
- !strconcat(asmop, "\t$Rd, $Rn, $Imm"),
- [(set i32:$Rd,
- (opnode i32:$Rn, logical_imm32_operand:$Imm))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU]>;
-
- def xxi : A64I_logicalimm<0b1, opc, (outs GPR64xsp:$Rd),
- (ins GPR64:$Rn, logical_imm64_operand:$Imm),
- !strconcat(asmop, "\t$Rd, $Rn, $Imm"),
- [(set i64:$Rd,
- (opnode i64:$Rn, logical_imm64_operand:$Imm))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU]>;
-}
-
-defm AND : A64I_logimmSizes<0b00, "and", and>;
-defm ORR : A64I_logimmSizes<0b01, "orr", or>;
-defm EOR : A64I_logimmSizes<0b10, "eor", xor>;
-
-let Defs = [NZCV] in {
- def ANDSwwi : A64I_logicalimm<0b0, 0b11, (outs GPR32:$Rd),
- (ins GPR32:$Rn, logical_imm32_operand:$Imm),
- "ands\t$Rd, $Rn, $Imm",
- [], NoItinerary>,
- Sched<[WriteALU, ReadALU]>;
-
- def ANDSxxi : A64I_logicalimm<0b1, 0b11, (outs GPR64:$Rd),
- (ins GPR64:$Rn, logical_imm64_operand:$Imm),
- "ands\t$Rd, $Rn, $Imm",
- [], NoItinerary>,
- Sched<[WriteALU, ReadALU]>;
-}
-
-def : InstAlias<"tst $Rn, $Imm",
- (ANDSwwi WZR, GPR32:$Rn, logical_imm32_operand:$Imm)>;
-def : InstAlias<"tst $Rn, $Imm",
- (ANDSxxi XZR, GPR64:$Rn, logical_imm64_operand:$Imm)>;
-// FIXME: these sometimes are canonical.
-def : InstAlias<"mov $Rd, $Imm",
- (ORRwwi GPR32wsp:$Rd, WZR, logical_imm32_mov_operand:$Imm), 0>;
-def : InstAlias<"mov $Rd, $Imm",
- (ORRxxi GPR64xsp:$Rd, XZR, logical_imm64_mov_operand:$Imm), 0>;
-
-//===----------------------------------------------------------------------===//
-// Logical (shifted register) instructions
-//===----------------------------------------------------------------------===//
-// Contains: AND, BIC, ORR, ORN, EOR, EON, ANDS, BICS + aliases TST, MVN, MOV
-
-// Operand for optimizing (icmp (and LHS, RHS), 0, SomeCode). In theory "ANDS"
-// behaves differently for unsigned comparisons, so we defensively only allow
-// signed or n/a as the operand. In practice "unsigned greater than 0" is "not
-// equal to 0" and LLVM gives us this.
-def signed_cond : PatLeaf<(cond), [{
- return !isUnsignedIntSetCC(N->get());
-}]>;
-
-
-// These instructions share their "shift" operands with add/sub (shifted
-// register instructions). They are defined there.
-
-// N.b. the commutable parameter is just !N. It will be first against the wall
-// when the revolution comes.
-multiclass logical_shifts<string prefix, bit sf, bits<2> opc,
- bit N, bit commutable,
- string asmop, SDPatternOperator opfrag, ValueType ty,
- RegisterClass GPR, list<Register> defs> {
- let isCommutable = commutable, Defs = defs in {
- def _lsl : A64I_logicalshift<sf, opc, 0b00, N,
- (outs GPR:$Rd),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6),
- !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"),
- [(set ty:$Rd, (opfrag ty:$Rn, (shl ty:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6))
- )],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _lsr : A64I_logicalshift<sf, opc, 0b01, N,
- (outs GPR:$Rd),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("lsr_operand_" # ty):$Imm6),
- !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"),
- [(set ty:$Rd, (opfrag ty:$Rn, (srl ty:$Rm,
- !cast<Operand>("lsr_operand_" # ty):$Imm6))
- )],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _asr : A64I_logicalshift<sf, opc, 0b10, N,
- (outs GPR:$Rd),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("asr_operand_" # ty):$Imm6),
- !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"),
- [(set ty:$Rd, (opfrag ty:$Rn, (sra ty:$Rm,
- !cast<Operand>("asr_operand_" # ty):$Imm6))
- )],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _ror : A64I_logicalshift<sf, opc, 0b11, N,
- (outs GPR:$Rd),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("ror_operand_" # ty):$Imm6),
- !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"),
- [(set ty:$Rd, (opfrag ty:$Rn, (rotr ty:$Rm,
- !cast<Operand>("ror_operand_" # ty):$Imm6))
- )],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
- }
-
- def _noshift
- : InstAlias<!strconcat(asmop, " $Rd, $Rn, $Rm"),
- (!cast<Instruction>(prefix # "_lsl") GPR:$Rd, GPR:$Rn,
- GPR:$Rm, 0)>;
-
- def : Pat<(opfrag ty:$Rn, ty:$Rm),
- (!cast<Instruction>(prefix # "_lsl") $Rn, $Rm, 0)>;
-}
-
-multiclass logical_sizes<string prefix, bits<2> opc, bit N, bit commutable,
- string asmop, SDPatternOperator opfrag,
- list<Register> defs> {
- defm xxx : logical_shifts<prefix # "xxx", 0b1, opc, N,
- commutable, asmop, opfrag, i64, GPR64, defs>;
- defm www : logical_shifts<prefix # "www", 0b0, opc, N,
- commutable, asmop, opfrag, i32, GPR32, defs>;
-}
-
-
-defm AND : logical_sizes<"AND", 0b00, 0b0, 0b1, "and", and, []>;
-defm ORR : logical_sizes<"ORR", 0b01, 0b0, 0b1, "orr", or, []>;
-defm EOR : logical_sizes<"EOR", 0b10, 0b0, 0b1, "eor", xor, []>;
-defm ANDS : logical_sizes<"ANDS", 0b11, 0b0, 0b1, "ands",
- PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs),
- [{ (void)N; return false; }]>,
- [NZCV]>;
-
-defm BIC : logical_sizes<"BIC", 0b00, 0b1, 0b0, "bic",
- PatFrag<(ops node:$lhs, node:$rhs),
- (and node:$lhs, (not node:$rhs))>, []>;
-defm ORN : logical_sizes<"ORN", 0b01, 0b1, 0b0, "orn",
- PatFrag<(ops node:$lhs, node:$rhs),
- (or node:$lhs, (not node:$rhs))>, []>;
-defm EON : logical_sizes<"EON", 0b10, 0b1, 0b0, "eon",
- PatFrag<(ops node:$lhs, node:$rhs),
- (xor node:$lhs, (not node:$rhs))>, []>;
-defm BICS : logical_sizes<"BICS", 0b11, 0b1, 0b0, "bics",
- PatFrag<(ops node:$lhs, node:$rhs),
- (and node:$lhs, (not node:$rhs)),
- [{ (void)N; return false; }]>,
- [NZCV]>;
-
-multiclass tst_shifts<string prefix, bit sf, ValueType ty, RegisterClass GPR> {
- let isCommutable = 1, Rd = 0b11111, Defs = [NZCV] in {
- def _lsl : A64I_logicalshift<sf, 0b11, 0b00, 0b0,
- (outs),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6),
- "tst\t$Rn, $Rm, $Imm6",
- [(set NZCV, (A64setcc (and ty:$Rn, (shl ty:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6)),
- 0, signed_cond))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
-
- def _lsr : A64I_logicalshift<sf, 0b11, 0b01, 0b0,
- (outs),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("lsr_operand_" # ty):$Imm6),
- "tst\t$Rn, $Rm, $Imm6",
- [(set NZCV, (A64setcc (and ty:$Rn, (srl ty:$Rm,
- !cast<Operand>("lsr_operand_" # ty):$Imm6)),
- 0, signed_cond))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _asr : A64I_logicalshift<sf, 0b11, 0b10, 0b0,
- (outs),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("asr_operand_" # ty):$Imm6),
- "tst\t$Rn, $Rm, $Imm6",
- [(set NZCV, (A64setcc (and ty:$Rn, (sra ty:$Rm,
- !cast<Operand>("asr_operand_" # ty):$Imm6)),
- 0, signed_cond))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _ror : A64I_logicalshift<sf, 0b11, 0b11, 0b0,
- (outs),
- (ins GPR:$Rn, GPR:$Rm,
- !cast<Operand>("ror_operand_" # ty):$Imm6),
- "tst\t$Rn, $Rm, $Imm6",
- [(set NZCV, (A64setcc (and ty:$Rn, (rotr ty:$Rm,
- !cast<Operand>("ror_operand_" # ty):$Imm6)),
- 0, signed_cond))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
- }
-
- def _noshift : InstAlias<"tst $Rn, $Rm",
- (!cast<Instruction>(prefix # "_lsl") GPR:$Rn, GPR:$Rm, 0)>;
-
- def : Pat<(A64setcc (and ty:$Rn, ty:$Rm), 0, signed_cond),
- (!cast<Instruction>(prefix # "_lsl") $Rn, $Rm, 0)>;
-}
-
-defm TSTxx : tst_shifts<"TSTxx", 0b1, i64, GPR64>;
-defm TSTww : tst_shifts<"TSTww", 0b0, i32, GPR32>;
-
-
-multiclass mvn_shifts<string prefix, bit sf, ValueType ty, RegisterClass GPR> {
- let isCommutable = 0, Rn = 0b11111 in {
- def _lsl : A64I_logicalshift<sf, 0b01, 0b00, 0b1,
- (outs GPR:$Rd),
- (ins GPR:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6),
- "mvn\t$Rd, $Rm, $Imm6",
- [(set ty:$Rd, (not (shl ty:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6)))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
-
- def _lsr : A64I_logicalshift<sf, 0b01, 0b01, 0b1,
- (outs GPR:$Rd),
- (ins GPR:$Rm,
- !cast<Operand>("lsr_operand_" # ty):$Imm6),
- "mvn\t$Rd, $Rm, $Imm6",
- [(set ty:$Rd, (not (srl ty:$Rm,
- !cast<Operand>("lsr_operand_" # ty):$Imm6)))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _asr : A64I_logicalshift<sf, 0b01, 0b10, 0b1,
- (outs GPR:$Rd),
- (ins GPR:$Rm,
- !cast<Operand>("asr_operand_" # ty):$Imm6),
- "mvn\t$Rd, $Rm, $Imm6",
- [(set ty:$Rd, (not (sra ty:$Rm,
- !cast<Operand>("asr_operand_" # ty):$Imm6)))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
-
- def _ror : A64I_logicalshift<sf, 0b01, 0b11, 0b1,
- (outs GPR:$Rd),
- (ins GPR:$Rm,
- !cast<Operand>("ror_operand_" # ty):$Imm6),
- "mvn\t$Rd, $Rm, $Imm6",
- [(set ty:$Rd, (not (rotr ty:$Rm,
- !cast<Operand>("lsl_operand_" # ty):$Imm6)))],
- NoItinerary>,
- Sched<[WriteALU, ReadALU, ReadALU]>;
- }
-
- def _noshift : InstAlias<"mvn $Rn, $Rm",
- (!cast<Instruction>(prefix # "_lsl") GPR:$Rn, GPR:$Rm, 0)>;
-
- def : Pat<(not ty:$Rm),
- (!cast<Instruction>(prefix # "_lsl") $Rm, 0)>;
-}
-
-defm MVNxx : mvn_shifts<"MVNxx", 0b1, i64, GPR64>;
-defm MVNww : mvn_shifts<"MVNww", 0b0, i32, GPR32>;
-
-def MOVxx :InstAlias<"mov $Rd, $Rm", (ORRxxx_lsl GPR64:$Rd, XZR, GPR64:$Rm, 0)>;
-def MOVww :InstAlias<"mov $Rd, $Rm", (ORRwww_lsl GPR32:$Rd, WZR, GPR32:$Rm, 0)>;
-
-//===----------------------------------------------------------------------===//
-// Move wide (immediate) instructions
-//===----------------------------------------------------------------------===//
-// Contains: MOVN, MOVZ, MOVK + MOV aliases
-
-// A wide variety of different relocations are needed for variants of these
-// instructions, so it turns out that we need a different operand for all of
-// them.
-multiclass movw_operands<string prefix, string instname, int width> {
- def _imm_asmoperand : AsmOperandClass {
- let Name = instname # width # "Shifted" # shift;
- let PredicateMethod = "is" # instname # width # "Imm";
- let RenderMethod = "addMoveWideImmOperands";
- let ParserMethod = "ParseImmWithLSLOperand";
- let DiagnosticType = "MOVWUImm16";
- }
-
- def _imm : Operand<i64> {
- let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_imm_asmoperand");
- let PrintMethod = "printMoveWideImmOperand";
- let EncoderMethod = "getMoveWideImmOpValue";
- let DecoderMethod = "DecodeMoveWideImmOperand<" # width # ">";
-
- let MIOperandInfo = (ops uimm16:$UImm16, imm:$Shift);
- }
-}
-
-defm movn32 : movw_operands<"movn32", "MOVN", 32>;
-defm movn64 : movw_operands<"movn64", "MOVN", 64>;
-defm movz32 : movw_operands<"movz32", "MOVZ", 32>;
-defm movz64 : movw_operands<"movz64", "MOVZ", 64>;
-defm movk32 : movw_operands<"movk32", "MOVK", 32>;
-defm movk64 : movw_operands<"movk64", "MOVK", 64>;
-
-multiclass A64I_movwSizes<bits<2> opc, string asmop, dag ins32bit,
- dag ins64bit> {
-
- def wii : A64I_movw<0b0, opc, (outs GPR32:$Rd), ins32bit,
- !strconcat(asmop, "\t$Rd, $FullImm"),
- [], NoItinerary>,
- Sched<[WriteALU]> {
- bits<18> FullImm;
- let UImm16 = FullImm{15-0};
- let Shift = FullImm{17-16};
- }
-
- def xii : A64I_movw<0b1, opc, (outs GPR64:$Rd), ins64bit,
- !strconcat(asmop, "\t$Rd, $FullImm"),
- [], NoItinerary>,
- Sched<[WriteALU]> {
- bits<18> FullImm;
- let UImm16 = FullImm{15-0};
- let Shift = FullImm{17-16};
- }
-}
-
-let isMoveImm = 1, isReMaterializable = 1,
- isAsCheapAsAMove = 1, hasSideEffects = 0 in {
- defm MOVN : A64I_movwSizes<0b00, "movn",
- (ins movn32_imm:$FullImm),
- (ins movn64_imm:$FullImm)>;
-
- // Some relocations are able to convert between a MOVZ and a MOVN. If these
- // are applied the instruction must be emitted with the corresponding bits as
- // 0, which means a MOVZ needs to override that bit from the default.
- let PostEncoderMethod = "fixMOVZ" in
- defm MOVZ : A64I_movwSizes<0b10, "movz",
- (ins movz32_imm:$FullImm),
- (ins movz64_imm:$FullImm)>;
-}
-
-let Constraints = "$src = $Rd",
- SchedRW = [WriteALU, ReadALU] in
-defm MOVK : A64I_movwSizes<0b11, "movk",
- (ins GPR32:$src, movk32_imm:$FullImm),
- (ins GPR64:$src, movk64_imm:$FullImm)>;
-
-
-// And now the "MOV" aliases. These also need their own operands because what
-// they accept is completely different to what the base instructions accept.
-multiclass movalias_operand<string prefix, string basename,
- string immpredicate, int width> {
- def _asmoperand : AsmOperandClass {
- let Name = basename # width # "MovAlias";
- let PredicateMethod
- = "isMoveWideMovAlias<" # width # ", A64Imms::" # immpredicate # ">";
- let RenderMethod
- = "addMoveWideMovAliasOperands<" # width # ", "
- # "A64Imms::" # immpredicate # ">";
- }
-
- def _movimm : Operand<i64> {
- let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_asmoperand");
-
- let MIOperandInfo = (ops uimm16:$UImm16, imm:$Shift);
- }
-}
-
-defm movz32 : movalias_operand<"movz32", "MOVZ", "isMOVZImm", 32>;
-defm movz64 : movalias_operand<"movz64", "MOVZ", "isMOVZImm", 64>;
-defm movn32 : movalias_operand<"movn32", "MOVN", "isOnlyMOVNImm", 32>;
-defm movn64 : movalias_operand<"movn64", "MOVN", "isOnlyMOVNImm", 64>;
-
-// FIXME: these are officially canonical aliases, but TableGen is too limited to
-// print them at the moment. I believe in this case an "AliasPredicate" method
-// will need to be implemented. to allow it, as well as the more generally
-// useful handling of non-register, non-constant operands.
-class movalias<Instruction INST, RegisterClass GPR, Operand operand>
- : InstAlias<"mov $Rd, $FullImm", (INST GPR:$Rd, operand:$FullImm), 0>;
-
-def : movalias<MOVZwii, GPR32, movz32_movimm>;
-def : movalias<MOVZxii, GPR64, movz64_movimm>;
-def : movalias<MOVNwii, GPR32, movn32_movimm>;
-def : movalias<MOVNxii, GPR64, movn64_movimm>;
-
-def movw_addressref_g0 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<0>">;
-def movw_addressref_g1 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<1>">;
-def movw_addressref_g2 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<2>">;
-def movw_addressref_g3 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<3>">;
-
-def : Pat<(A64WrapperLarge movw_addressref_g3:$G3, movw_addressref_g2:$G2,
- movw_addressref_g1:$G1, movw_addressref_g0:$G0),
- (MOVKxii (MOVKxii (MOVKxii (MOVZxii movw_addressref_g3:$G3),
- movw_addressref_g2:$G2),
- movw_addressref_g1:$G1),
- movw_addressref_g0:$G0)>;
-
-//===----------------------------------------------------------------------===//
-// PC-relative addressing instructions
-//===----------------------------------------------------------------------===//
-// Contains: ADR, ADRP
-
-def adr_label : Operand<i64> {
- let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_adr_prel>";
-
- // This label is a 21-bit offset from PC, unscaled
- let PrintMethod = "printLabelOperand<21, 1>";
- let ParserMatchClass = label_asmoperand<21, 1>;
- let OperandType = "OPERAND_PCREL";
-}
-
-def adrp_label_asmoperand : AsmOperandClass {
- let Name = "AdrpLabel";
- let RenderMethod = "addLabelOperands<21, 4096>";
- let DiagnosticType = "Label";
-}
-
-def adrp_label : Operand<i64> {
- let EncoderMethod = "getAdrpLabelOpValue";
-
- // This label is a 21-bit offset from PC, scaled by the page-size: 4096.
- let PrintMethod = "printLabelOperand<21, 4096>";
- let ParserMatchClass = adrp_label_asmoperand;
- let OperandType = "OPERAND_PCREL";
-}
-
-let hasSideEffects = 0 in {
- def ADRxi : A64I_PCADR<0b0, (outs GPR64:$Rd), (ins adr_label:$Label),
- "adr\t$Rd, $Label", [], NoItinerary>,
- Sched<[WriteALUs]>;
-
- def ADRPxi : A64I_PCADR<0b1, (outs GPR64:$Rd), (ins adrp_label:$Label),
- "adrp\t$Rd, $Label", [], NoItinerary>,
- Sched<[WriteALUs]>;
-}
-
-//===----------------------------------------------------------------------===//
-// System instructions
-//===----------------------------------------------------------------------===//
-// Contains: HINT, CLREX, DSB, DMB, ISB, MSR, SYS, SYSL, MRS
-// + aliases IC, DC, AT, TLBI, NOP, YIELD, WFE, WFI, SEV, SEVL
-
-// Op1 and Op2 fields are sometimes simple 3-bit unsigned immediate values.
-def uimm3_asmoperand : AsmOperandClass {
- let Name = "UImm3";
- let PredicateMethod = "isUImm<3>";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "UImm3";
-}
-
-def uimm3 : Operand<i32> {
- let ParserMatchClass = uimm3_asmoperand;
-}
-
-// The HINT alias can accept a simple unsigned 7-bit immediate.
-def uimm7_asmoperand : AsmOperandClass {
- let Name = "UImm7";
- let PredicateMethod = "isUImm<7>";
- let RenderMethod = "addImmOperands";
- let DiagnosticType = "UImm7";
-}
-
-def uimm7 : Operand<i32> {
- let ParserMatchClass = uimm7_asmoperand;
-}
-
-// Multiclass namedimm is defined with the prefetch operands. Most of these fit
-// into the NamedImmMapper scheme well: they either accept a named operand or
-// any immediate under a particular value (which may be 0, implying no immediate
-// is allowed).
-defm dbarrier : namedimm<"dbarrier", "A64DB::DBarrierMapper">;
-defm isb : namedimm<"isb", "A64ISB::ISBMapper">;
-defm ic : namedimm<"ic", "A64IC::ICMapper">;
-defm dc : namedimm<"dc", "A64DC::DCMapper">;
-defm at : namedimm<"at", "A64AT::ATMapper">;
-defm tlbi : namedimm<"tlbi", "A64TLBI::TLBIMapper">;
-
-// However, MRS and MSR are more complicated for a few reasons:
-// * There are ~1000 generic names S3_<op1>_<CRn>_<CRm>_<Op2> which have an
-// implementation-defined effect
-// * Most registers are shared, but some are read-only or write-only.
-// * There is a variant of MSR which accepts the same register name (SPSel),
-// but which would have a different encoding.
-
-// In principle these could be resolved in with more complicated subclasses of
-// NamedImmMapper, however that imposes an overhead on other "named
-// immediates". Both in concrete terms with virtual tables and in unnecessary
-// abstraction.
-
-// The solution adopted here is to take the MRS/MSR Mappers out of the usual
-// hierarchy (they're not derived from NamedImmMapper) and to add logic for
-// their special situation.
-def mrs_asmoperand : AsmOperandClass {
- let Name = "MRS";
- let ParserMethod = "ParseSysRegOperand";
- let DiagnosticType = "MRS";
-}
-
-def mrs_op : Operand<i32> {
- let ParserMatchClass = mrs_asmoperand;
- let PrintMethod = "printMRSOperand";
- let DecoderMethod = "DecodeMRSOperand";
-}
-
-def msr_asmoperand : AsmOperandClass {
- let Name = "MSRWithReg";
-
- // Note that SPSel is valid for both this and the pstate operands, but with
- // different immediate encodings. This is why these operands provide a string
- // AArch64Operand rather than an immediate. The overlap is small enough that
- // it could be resolved with hackery now, but who can say in future?
- let ParserMethod = "ParseSysRegOperand";
- let DiagnosticType = "MSR";
-}
-
-def msr_op : Operand<i32> {
- let ParserMatchClass = msr_asmoperand;
- let PrintMethod = "printMSROperand";
- let DecoderMethod = "DecodeMSROperand";
-}
-
-def pstate_asmoperand : AsmOperandClass {
- let Name = "MSRPState";
- // See comment above about parser.
- let ParserMethod = "ParseSysRegOperand";
- let DiagnosticType = "MSR";
-}
-
-def pstate_op : Operand<i32> {
- let ParserMatchClass = pstate_asmoperand;
- let PrintMethod = "printNamedImmOperand<A64PState::PStateMapper>";
- let DecoderMethod = "DecodeNamedImmOperand<A64PState::PStateMapper>";
-}
-
-// When <CRn> is specified, an assembler should accept something like "C4", not
-// the usual "#4" immediate.
-def CRx_asmoperand : AsmOperandClass {
- let Name = "CRx";
- let PredicateMethod = "isUImm<4>";
- let RenderMethod = "addImmOperands";
- let ParserMethod = "ParseCRxOperand";
- // Diagnostics are handled in all cases by ParseCRxOperand.
-}
-
-def CRx : Operand<i32> {
- let ParserMatchClass = CRx_asmoperand;
- let PrintMethod = "printCRxOperand";
-}
-
-
-// Finally, we can start defining the instructions.
-
-// HINT is straightforward, with a few aliases.
-def HINTi : A64I_system<0b0, (outs), (ins uimm7:$UImm7), "hint\t$UImm7",
- [], NoItinerary> {
- bits<7> UImm7;
- let CRm = UImm7{6-3};
- let Op2 = UImm7{2-0};
-
- let Op0 = 0b00;
- let Op1 = 0b011;
- let CRn = 0b0010;
- let Rt = 0b11111;
-}
-
-def : InstAlias<"nop", (HINTi 0)>;
-def : InstAlias<"yield", (HINTi 1)>;
-def : InstAlias<"wfe", (HINTi 2)>;
-def : InstAlias<"wfi", (HINTi 3)>;
-def : InstAlias<"sev", (HINTi 4)>;
-def : InstAlias<"sevl", (HINTi 5)>;
-
-// Quite a few instructions then follow a similar pattern of fixing common
-// fields in the bitpattern, we'll define a helper-class for them.
-class simple_sys<bits<2> op0, bits<3> op1, bits<4> crn, bits<3> op2,
- Operand operand, string asmop>
- : A64I_system<0b0, (outs), (ins operand:$CRm), !strconcat(asmop, "\t$CRm"),
- [], NoItinerary> {
- let Op0 = op0;
- let Op1 = op1;
- let CRn = crn;
- let Op2 = op2;
- let Rt = 0b11111;
-}
-
-
-def CLREXi : simple_sys<0b00, 0b011, 0b0011, 0b010, uimm4, "clrex">;
-def DSBi : simple_sys<0b00, 0b011, 0b0011, 0b100, dbarrier_op, "dsb">;
-def DMBi : simple_sys<0b00, 0b011, 0b0011, 0b101, dbarrier_op, "dmb">;
-def ISBi : simple_sys<0b00, 0b011, 0b0011, 0b110, isb_op, "isb">;
-
-def : InstAlias<"clrex", (CLREXi 0b1111)>;
-def : InstAlias<"isb", (ISBi 0b1111)>;
-
-// (DMBi 0xb) is a "DMB ISH" instruciton, appropriate for Linux SMP
-// configurations at least.
-def : Pat<(atomic_fence imm, imm), (DMBi 0xb)>;
-
-// Any SYS bitpattern can be represented with a complex and opaque "SYS"
-// instruction.
-def SYSiccix : A64I_system<0b0, (outs),
- (ins uimm3:$Op1, CRx:$CRn, CRx:$CRm,
- uimm3:$Op2, GPR64:$Rt),
- "sys\t$Op1, $CRn, $CRm, $Op2, $Rt",
- [], NoItinerary> {
- let Op0 = 0b01;
-}
-
-// You can skip the Xt argument whether it makes sense or not for the generic
-// SYS instruction.
-def : InstAlias<"sys $Op1, $CRn, $CRm, $Op2",
- (SYSiccix uimm3:$Op1, CRx:$CRn, CRx:$CRm, uimm3:$Op2, XZR)>;
-
-
-// But many have aliases, which obviously don't fit into
-class SYSalias<dag ins, string asmstring>
- : A64I_system<0b0, (outs), ins, asmstring, [], NoItinerary> {
- let isAsmParserOnly = 1;
-
- bits<14> SysOp;
- let Op0 = 0b01;
- let Op1 = SysOp{13-11};
- let CRn = SysOp{10-7};
- let CRm = SysOp{6-3};
- let Op2 = SysOp{2-0};
-}
-
-def ICix : SYSalias<(ins ic_op:$SysOp, GPR64:$Rt), "ic\t$SysOp, $Rt">;
-
-def ICi : SYSalias<(ins ic_op:$SysOp), "ic\t$SysOp"> {
- let Rt = 0b11111;
-}
-
-def DCix : SYSalias<(ins dc_op:$SysOp, GPR64:$Rt), "dc\t$SysOp, $Rt">;
-def ATix : SYSalias<(ins at_op:$SysOp, GPR64:$Rt), "at\t$SysOp, $Rt">;
-
-def TLBIix : SYSalias<(ins tlbi_op:$SysOp, GPR64:$Rt), "tlbi\t$SysOp, $Rt">;
-
-def TLBIi : SYSalias<(ins tlbi_op:$SysOp), "tlbi\t$SysOp"> {
- let Rt = 0b11111;
-}
-
-
-def SYSLxicci : A64I_system<0b1, (outs GPR64:$Rt),
- (ins uimm3:$Op1, CRx:$CRn, CRx:$CRm, uimm3:$Op2),
- "sysl\t$Rt, $Op1, $CRn, $CRm, $Op2",
- [], NoItinerary> {
- let Op0 = 0b01;
-}
-
-// The instructions themselves are rather simple for MSR and MRS.
-def MSRix : A64I_system<0b0, (outs), (ins msr_op:$SysReg, GPR64:$Rt),
- "msr\t$SysReg, $Rt", [], NoItinerary> {
- bits<16> SysReg;
- let Op0 = SysReg{15-14};
- let Op1 = SysReg{13-11};
- let CRn = SysReg{10-7};
- let CRm = SysReg{6-3};
- let Op2 = SysReg{2-0};
-}
-
-def MRSxi : A64I_system<0b1, (outs GPR64:$Rt), (ins mrs_op:$SysReg),
- "mrs\t$Rt, $SysReg", [], NoItinerary> {
- bits<16> SysReg;
- let Op0 = SysReg{15-14};
- let Op1 = SysReg{13-11};
- let CRn = SysReg{10-7};
- let CRm = SysReg{6-3};
- let Op2 = SysReg{2-0};
-}
-
-def MSRii : A64I_system<0b0, (outs), (ins pstate_op:$PState, uimm4:$CRm),
- "msr\t$PState, $CRm", [], NoItinerary> {
- bits<6> PState;
-
- let Op0 = 0b00;
- let Op1 = PState{5-3};
- let CRn = 0b0100;
- let Op2 = PState{2-0};
- let Rt = 0b11111;
-}
-
-//===----------------------------------------------------------------------===//
-// Test & branch (immediate) instructions
-//===----------------------------------------------------------------------===//
-// Contains: TBZ, TBNZ
-
-// The bit to test is a simple unsigned 6-bit immediate in the X-register
-// versions.
-def uimm6 : Operand<i64> {
- let ParserMatchClass = uimm6_asmoperand;
-}
-
-def label_wid14_scal4_asmoperand : label_asmoperand<14, 4>;
-
-def tbimm_target : Operand<OtherVT> {
- let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_tstbr>";
-
- // This label is a 14-bit offset from PC, scaled by the instruction-width: 4.
- let PrintMethod = "printLabelOperand<14, 4>";
- let ParserMatchClass = label_wid14_scal4_asmoperand;
-
- let OperandType = "OPERAND_PCREL";
-}
-
-def A64eq : ImmLeaf<i32, [{ return Imm == A64CC::EQ; }]>;
-def A64ne : ImmLeaf<i32, [{ return Imm == A64CC::NE; }]>;
-
-// These instructions correspond to patterns involving "and" with a power of
-// two, which we need to be able to select.
-def tstb64_pat : ComplexPattern<i64, 1, "SelectTSTBOperand<64>">;
-def tstb32_pat : ComplexPattern<i32, 1, "SelectTSTBOperand<32>">;
-
-let isBranch = 1, isTerminator = 1 in {
- def TBZxii : A64I_TBimm<0b0, (outs),
- (ins GPR64:$Rt, uimm6:$Imm, tbimm_target:$Label),
- "tbz\t$Rt, $Imm, $Label",
- [(A64br_cc (A64cmp (and i64:$Rt, tstb64_pat:$Imm), 0),
- A64eq, bb:$Label)],
- NoItinerary>,
- Sched<[WriteBr]>;
-
- def TBNZxii : A64I_TBimm<0b1, (outs),
- (ins GPR64:$Rt, uimm6:$Imm, tbimm_target:$Label),
- "tbnz\t$Rt, $Imm, $Label",
- [(A64br_cc (A64cmp (and i64:$Rt, tstb64_pat:$Imm), 0),
- A64ne, bb:$Label)],
- NoItinerary>,
- Sched<[WriteBr]>;
-
-
- // Note, these instructions overlap with the above 64-bit patterns. This is
- // intentional, "tbz x3, #1, somewhere" and "tbz w3, #1, somewhere" would both
- // do the same thing and are both permitted assembly. They also both have
- // sensible DAG patterns.
- def TBZwii : A64I_TBimm<0b0, (outs),
- (ins GPR32:$Rt, uimm5:$Imm, tbimm_target:$Label),
- "tbz\t$Rt, $Imm, $Label",
- [(A64br_cc (A64cmp (and i32:$Rt, tstb32_pat:$Imm), 0),
- A64eq, bb:$Label)],
- NoItinerary>,
- Sched<[WriteBr]> {
- let Imm{5} = 0b0;
- }
-
- def TBNZwii : A64I_TBimm<0b1, (outs),
- (ins GPR32:$Rt, uimm5:$Imm, tbimm_target:$Label),
- "tbnz\t$Rt, $Imm, $Label",
- [(A64br_cc (A64cmp (and i32:$Rt, tstb32_pat:$Imm), 0),
- A64ne, bb:$Label)],
- NoItinerary>,
- Sched<[WriteBr]> {
- let Imm{5} = 0b0;
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Unconditional branch (immediate) instructions
-//===----------------------------------------------------------------------===//
-// Contains: B, BL
-
-def label_wid26_scal4_asmoperand : label_asmoperand<26, 4>;
-
-def bimm_target : Operand<OtherVT> {
- let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_uncondbr>";
-
- // This label is a 26-bit offset from PC, scaled by the instruction-width: 4.
- let PrintMethod = "printLabelOperand<26, 4>";
- let ParserMatchClass = label_wid26_scal4_asmoperand;
-
- let OperandType = "OPERAND_PCREL";
-}
-
-def blimm_target : Operand<i64> {
- let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_call>";
-
- // This label is a 26-bit offset from PC, scaled by the instruction-width: 4.
- let PrintMethod = "printLabelOperand<26, 4>";
- let ParserMatchClass = label_wid26_scal4_asmoperand;
-
- let OperandType = "OPERAND_PCREL";
-}
-
-class A64I_BimmImpl<bit op, string asmop, list<dag> patterns, Operand lbl_type>
- : A64I_Bimm<op, (outs), (ins lbl_type:$Label),
- !strconcat(asmop, "\t$Label"), patterns,
- NoItinerary>,
- Sched<[WriteBr]>;
-
-let isBranch = 1 in {
- def Bimm : A64I_BimmImpl<0b0, "b", [(br bb:$Label)], bimm_target> {
- let isTerminator = 1;
- let isBarrier = 1;
- }
-
- let SchedRW = [WriteBrL] in {
- def BLimm : A64I_BimmImpl<0b1, "bl",
- [(AArch64Call tglobaladdr:$Label)], blimm_target> {
- let isCall = 1;
- let Defs = [X30];
- }
- }
-}
-
-def : Pat<(AArch64Call texternalsym:$Label), (BLimm texternalsym:$Label)>;
-
-//===----------------------------------------------------------------------===//
-// Unconditional branch (register) instructions
-//===----------------------------------------------------------------------===//
-// Contains: BR, BLR, RET, ERET, DRP.
-
-// Most of the notional opcode fields in the A64I_Breg format are fixed in A64
-// at the moment.
-class A64I_BregImpl<bits<4> opc,
- dag outs, dag ins, string asmstr, list<dag> patterns,
- InstrItinClass itin = NoItinerary>
- : A64I_Breg<opc, 0b11111, 0b000000, 0b00000,
- outs, ins, asmstr, patterns, itin>,
- Sched<[WriteBr]> {
- let isBranch = 1;
- let isIndirectBranch = 1;
-}
-
-// Note that these are not marked isCall or isReturn because as far as LLVM is
-// concerned they're not. "ret" is just another jump unless it has been selected
-// by LLVM as the function's return.
-
-let isBranch = 1 in {
- def BRx : A64I_BregImpl<0b0000,(outs), (ins GPR64:$Rn),
- "br\t$Rn", [(brind i64:$Rn)]> {
- let isBarrier = 1;
- let isTerminator = 1;
- }
-
- let SchedRW = [WriteBrL] in {
- def BLRx : A64I_BregImpl<0b0001, (outs), (ins GPR64:$Rn),
- "blr\t$Rn", [(AArch64Call i64:$Rn)]> {
- let isBarrier = 0;
- let isCall = 1;
- let Defs = [X30];
- }
- }
-
- def RETx : A64I_BregImpl<0b0010, (outs), (ins GPR64:$Rn),
- "ret\t$Rn", []> {
- let isBarrier = 1;
- let isTerminator = 1;
- let isReturn = 1;
- }
-
- // Create a separate pseudo-instruction for codegen to use so that we don't
- // flag x30 as used in every function. It'll be restored before the RET by the
- // epilogue if it's legitimately used.
- def RET : A64PseudoExpand<(outs), (ins), [(A64ret)], (RETx (ops X30))> {
- let isTerminator = 1;
- let isBarrier = 1;
- let isReturn = 1;
- }
-
- def ERET : A64I_BregImpl<0b0100, (outs), (ins), "eret", []> {
- let Rn = 0b11111;
- let isBarrier = 1;
- let isTerminator = 1;
- let isReturn = 1;
- }
-
- def DRPS : A64I_BregImpl<0b0101, (outs), (ins), "drps", []> {
- let Rn = 0b11111;
- let isBarrier = 1;
- }
-}
-
-def RETAlias : InstAlias<"ret", (RETx X30)>;
-
-
-//===----------------------------------------------------------------------===//
-// Address generation patterns
-//===----------------------------------------------------------------------===//
-
-// Primary method of address generation for the small/absolute memory model is
-// an ADRP/ADR pair:
-// ADRP x0, some_variable
-// ADD x0, x0, #:lo12:some_variable
-//
-// The load/store elision of the ADD is accomplished when selecting
-// addressing-modes. This just mops up the cases where that doesn't work and we
-// really need an address in some register.
-
-// This wrapper applies a LO12 modifier to the address. Otherwise we could just
-// use the same address.
-
-class ADRP_ADD<SDNode Wrapper, SDNode addrop>
- : Pat<(Wrapper addrop:$Hi, addrop:$Lo12, (i32 imm)),
- (ADDxxi_lsl0_s (ADRPxi addrop:$Hi), addrop:$Lo12)>;
-
-def : ADRP_ADD<A64WrapperSmall, tblockaddress>;
-def : ADRP_ADD<A64WrapperSmall, texternalsym>;
-def : ADRP_ADD<A64WrapperSmall, tglobaladdr>;
-def : ADRP_ADD<A64WrapperSmall, tglobaltlsaddr>;
-def : ADRP_ADD<A64WrapperSmall, tjumptable>;
-def : ADRP_ADD<A64WrapperSmall, tconstpool>;
-
-//===----------------------------------------------------------------------===//
-// GOT access patterns
-//===----------------------------------------------------------------------===//
-
-class GOTLoadSmall<SDNode addrfrag>
- : Pat<(A64GOTLoad (A64WrapperSmall addrfrag:$Hi, addrfrag:$Lo12, 8)),
- (LS64_LDR (ADRPxi addrfrag:$Hi), addrfrag:$Lo12)>;
-
-def : GOTLoadSmall<texternalsym>;
-def : GOTLoadSmall<tglobaladdr>;
-def : GOTLoadSmall<tglobaltlsaddr>;
-
-//===----------------------------------------------------------------------===//
-// Tail call handling
-//===----------------------------------------------------------------------===//
-
-let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [XSP] in {
- def TC_RETURNdi
- : PseudoInst<(outs), (ins i64imm:$dst, i32imm:$FPDiff),
- [(AArch64tcret tglobaladdr:$dst, (i32 timm:$FPDiff))]>;
-
- def TC_RETURNxi
- : PseudoInst<(outs), (ins tcGPR64:$dst, i32imm:$FPDiff),
- [(AArch64tcret i64:$dst, (i32 timm:$FPDiff))]>;
-}
-
-let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
- Uses = [XSP] in {
- def TAIL_Bimm : A64PseudoExpand<(outs), (ins bimm_target:$Label), [],
- (Bimm bimm_target:$Label)>;
-
- def TAIL_BRx : A64PseudoExpand<(outs), (ins tcGPR64:$Rd), [],
- (BRx GPR64:$Rd)>;
-}
-