1//===-- RISCVInstrInfoA.td - RISC-V 'A' instructions -------*- tablegen -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file describes the RISC-V instructions from the standard 'A', Atomic 10// Instructions extension. 11// 12//===----------------------------------------------------------------------===// 13 14//===----------------------------------------------------------------------===// 15// Instruction class templates 16//===----------------------------------------------------------------------===// 17 18let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in 19class LR_r<bit aq, bit rl, bits<3> funct3, string opcodestr> 20 : RVInstRAtomic<0b00010, aq, rl, funct3, OPC_AMO, 21 (outs GPR:$rd), (ins GPRMemZeroOffset:$rs1), 22 opcodestr, "$rd, $rs1"> { 23 let rs2 = 0; 24} 25 26multiclass LR_r_aq_rl<bits<3> funct3, string opcodestr> { 27 def "" : LR_r<0, 0, funct3, opcodestr>; 28 def _AQ : LR_r<1, 0, funct3, opcodestr # ".aq">; 29 def _RL : LR_r<0, 1, funct3, opcodestr # ".rl">; 30 def _AQ_RL : LR_r<1, 1, funct3, opcodestr # ".aqrl">; 31} 32 33let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in 34class AMO_rr<bits<5> funct5, bit aq, bit rl, bits<3> funct3, string opcodestr> 35 : RVInstRAtomic<funct5, aq, rl, funct3, OPC_AMO, 36 (outs GPR:$rd), (ins GPRMemZeroOffset:$rs1, GPR:$rs2), 37 opcodestr, "$rd, $rs2, $rs1">; 38 39multiclass AMO_rr_aq_rl<bits<5> funct5, bits<3> funct3, string opcodestr> { 40 def "" : AMO_rr<funct5, 0, 0, funct3, opcodestr>; 41 def _AQ : AMO_rr<funct5, 1, 0, funct3, opcodestr # ".aq">; 42 def _RL : AMO_rr<funct5, 0, 1, funct3, opcodestr # ".rl">; 43 def _AQ_RL : AMO_rr<funct5, 1, 1, funct3, opcodestr # ".aqrl">; 44} 45 46multiclass AtomicStPat<PatFrag StoreOp, RVInst Inst, RegisterClass StTy, 47 ValueType vt = XLenVT> { 48 def : Pat<(StoreOp (AddrRegImm GPR:$rs1, simm12:$imm12), (vt StTy:$rs2)), 49 (Inst StTy:$rs2, GPR:$rs1, simm12:$imm12)>; 50} 51 52//===----------------------------------------------------------------------===// 53// Instructions 54//===----------------------------------------------------------------------===// 55 56let Predicates = [HasStdExtA] in { 57defm LR_W : LR_r_aq_rl<0b010, "lr.w">, Sched<[WriteAtomicLDW, ReadAtomicLDW]>; 58defm SC_W : AMO_rr_aq_rl<0b00011, 0b010, "sc.w">, 59 Sched<[WriteAtomicSTW, ReadAtomicSTW, ReadAtomicSTW]>; 60defm AMOSWAP_W : AMO_rr_aq_rl<0b00001, 0b010, "amoswap.w">, 61 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 62defm AMOADD_W : AMO_rr_aq_rl<0b00000, 0b010, "amoadd.w">, 63 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 64defm AMOXOR_W : AMO_rr_aq_rl<0b00100, 0b010, "amoxor.w">, 65 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 66defm AMOAND_W : AMO_rr_aq_rl<0b01100, 0b010, "amoand.w">, 67 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 68defm AMOOR_W : AMO_rr_aq_rl<0b01000, 0b010, "amoor.w">, 69 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 70defm AMOMIN_W : AMO_rr_aq_rl<0b10000, 0b010, "amomin.w">, 71 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 72defm AMOMAX_W : AMO_rr_aq_rl<0b10100, 0b010, "amomax.w">, 73 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 74defm AMOMINU_W : AMO_rr_aq_rl<0b11000, 0b010, "amominu.w">, 75 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 76defm AMOMAXU_W : AMO_rr_aq_rl<0b11100, 0b010, "amomaxu.w">, 77 Sched<[WriteAtomicW, ReadAtomicWA, ReadAtomicWD]>; 78} // Predicates = [HasStdExtA] 79 80let Predicates = [HasStdExtA, IsRV64] in { 81defm LR_D : LR_r_aq_rl<0b011, "lr.d">, Sched<[WriteAtomicLDD, ReadAtomicLDD]>; 82defm SC_D : AMO_rr_aq_rl<0b00011, 0b011, "sc.d">, 83 Sched<[WriteAtomicSTD, ReadAtomicSTD, ReadAtomicSTD]>; 84defm AMOSWAP_D : AMO_rr_aq_rl<0b00001, 0b011, "amoswap.d">, 85 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 86defm AMOADD_D : AMO_rr_aq_rl<0b00000, 0b011, "amoadd.d">, 87 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 88defm AMOXOR_D : AMO_rr_aq_rl<0b00100, 0b011, "amoxor.d">, 89 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 90defm AMOAND_D : AMO_rr_aq_rl<0b01100, 0b011, "amoand.d">, 91 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 92defm AMOOR_D : AMO_rr_aq_rl<0b01000, 0b011, "amoor.d">, 93 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 94defm AMOMIN_D : AMO_rr_aq_rl<0b10000, 0b011, "amomin.d">, 95 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 96defm AMOMAX_D : AMO_rr_aq_rl<0b10100, 0b011, "amomax.d">, 97 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 98defm AMOMINU_D : AMO_rr_aq_rl<0b11000, 0b011, "amominu.d">, 99 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 100defm AMOMAXU_D : AMO_rr_aq_rl<0b11100, 0b011, "amomaxu.d">, 101 Sched<[WriteAtomicD, ReadAtomicDA, ReadAtomicDD]>; 102} // Predicates = [HasStdExtA, IsRV64] 103 104//===----------------------------------------------------------------------===// 105// Pseudo-instructions and codegen patterns 106//===----------------------------------------------------------------------===// 107 108let Predicates = [HasStdExtA] in { 109 110/// Atomic loads and stores 111 112// Fences will be inserted for atomic load/stores according to the logic in 113// RISCVTargetLowering::{emitLeadingFence,emitTrailingFence}. 114 115defm : LdPat<atomic_load_8, LB>; 116defm : LdPat<atomic_load_16, LH>; 117defm : LdPat<atomic_load_32, LW>; 118 119defm : AtomicStPat<atomic_store_8, SB, GPR>; 120defm : AtomicStPat<atomic_store_16, SH, GPR>; 121defm : AtomicStPat<atomic_store_32, SW, GPR>; 122 123/// AMOs 124 125multiclass AMOPat<string AtomicOp, string BaseInst> { 126 def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_monotonic"), 127 !cast<RVInst>(BaseInst)>; 128 def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_acquire"), 129 !cast<RVInst>(BaseInst#"_AQ")>; 130 def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_release"), 131 !cast<RVInst>(BaseInst#"_RL")>; 132 def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_acq_rel"), 133 !cast<RVInst>(BaseInst#"_AQ_RL")>; 134 def : PatGprGpr<!cast<PatFrag>(AtomicOp#"_seq_cst"), 135 !cast<RVInst>(BaseInst#"_AQ_RL")>; 136} 137 138defm : AMOPat<"atomic_swap_32", "AMOSWAP_W">; 139defm : AMOPat<"atomic_load_add_32", "AMOADD_W">; 140defm : AMOPat<"atomic_load_and_32", "AMOAND_W">; 141defm : AMOPat<"atomic_load_or_32", "AMOOR_W">; 142defm : AMOPat<"atomic_load_xor_32", "AMOXOR_W">; 143defm : AMOPat<"atomic_load_max_32", "AMOMAX_W">; 144defm : AMOPat<"atomic_load_min_32", "AMOMIN_W">; 145defm : AMOPat<"atomic_load_umax_32", "AMOMAXU_W">; 146defm : AMOPat<"atomic_load_umin_32", "AMOMINU_W">; 147 148def : Pat<(atomic_load_sub_32_monotonic GPR:$addr, GPR:$incr), 149 (AMOADD_W GPR:$addr, (SUB X0, GPR:$incr))>; 150def : Pat<(atomic_load_sub_32_acquire GPR:$addr, GPR:$incr), 151 (AMOADD_W_AQ GPR:$addr, (SUB X0, GPR:$incr))>; 152def : Pat<(atomic_load_sub_32_release GPR:$addr, GPR:$incr), 153 (AMOADD_W_RL GPR:$addr, (SUB X0, GPR:$incr))>; 154def : Pat<(atomic_load_sub_32_acq_rel GPR:$addr, GPR:$incr), 155 (AMOADD_W_AQ_RL GPR:$addr, (SUB X0, GPR:$incr))>; 156def : Pat<(atomic_load_sub_32_seq_cst GPR:$addr, GPR:$incr), 157 (AMOADD_W_AQ_RL GPR:$addr, (SUB X0, GPR:$incr))>; 158 159/// Pseudo AMOs 160 161class PseudoAMO : Pseudo<(outs GPR:$res, GPR:$scratch), 162 (ins GPR:$addr, GPR:$incr, ixlenimm:$ordering), []> { 163 let Constraints = "@earlyclobber $res,@earlyclobber $scratch"; 164 let mayLoad = 1; 165 let mayStore = 1; 166 let hasSideEffects = 0; 167} 168 169let Size = 20 in 170def PseudoAtomicLoadNand32 : PseudoAMO; 171// Ordering constants must be kept in sync with the AtomicOrdering enum in 172// AtomicOrdering.h. 173def : Pat<(atomic_load_nand_32_monotonic GPR:$addr, GPR:$incr), 174 (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 2)>; 175def : Pat<(atomic_load_nand_32_acquire GPR:$addr, GPR:$incr), 176 (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 4)>; 177def : Pat<(atomic_load_nand_32_release GPR:$addr, GPR:$incr), 178 (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 5)>; 179def : Pat<(atomic_load_nand_32_acq_rel GPR:$addr, GPR:$incr), 180 (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 6)>; 181def : Pat<(atomic_load_nand_32_seq_cst GPR:$addr, GPR:$incr), 182 (PseudoAtomicLoadNand32 GPR:$addr, GPR:$incr, 7)>; 183 184class PseudoMaskedAMO 185 : Pseudo<(outs GPR:$res, GPR:$scratch), 186 (ins GPR:$addr, GPR:$incr, GPR:$mask, ixlenimm:$ordering), []> { 187 let Constraints = "@earlyclobber $res,@earlyclobber $scratch"; 188 let mayLoad = 1; 189 let mayStore = 1; 190 let hasSideEffects = 0; 191} 192 193class PseudoMaskedAMOMinMax 194 : Pseudo<(outs GPR:$res, GPR:$scratch1, GPR:$scratch2), 195 (ins GPR:$addr, GPR:$incr, GPR:$mask, ixlenimm:$sextshamt, 196 ixlenimm:$ordering), []> { 197 let Constraints = "@earlyclobber $res,@earlyclobber $scratch1," 198 "@earlyclobber $scratch2"; 199 let mayLoad = 1; 200 let mayStore = 1; 201 let hasSideEffects = 0; 202} 203 204class PseudoMaskedAMOUMinUMax 205 : Pseudo<(outs GPR:$res, GPR:$scratch1, GPR:$scratch2), 206 (ins GPR:$addr, GPR:$incr, GPR:$mask, ixlenimm:$ordering), []> { 207 let Constraints = "@earlyclobber $res,@earlyclobber $scratch1," 208 "@earlyclobber $scratch2"; 209 let mayLoad = 1; 210 let mayStore = 1; 211 let hasSideEffects = 0; 212} 213 214class PseudoMaskedAMOPat<Intrinsic intrin, Pseudo AMOInst> 215 : Pat<(intrin GPR:$addr, GPR:$incr, GPR:$mask, timm:$ordering), 216 (AMOInst GPR:$addr, GPR:$incr, GPR:$mask, timm:$ordering)>; 217 218class PseudoMaskedAMOMinMaxPat<Intrinsic intrin, Pseudo AMOInst> 219 : Pat<(intrin GPR:$addr, GPR:$incr, GPR:$mask, GPR:$shiftamt, 220 timm:$ordering), 221 (AMOInst GPR:$addr, GPR:$incr, GPR:$mask, GPR:$shiftamt, 222 timm:$ordering)>; 223 224let Size = 28 in 225def PseudoMaskedAtomicSwap32 : PseudoMaskedAMO; 226def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_xchg_i32, 227 PseudoMaskedAtomicSwap32>; 228let Size = 28 in 229def PseudoMaskedAtomicLoadAdd32 : PseudoMaskedAMO; 230def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_add_i32, 231 PseudoMaskedAtomicLoadAdd32>; 232let Size = 28 in 233def PseudoMaskedAtomicLoadSub32 : PseudoMaskedAMO; 234def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_sub_i32, 235 PseudoMaskedAtomicLoadSub32>; 236let Size = 32 in 237def PseudoMaskedAtomicLoadNand32 : PseudoMaskedAMO; 238def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_nand_i32, 239 PseudoMaskedAtomicLoadNand32>; 240let Size = 44 in 241def PseudoMaskedAtomicLoadMax32 : PseudoMaskedAMOMinMax; 242def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_max_i32, 243 PseudoMaskedAtomicLoadMax32>; 244let Size = 44 in 245def PseudoMaskedAtomicLoadMin32 : PseudoMaskedAMOMinMax; 246def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_min_i32, 247 PseudoMaskedAtomicLoadMin32>; 248let Size = 36 in 249def PseudoMaskedAtomicLoadUMax32 : PseudoMaskedAMOUMinUMax; 250def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umax_i32, 251 PseudoMaskedAtomicLoadUMax32>; 252let Size = 36 in 253def PseudoMaskedAtomicLoadUMin32 : PseudoMaskedAMOUMinUMax; 254def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i32, 255 PseudoMaskedAtomicLoadUMin32>; 256 257/// Compare and exchange 258 259class PseudoCmpXchg 260 : Pseudo<(outs GPR:$res, GPR:$scratch), 261 (ins GPR:$addr, GPR:$cmpval, GPR:$newval, ixlenimm:$ordering), []> { 262 let Constraints = "@earlyclobber $res,@earlyclobber $scratch"; 263 let mayLoad = 1; 264 let mayStore = 1; 265 let hasSideEffects = 0; 266 let Size = 16; 267} 268 269// Ordering constants must be kept in sync with the AtomicOrdering enum in 270// AtomicOrdering.h. 271multiclass PseudoCmpXchgPat<string Op, Pseudo CmpXchgInst> { 272 def : Pat<(!cast<PatFrag>(Op#"_monotonic") GPR:$addr, GPR:$cmp, GPR:$new), 273 (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 2)>; 274 def : Pat<(!cast<PatFrag>(Op#"_acquire") GPR:$addr, GPR:$cmp, GPR:$new), 275 (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 4)>; 276 def : Pat<(!cast<PatFrag>(Op#"_release") GPR:$addr, GPR:$cmp, GPR:$new), 277 (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 5)>; 278 def : Pat<(!cast<PatFrag>(Op#"_acq_rel") GPR:$addr, GPR:$cmp, GPR:$new), 279 (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 6)>; 280 def : Pat<(!cast<PatFrag>(Op#"_seq_cst") GPR:$addr, GPR:$cmp, GPR:$new), 281 (CmpXchgInst GPR:$addr, GPR:$cmp, GPR:$new, 7)>; 282} 283 284def PseudoCmpXchg32 : PseudoCmpXchg; 285defm : PseudoCmpXchgPat<"atomic_cmp_swap_32", PseudoCmpXchg32>; 286 287def PseudoMaskedCmpXchg32 288 : Pseudo<(outs GPR:$res, GPR:$scratch), 289 (ins GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, 290 ixlenimm:$ordering), []> { 291 let Constraints = "@earlyclobber $res,@earlyclobber $scratch"; 292 let mayLoad = 1; 293 let mayStore = 1; 294 let hasSideEffects = 0; 295 let Size = 32; 296} 297 298def : Pat<(int_riscv_masked_cmpxchg_i32 299 GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering), 300 (PseudoMaskedCmpXchg32 301 GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering)>; 302 303} // Predicates = [HasStdExtA] 304 305let Predicates = [HasStdExtA, IsRV64] in { 306 307/// 64-bit atomic loads and stores 308 309// Fences will be inserted for atomic load/stores according to the logic in 310// RISCVTargetLowering::{emitLeadingFence,emitTrailingFence}. 311defm : LdPat<atomic_load_64, LD, i64>; 312defm : AtomicStPat<atomic_store_64, SD, GPR, i64>; 313 314defm : AMOPat<"atomic_swap_64", "AMOSWAP_D">; 315defm : AMOPat<"atomic_load_add_64", "AMOADD_D">; 316defm : AMOPat<"atomic_load_and_64", "AMOAND_D">; 317defm : AMOPat<"atomic_load_or_64", "AMOOR_D">; 318defm : AMOPat<"atomic_load_xor_64", "AMOXOR_D">; 319defm : AMOPat<"atomic_load_max_64", "AMOMAX_D">; 320defm : AMOPat<"atomic_load_min_64", "AMOMIN_D">; 321defm : AMOPat<"atomic_load_umax_64", "AMOMAXU_D">; 322defm : AMOPat<"atomic_load_umin_64", "AMOMINU_D">; 323 324/// 64-bit AMOs 325 326def : Pat<(i64 (atomic_load_sub_64_monotonic GPR:$addr, GPR:$incr)), 327 (AMOADD_D GPR:$addr, (SUB X0, GPR:$incr))>; 328def : Pat<(i64 (atomic_load_sub_64_acquire GPR:$addr, GPR:$incr)), 329 (AMOADD_D_AQ GPR:$addr, (SUB X0, GPR:$incr))>; 330def : Pat<(i64 (atomic_load_sub_64_release GPR:$addr, GPR:$incr)), 331 (AMOADD_D_RL GPR:$addr, (SUB X0, GPR:$incr))>; 332def : Pat<(i64 (atomic_load_sub_64_acq_rel GPR:$addr, GPR:$incr)), 333 (AMOADD_D_AQ_RL GPR:$addr, (SUB X0, GPR:$incr))>; 334def : Pat<(i64 (atomic_load_sub_64_seq_cst GPR:$addr, GPR:$incr)), 335 (AMOADD_D_AQ_RL GPR:$addr, (SUB X0, GPR:$incr))>; 336 337/// 64-bit pseudo AMOs 338 339let Size = 20 in 340def PseudoAtomicLoadNand64 : PseudoAMO; 341// Ordering constants must be kept in sync with the AtomicOrdering enum in 342// AtomicOrdering.h. 343def : Pat<(i64 (atomic_load_nand_64_monotonic GPR:$addr, GPR:$incr)), 344 (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 2)>; 345def : Pat<(i64 (atomic_load_nand_64_acquire GPR:$addr, GPR:$incr)), 346 (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 4)>; 347def : Pat<(i64 (atomic_load_nand_64_release GPR:$addr, GPR:$incr)), 348 (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 5)>; 349def : Pat<(i64 (atomic_load_nand_64_acq_rel GPR:$addr, GPR:$incr)), 350 (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 6)>; 351def : Pat<(i64 (atomic_load_nand_64_seq_cst GPR:$addr, GPR:$incr)), 352 (PseudoAtomicLoadNand64 GPR:$addr, GPR:$incr, 7)>; 353 354def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_xchg_i64, 355 PseudoMaskedAtomicSwap32>; 356def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_add_i64, 357 PseudoMaskedAtomicLoadAdd32>; 358def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_sub_i64, 359 PseudoMaskedAtomicLoadSub32>; 360def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_nand_i64, 361 PseudoMaskedAtomicLoadNand32>; 362def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_max_i64, 363 PseudoMaskedAtomicLoadMax32>; 364def : PseudoMaskedAMOMinMaxPat<int_riscv_masked_atomicrmw_min_i64, 365 PseudoMaskedAtomicLoadMin32>; 366def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umax_i64, 367 PseudoMaskedAtomicLoadUMax32>; 368def : PseudoMaskedAMOPat<int_riscv_masked_atomicrmw_umin_i64, 369 PseudoMaskedAtomicLoadUMin32>; 370 371/// 64-bit compare and exchange 372 373def PseudoCmpXchg64 : PseudoCmpXchg; 374defm : PseudoCmpXchgPat<"atomic_cmp_swap_64", PseudoCmpXchg64>; 375 376def : Pat<(int_riscv_masked_cmpxchg_i64 377 GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering), 378 (PseudoMaskedCmpXchg32 379 GPR:$addr, GPR:$cmpval, GPR:$newval, GPR:$mask, timm:$ordering)>; 380} // Predicates = [HasStdExtA, IsRV64] 381