1;; s390x instruction selection and CLIF-to-MachInst lowering. 2 3;; The main lowering constructor term: takes a clif `Inst` and returns the 4;; register(s) within which the lowered instruction's result values live. 5(decl partial lower (Inst) InstOutput) 6 7;; A variant of the main lowering constructor term, used for branches. 8;; The only difference is that it gets an extra argument holding a vector 9;; of branch targets to be used. 10(decl partial lower_branch (Inst MachLabelSlice) Unit) 11 12 13;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 14 15(rule (lower (has_type ty (iconst _ (u64_from_imm64 n)))) 16 (imm ty n)) 17 18 19;;;; Rules for `f16const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 20 21(rule (lower (f16const _ (u16_from_ieee16 x))) 22 (imm $F16 x)) 23 24 25;;;; Rules for `f32const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 26 27(rule (lower (f32const _ (u32_from_ieee32 x))) 28 (imm $F32 x)) 29 30 31;;;; Rules for `f64const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 32 33(rule (lower (f64const _ (u64_from_ieee64 x))) 34 (imm $F64 x)) 35 36 37;;;; Rules for `f128const` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 38 39(rule (lower (f128const _ (u128_from_constant x))) 40 (vec_imm $F128 (be_vec_const $F128 x))) 41 42 43;;;; Rules for `vconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 44 45(rule (lower (has_type ty (vconst _ (u128_from_constant x)))) 46 (vec_imm ty (be_vec_const ty x))) 47 48 49;;;; Rules for `nop` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 50 51(rule (lower (nop)) 52 (invalid_reg)) 53 54 55;;;; Rules for `iconcat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 56 57(rule (lower (has_type (vr128_ty ty) (iconcat _ x y))) 58 (mov_to_vec128 ty y x)) 59 60 61;;;; Rules for `isplit` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 62 63(rule (lower (isplit _ x @ (value_type $I128))) 64 (let ((x_reg Reg x) 65 (x_hi Reg (vec_extract_lane $I64X2 x_reg 0 (zero_reg))) 66 (x_lo Reg (vec_extract_lane $I64X2 x_reg 1 (zero_reg)))) 67 (output_pair x_lo x_hi))) 68 69 70;;;; Rules for `iadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 71 72;; Add two registers. 73(rule 0 (lower (has_type (fits_in_64 ty) (iadd _ x y))) 74 (add_reg ty x y)) 75 76;; Add a register and a sign-extended register. 77(rule 8 (lower (has_type (fits_in_64 ty) (iadd _ x (sext32_value y)))) 78 (add_reg_sext32 ty x y)) 79(rule 15 (lower (has_type (fits_in_64 ty) (iadd _ (sext32_value x) y))) 80 (add_reg_sext32 ty y x)) 81 82;; Add a register and an immediate. 83(rule 7 (lower (has_type (fits_in_64 ty) (iadd _ x (i16_from_value y)))) 84 (add_simm16 ty x y)) 85(rule 14 (lower (has_type (fits_in_64 ty) (iadd _ (i16_from_value x) y))) 86 (add_simm16 ty y x)) 87(rule 6 (lower (has_type (fits_in_64 ty) (iadd _ x (i32_from_value y)))) 88 (add_simm32 ty x y)) 89(rule 13 (lower (has_type (fits_in_64 ty) (iadd _ (i32_from_value x) y))) 90 (add_simm32 ty y x)) 91 92;; Add a register and memory (32/64-bit types). 93(rule 5 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_load_32_64 y)))) 94 (add_mem ty x (sink_load y))) 95(rule 12 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_load_32_64 x) y))) 96 (add_mem ty y (sink_load x))) 97 98;; Add a register and memory (16-bit types). 99(rule 4 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_load_16 y)))) 100 (add_mem_sext16 ty x (sink_load y))) 101(rule 11 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_load_16 x) y))) 102 (add_mem_sext16 ty y (sink_load x))) 103 104;; Add a register and sign-extended memory. 105(rule 3 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_sload16 y)))) 106 (add_mem_sext16 ty x (sink_sload16 y))) 107(rule 10 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_sload16 x) y))) 108 (add_mem_sext16 ty y (sink_sload16 x))) 109(rule 2 (lower (has_type (fits_in_64 ty) (iadd _ x (sinkable_sload32 y)))) 110 (add_mem_sext32 ty x (sink_sload32 y))) 111(rule 9 (lower (has_type (fits_in_64 ty) (iadd _ (sinkable_sload32 x) y))) 112 (add_mem_sext32 ty y (sink_sload32 x))) 113 114;; Add two vector registers. 115(rule 1 (lower (has_type (vr128_ty ty) (iadd _ x y))) 116 (vec_add ty x y)) 117 118 119;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 120 121;; Add (saturate unsigned) two vector registers. 122(rule (lower (has_type (ty_vec128 ty) (uadd_sat _ x y))) 123 (let ((sum Reg (vec_add ty x y))) 124 (vec_or ty sum (vec_cmphl ty x sum)))) 125 126 127;;;; Rules for `sadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 128 129;; Add (saturate signed) two vector registers. $I64X2 not supported. 130(rule (lower (has_type (ty_vec128 ty) (sadd_sat _ x y))) 131 (vec_pack_ssat (vec_widen_type ty) 132 (vec_add (vec_widen_type ty) (vec_unpacks_high ty x) 133 (vec_unpacks_high ty y)) 134 (vec_add (vec_widen_type ty) (vec_unpacks_low ty x) 135 (vec_unpacks_low ty y)))) 136 137 138;;;; Rules for `iadd_pairwise` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 139 140;; Lane-wise integer pairwise addition for 8-/16/32-bit vector registers. 141(rule (lower (has_type ty @ (multi_lane bits _) (iadd_pairwise _ x y))) 142 (let ((size Reg (vec_imm_splat $I8X16 bits))) 143 (vec_pack_lane_order (vec_widen_type ty) 144 (vec_add ty x (vec_lshr_by_byte x size)) 145 (vec_add ty y (vec_lshr_by_byte y size))))) 146 147;; special case for the `i32x4.dot_i16x8_s` wasm instruction 148(rule 1 (lower 149 (has_type dst_ty (iadd_pairwise _ 150 (imul _ (swiden_low _ x @ (value_type src_ty)) (swiden_low _ y)) 151 (imul _ (swiden_high _ x) (swiden_high _ y))))) 152 (vec_add dst_ty (vec_smul_even src_ty x y) 153 (vec_smul_odd src_ty x y))) 154 155 156;;;; Rules for `isub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 157 158;; Sub two registers. 159(rule 0 (lower (has_type (fits_in_64 ty) (isub _ x y))) 160 (sub_reg ty x y)) 161 162;; Sub a register and a sign-extended register. 163(rule 8 (lower (has_type (fits_in_64 ty) (isub _ x (sext32_value y)))) 164 (sub_reg_sext32 ty x y)) 165 166;; Sub a register and an immediate (using add of the negated value). 167(rule 7 (lower (has_type (fits_in_64 ty) (isub _ x (i16_from_negated_value y)))) 168 (add_simm16 ty x y)) 169(rule 6 (lower (has_type (fits_in_64 ty) (isub _ x (i32_from_negated_value y)))) 170 (add_simm32 ty x y)) 171 172;; Sub a register and memory (32/64-bit types). 173(rule 5 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_load_32_64 y)))) 174 (sub_mem ty x (sink_load y))) 175 176;; Sub a register and memory (16-bit types). 177(rule 4 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_load_16 y)))) 178 (sub_mem_sext16 ty x (sink_load y))) 179 180;; Sub a register and sign-extended memory. 181(rule 3 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_sload16 y)))) 182 (sub_mem_sext16 ty x (sink_sload16 y))) 183(rule 2 (lower (has_type (fits_in_64 ty) (isub _ x (sinkable_sload32 y)))) 184 (sub_mem_sext32 ty x (sink_sload32 y))) 185 186;; Sub two vector registers. 187(rule 1 (lower (has_type (vr128_ty ty) (isub _ x y))) 188 (vec_sub ty x y)) 189 190 191;;;; Rules for `usub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 192 193;; Add (saturate unsigned) two vector registers. 194(rule (lower (has_type (ty_vec128 ty) (usub_sat _ x y))) 195 (vec_and ty (vec_sub ty x y) (vec_cmphl ty x y))) 196 197 198;;;; Rules for `ssub_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 199 200;; Add (saturate signed) two vector registers. $I64X2 not supported. 201(rule (lower (has_type (ty_vec128 ty) (ssub_sat _ x y))) 202 (vec_pack_ssat (vec_widen_type ty) 203 (vec_sub (vec_widen_type ty) (vec_unpacks_high ty x) 204 (vec_unpacks_high ty y)) 205 (vec_sub (vec_widen_type ty) (vec_unpacks_low ty x) 206 (vec_unpacks_low ty y)))) 207 208 209;;;; Rules for `iabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 210 211;; Absolute value of a register. 212;; For types smaller than 32-bit, the input value must be sign-extended. 213(rule 2 (lower (has_type (fits_in_64 ty) (iabs _ x))) 214 (abs_reg (ty_ext32 ty) (put_in_reg_sext32 x))) 215 216;; Absolute value of a sign-extended register. 217(rule 3 (lower (has_type (fits_in_64 ty) (iabs _ (sext32_value x)))) 218 (abs_reg_sext32 ty x)) 219 220;; Absolute value of a vector register. 221(rule 1 (lower (has_type (ty_vec128 ty) (iabs _ x))) 222 (vec_abs ty x)) 223 224;; Absolute value of a 128-bit integer on z17. 225(rule 4 (lower (has_type (and (vxrs_ext3_enabled) $I128) (iabs _ x))) 226 (vec_abs $I128 x)) 227 228;; Absolute value of a 128-bit integer pre-z17. 229(rule 0 (lower (has_type (and (vxrs_ext3_disabled) $I128) (iabs _ x))) 230 (let ((zero Reg (vec_imm $I128 0)) 231 (pos Reg x) 232 (neg Reg (vec_sub $I128 zero pos)) 233 (rep Reg (vec_replicate_lane $I64X2 pos 0)) 234 (mask Reg (vec_cmph $I64X2 zero rep))) 235 (vec_select $I128 neg pos mask))) 236 237 238;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 239 240;; Negate a register. 241(rule 2 (lower (has_type (fits_in_64 ty) (ineg _ x))) 242 (neg_reg ty x)) 243 244;; Negate a sign-extended register. 245(rule 3 (lower (has_type (fits_in_64 ty) (ineg _ (sext32_value x)))) 246 (neg_reg_sext32 ty x)) 247 248;; Negate a vector register. 249(rule 1 (lower (has_type (ty_vec128 ty) (ineg _ x))) 250 (vec_neg ty x)) 251 252;; Negate a 128-bit integer on z17. 253(rule 4 (lower (has_type (and (vxrs_ext3_enabled) $I128) (ineg _ x))) 254 (vec_neg $I128 x)) 255 256;; Negate a 128-bit integer pre-z17. 257(rule 0 (lower (has_type (and (vxrs_ext3_disabled) $I128) (ineg _ x))) 258 (vec_sub $I128 (vec_imm $I128 0) x)) 259 260 261;;;; Rules for `umax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 262 263;; Unsigned maximum of two scalar integers - expand to icmp + select. 264(rule 2 (lower (has_type (fits_in_64 ty) (umax _ x y))) 265 (let ((x_ext Reg (put_in_reg_zext32 x)) 266 (y_ext Reg (put_in_reg_zext32 y)) 267 (cond ProducesBool (bool (icmpu_reg (ty_ext32 ty) x_ext y_ext) 268 (intcc_as_cond (IntCC.UnsignedLessThan))))) 269 (select_bool_reg ty cond y_ext x_ext))) 270 271;; Unsigned maximum of two 128-bit integers pre-z17 - expand to icmp + select. 272(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (umax _ x y))) 273 (let ((x_reg Reg (put_in_reg x)) 274 (y_reg Reg (put_in_reg y)) 275 (cond ProducesBool (vec_int128_ucmphi y_reg x_reg))) 276 (select_bool_reg $I128 cond y_reg x_reg))) 277 278;; Unsigned maximum of two 128-bit integers on z17. 279(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (umax _ x y))) 280 (vec_umax $I128 x y)) 281 282;; Unsigned maximum of two vector registers. 283(rule 0 (lower (has_type (ty_vec128 ty) (umax _ x y))) 284 (vec_umax ty x y)) 285 286 287;;;; Rules for `umin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 288 289;; Unsigned minimum of two scalar integers - expand to icmp + select. 290(rule 2 (lower (has_type (fits_in_64 ty) (umin _ x y))) 291 (let ((x_ext Reg (put_in_reg_zext32 x)) 292 (y_ext Reg (put_in_reg_zext32 y)) 293 (cond ProducesBool (bool (icmpu_reg (ty_ext32 ty) x_ext y_ext) 294 (intcc_as_cond (IntCC.UnsignedGreaterThan))))) 295 (select_bool_reg ty cond y_ext x_ext))) 296 297;; Unsigned maximum of two 128-bit integers pre-z17 - expand to icmp + select. 298(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (umin _ x y))) 299 (let ((x_reg Reg (put_in_reg x)) 300 (y_reg Reg (put_in_reg y)) 301 (cond ProducesBool (vec_int128_ucmphi x_reg y_reg))) 302 (select_bool_reg $I128 cond y_reg x_reg))) 303 304;; Unsigned minimum of two 128-bit integers on z17. 305(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (umin _ x y))) 306 (vec_umin $I128 x y)) 307 308;; Unsigned minimum of two vector registers. 309(rule 0 (lower (has_type (ty_vec128 ty) (umin _ x y))) 310 (vec_umin ty x y)) 311 312 313;;;; Rules for `smax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 314 315;; Signed maximum of two scalar integers - expand to icmp + select. 316(rule 2 (lower (has_type (fits_in_64 ty) (smax _ x y))) 317 (let ((x_ext Reg (put_in_reg_sext32 x)) 318 (y_ext Reg (put_in_reg_sext32 y)) 319 (cond ProducesBool (bool (icmps_reg (ty_ext32 ty) x_ext y_ext) 320 (intcc_as_cond (IntCC.SignedLessThan))))) 321 (select_bool_reg ty cond y_ext x_ext))) 322 323;; Signed maximum of two 128-bit integers pre-z17 - expand to icmp + select. 324(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (smax _ x y))) 325 (let ((x_reg Reg (put_in_reg x)) 326 (y_reg Reg (put_in_reg y)) 327 (cond ProducesBool (vec_int128_scmphi y_reg x_reg))) 328 (select_bool_reg $I128 cond y_reg x_reg))) 329 330;; Signed maximum of two 128-bit integers on z17. 331(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (smax _ x y))) 332 (vec_smax $I128 x y)) 333 334;; Signed maximum of two vector registers. 335(rule (lower (has_type (ty_vec128 ty) (smax _ x y))) 336 (vec_smax ty x y)) 337 338 339;;;; Rules for `smin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 340 341;; Signed minimum of two scalar integers - expand to icmp + select. 342(rule 2 (lower (has_type (fits_in_64 ty) (smin _ x y))) 343 (let ((x_ext Reg (put_in_reg_sext32 x)) 344 (y_ext Reg (put_in_reg_sext32 y)) 345 (cond ProducesBool (bool (icmps_reg (ty_ext32 ty) x_ext y_ext) 346 (intcc_as_cond (IntCC.SignedGreaterThan))))) 347 (select_bool_reg ty cond y_ext x_ext))) 348 349;; Signed maximum of two 128-bit integers pre-z17 - expand to icmp + select. 350(rule 1 (lower (has_type (and (vxrs_ext3_disabled) $I128) (smin _ x y))) 351 (let ((x_reg Reg (put_in_reg x)) 352 (y_reg Reg (put_in_reg y)) 353 (cond ProducesBool (vec_int128_scmphi x_reg y_reg))) 354 (select_bool_reg $I128 cond y_reg x_reg))) 355 356;; Signed minimum of two 128-bit integers on z17. 357(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (smin _ x y))) 358 (vec_smin $I128 x y)) 359 360;; Signed minimum of two vector registers. 361(rule (lower (has_type (ty_vec128 ty) (smin _ x y))) 362 (vec_smin ty x y)) 363 364 365;;;; Rules for `avg_round` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 366 367;; Unsigned average of two vector registers. 368(rule (lower (has_type (ty_vec128 ty) (avg_round _ x y))) 369 (vec_uavg ty x y)) 370 371 372;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 373 374;; Multiply two registers. 375(rule 0 (lower (has_type (fits_in_64 ty) (imul _ x y))) 376 (mul_reg ty x y)) 377 378;; Multiply a register and a sign-extended register. 379(rule 8 (lower (has_type (fits_in_64 ty) (imul _ x (sext32_value y)))) 380 (mul_reg_sext32 ty x y)) 381(rule 15 (lower (has_type (fits_in_64 ty) (imul _ (sext32_value x) y))) 382 (mul_reg_sext32 ty y x)) 383 384;; Multiply a register and an immediate. 385(rule 7 (lower (has_type (fits_in_64 ty) (imul _ x (i16_from_value y)))) 386 (mul_simm16 ty x y)) 387(rule 14 (lower (has_type (fits_in_64 ty) (imul _ (i16_from_value x) y))) 388 (mul_simm16 ty y x)) 389(rule 6 (lower (has_type (fits_in_64 ty) (imul _ x (i32_from_value y)))) 390 (mul_simm32 ty x y)) 391(rule 13 (lower (has_type (fits_in_64 ty) (imul _ (i32_from_value x) y))) 392 (mul_simm32 ty y x)) 393 394;; Multiply a register and memory (32/64-bit types). 395(rule 5 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_load_32_64 y)))) 396 (mul_mem ty x (sink_load y))) 397(rule 12 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_load_32_64 x) y))) 398 (mul_mem ty y (sink_load x))) 399 400;; Multiply a register and memory (16-bit types). 401(rule 4 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_load_16 y)))) 402 (mul_mem_sext16 ty x (sink_load y))) 403(rule 11 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_load_16 x) y))) 404 (mul_mem_sext16 ty y (sink_load x))) 405 406;; Multiply a register and sign-extended memory. 407(rule 3 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_sload16 y)))) 408 (mul_mem_sext16 ty x (sink_sload16 y))) 409(rule 10 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_sload16 x) y))) 410 (mul_mem_sext16 ty y (sink_sload16 x))) 411(rule 2 (lower (has_type (fits_in_64 ty) (imul _ x (sinkable_sload32 y)))) 412 (mul_mem_sext32 ty x (sink_sload32 y))) 413(rule 9 (lower (has_type (fits_in_64 ty) (imul _ (sinkable_sload32 x) y))) 414 (mul_mem_sext32 ty y (sink_sload32 x))) 415 416;; Multiply two vector registers, using a helper. 417(decl vec_mul_impl (Type Reg Reg) Reg) 418(rule 1 (lower (has_type (vr128_ty ty) (imul _ x y))) 419 (vec_mul_impl ty x y)) 420 421;; Multiply two vector registers - byte, halfword, and word. 422(rule (vec_mul_impl $I8X16 x y) (vec_mul $I8X16 x y)) 423(rule (vec_mul_impl $I16X8 x y) (vec_mul $I16X8 x y)) 424(rule (vec_mul_impl $I32X4 x y) (vec_mul $I32X4 x y)) 425 426;; Multiply two vector registers - doubleword on z17. 427(rule 1 (vec_mul_impl (and (vxrs_ext3_enabled) $I64X2) x y) (vec_mul $I64X2 x y)) 428 429;; Multiply two vector registers - doubleword pre-z17. Has to be scalarized. 430(rule (vec_mul_impl (and (vxrs_ext3_disabled) $I64X2) x y) 431 (mov_to_vec128 $I64X2 432 (mul_reg $I64 (vec_extract_lane $I64X2 x 0 (zero_reg)) 433 (vec_extract_lane $I64X2 y 0 (zero_reg))) 434 (mul_reg $I64 (vec_extract_lane $I64X2 x 1 (zero_reg)) 435 (vec_extract_lane $I64X2 y 1 (zero_reg))))) 436 437;; Multiply two vector registers - quadword on z17. 438(rule 1 (vec_mul_impl (and (vxrs_ext3_enabled) $I128) x y) (vec_mul $I128 x y)) 439 440;; Multiply two vector registers - quadword pre-z17. 441(rule (vec_mul_impl (and (vxrs_ext3_disabled) $I128) x y) 442 (let ((x_hi Reg (vec_extract_lane $I64X2 x 0 (zero_reg))) 443 (x_lo Reg (vec_extract_lane $I64X2 x 1 (zero_reg))) 444 (y_hi Reg (vec_extract_lane $I64X2 y 0 (zero_reg))) 445 (y_lo Reg (vec_extract_lane $I64X2 y 1 (zero_reg))) 446 (lo_pair RegPair (umul_wide x_lo y_lo)) 447 (res_lo Reg (regpair_lo lo_pair)) 448 (res_hi_1 Reg (regpair_hi lo_pair)) 449 (res_hi_2 Reg (mul_reg $I64 x_lo y_hi)) 450 (res_hi_3 Reg (mul_reg $I64 x_hi y_lo)) 451 (res_hi Reg (add_reg $I64 res_hi_3 (add_reg $I64 res_hi_2 res_hi_1)))) 452 (mov_to_vec128 $I64X2 res_hi res_lo))) 453 454;; Special-case the lowering of a 128-bit multiply where the operands are sign 455;; or zero extended. This maps directly to `umul_wide` and `smul_wide`. 456(rule 16 (lower (has_type $I128 (imul _ (uextend _ x) (uextend _ y)))) 457 (let ((pair RegPair (umul_wide (put_in_reg_zext64 x) (put_in_reg_zext64 y)))) 458 (mov_to_vec128 $I64X2 (regpair_hi pair) (regpair_lo pair)))) 459 460(rule 16 (lower (has_type $I128 (imul _ (sextend _ x) (sextend _ y)))) 461 (let ((pair RegPair (smul_wide (put_in_reg_sext64 x) (put_in_reg_sext64 y)))) 462 (mov_to_vec128 $I64X2 (regpair_hi pair) (regpair_lo pair)))) 463 464;;;; Rules for `umulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 465 466;; Multiply high part unsigned, 8-bit or 16-bit types. (Uses 32-bit multiply.) 467(rule -1 (lower (has_type (ty_8_or_16 ty) (umulhi _ x y))) 468 (let ((ext_reg_x Reg (put_in_reg_zext32 x)) 469 (ext_reg_y Reg (put_in_reg_zext32 y)) 470 (ext_mul Reg (mul_reg $I32 ext_reg_x ext_reg_y))) 471 (lshr_imm $I32 ext_mul (ty_bits ty)))) 472 473;; Multiply high part unsigned, 32-bit types. (Uses 64-bit multiply.) 474(rule (lower (has_type $I32 (umulhi _ x y))) 475 (let ((ext_reg_x Reg (put_in_reg_zext64 x)) 476 (ext_reg_y Reg (put_in_reg_zext64 y)) 477 (ext_mul Reg (mul_reg $I64 ext_reg_x ext_reg_y))) 478 (lshr_imm $I64 ext_mul 32))) 479 480;; Multiply high part unsigned, 64-bit types. (Uses umul_wide.) 481(rule (lower (has_type $I64 (umulhi _ x y))) 482 (let ((pair RegPair (umul_wide x y))) 483 (regpair_hi pair))) 484 485;; Multiply high part unsigned, vector types with 8-, 16-, or 32-bit elements. 486(rule (lower (has_type $I8X16 (umulhi _ x y))) (vec_umulhi $I8X16 x y)) 487(rule (lower (has_type $I16X8 (umulhi _ x y))) (vec_umulhi $I16X8 x y)) 488(rule (lower (has_type $I32X4 (umulhi _ x y))) (vec_umulhi $I32X4 x y)) 489 490;; Multiply high part unsigned, vector types with 64-bit elements on z17. 491(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I64X2) (umulhi _ x y))) (vec_umulhi $I64X2 x y)) 492 493;; Multiply high part unsigned, vector types with 64-bit elements pre-z17. 494;; Has to be scalarized. 495(rule (lower (has_type (and (vxrs_ext3_disabled) $I64X2) (umulhi _ x y))) 496 (let ((pair_0 RegPair (umul_wide (vec_extract_lane $I64X2 x 0 (zero_reg)) 497 (vec_extract_lane $I64X2 y 0 (zero_reg)))) 498 (res_0 Reg (regpair_hi pair_0)) 499 (pair_1 RegPair (umul_wide (vec_extract_lane $I64X2 x 1 (zero_reg)) 500 (vec_extract_lane $I64X2 y 1 (zero_reg)))) 501 (res_1 Reg (regpair_hi pair_1))) 502 (mov_to_vec128 $I64X2 res_0 res_1))) 503 504 505;;;; Rules for `smulhi` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 506 507;; Multiply high part signed, 8-bit or 16-bit types. (Uses 32-bit multiply.) 508(rule -1 (lower (has_type (ty_8_or_16 ty) (smulhi _ x y))) 509 (let ((ext_reg_x Reg (put_in_reg_sext32 x)) 510 (ext_reg_y Reg (put_in_reg_sext32 y)) 511 (ext_mul Reg (mul_reg $I32 ext_reg_x ext_reg_y))) 512 (ashr_imm $I32 ext_mul (ty_bits ty)))) 513 514;; Multiply high part signed, 32-bit types. (Uses 64-bit multiply.) 515(rule (lower (has_type $I32 (smulhi _ x y))) 516 (let ((ext_reg_x Reg (put_in_reg_sext64 x)) 517 (ext_reg_y Reg (put_in_reg_sext64 y)) 518 (ext_mul Reg (mul_reg $I64 ext_reg_x ext_reg_y))) 519 (ashr_imm $I64 ext_mul 32))) 520 521;; Multiply high part signed, 64-bit types. (Uses smul_wide.) 522(rule (lower (has_type $I64 (smulhi _ x y))) 523 (let ((pair RegPair (smul_wide x y))) 524 (regpair_hi pair))) 525 526;; Multiply high part signed, vector types with 8-, 16-, or 32-bit elements. 527(rule (lower (has_type $I8X16 (smulhi _ x y))) (vec_smulhi $I8X16 x y)) 528(rule (lower (has_type $I16X8 (smulhi _ x y))) (vec_smulhi $I16X8 x y)) 529(rule (lower (has_type $I32X4 (smulhi _ x y))) (vec_smulhi $I32X4 x y)) 530 531;; Multiply high part signed, vector types with 64-bit elements on z17. 532(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I64X2) (smulhi _ x y))) (vec_smulhi $I64X2 x y)) 533 534;; Multiply high part signed, vector types with 64-bit elements pre-z17. 535;; Has to be scalarized. 536(rule (lower (has_type (and (vxrs_ext3_disabled) $I64X2) (smulhi _ x y))) 537 (let ((pair_0 RegPair (smul_wide (vec_extract_lane $I64X2 x 0 (zero_reg)) 538 (vec_extract_lane $I64X2 y 0 (zero_reg)))) 539 (res_0 Reg (copy_reg $I64 (regpair_hi pair_0))) 540 (pair_1 RegPair (smul_wide (vec_extract_lane $I64X2 x 1 (zero_reg)) 541 (vec_extract_lane $I64X2 y 1 (zero_reg)))) 542 (res_1 Reg (regpair_hi pair_1))) 543 (mov_to_vec128 $I64X2 res_0 res_1))) 544 545 546;;;; Rules for `sqmul_round_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 547 548;; Fixed-point multiplication of two vector registers. 549(rule (lower (has_type (ty_vec128 ty) (sqmul_round_sat _ x y))) 550 (vec_pack_ssat (vec_widen_type ty) 551 (sqmul_impl (vec_widen_type ty) 552 (vec_unpacks_high ty x) 553 (vec_unpacks_high ty y)) 554 (sqmul_impl (vec_widen_type ty) 555 (vec_unpacks_low ty x) 556 (vec_unpacks_low ty y)))) 557 558;; Helper to perform the rounded multiply in the wider type. 559(decl sqmul_impl (Type Reg Reg) Reg) 560(rule (sqmul_impl $I32X4 x y) 561 (vec_ashr_imm $I32X4 (vec_add $I32X4 (vec_mul_impl $I32X4 x y) 562 (vec_imm_bit_mask $I32X4 17 17)) 563 15)) 564(rule (sqmul_impl $I64X2 x y) 565 (vec_ashr_imm $I64X2 (vec_add $I64X2 (vec_mul_impl $I64X2 x y) 566 (vec_imm_bit_mask $I64X2 33 33)) 567 31)) 568 569 570;;;; Rules for `udiv` and `urem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 571 572;; Divide two registers. The architecture provides combined udiv / urem 573;; instructions with the following combination of data types: 574;; 575;; - 64-bit dividend (split across a 2x32-bit register pair), 576;; 32-bit divisor (in a single input register) 577;; 32-bit quotient & remainder (in a 2x32-bit register pair) 578;; 579;; - 128-bit dividend (split across a 2x64-bit register pair), 580;; 64-bit divisor (in a single input register) 581;; 64-bit quotient & remainder (in a 2x64-bit register pair) 582;; 583;; We use the first variant for 32-bit and smaller input types, 584;; and the second variant for 64-bit input types. 585 586;; Implement `udiv`. 587(rule (lower (has_type (fits_in_64 ty) (udiv _ x y))) 588 (let ( 589 ;; Look at the divisor to determine whether we need to generate 590 ;; an explicit division-by zero check. 591 ;; Load up the dividend, by loading the input (possibly zero- 592 ;; extended) input into the low half of the register pair, 593 ;; and setting the high half to zero. 594 (ext_x RegPair (regpair (imm (ty_ext32 ty) 0) 595 (put_in_reg_zext32 x))) 596 ;; Load up the divisor, zero-extended if necessary. 597 (ext_y Reg (put_in_reg_zext32 y)) 598 (ext_ty Type (ty_ext32 ty)) 599 ;; Emit the actual divide instruction. 600 (pair RegPair (udivmod ext_ty ext_x ext_y))) 601 ;; The quotient can be found in the low half of the result. 602 (regpair_lo pair))) 603 604;; Implement `urem`. Same as `udiv`, but finds the remainder in 605;; the high half of the result register pair instead. 606(rule (lower (has_type (fits_in_64 ty) (urem _ x y))) 607 (let ((ext_x RegPair (regpair (imm (ty_ext32 ty) 0) 608 (put_in_reg_zext32 x))) 609 (ext_y Reg (put_in_reg_zext32 y)) 610 (ext_ty Type (ty_ext32 ty)) 611 (pair RegPair (udivmod ext_ty ext_x ext_y))) 612 (regpair_hi pair))) 613 614;; Implement `udiv` for 128-bit integers on z17 (only). 615(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (udiv _ x y))) 616 (vec_udiv $I128 x y)) 617 618;; Implement `urem` for 128-bit integers on z17 (only). 619(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (urem _ x y))) 620 (vec_urem $I128 x y)) 621 622 623;;;; Rules for `sdiv` and `srem` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 624 625;; Divide two registers. The architecture provides combined sdiv / srem 626;; instructions with the following combination of data types: 627;; 628;; - 64-bit dividend (in the low half of a 2x64-bit register pair), 629;; 32-bit divisor (in a single input register) 630;; 64-bit quotient & remainder (in a 2x64-bit register pair) 631;; 632;; - 64-bit dividend (in the low half of a 2x64-bit register pair), 633;; 64-bit divisor (in a single input register) 634;; 64-bit quotient & remainder (in a 2x64-bit register pair) 635;; 636;; We use the first variant for 32-bit and smaller input types, 637;; and the second variant for 64-bit input types. 638 639;; Implement `sdiv`. 640(rule (lower (has_type (fits_in_64 ty) (sdiv _ x y))) 641 (let ( 642 ;; Look at the divisor to determine whether we need to generate 643 ;; explicit division-by-zero and/or integer-overflow checks. 644 (OFcheck bool (div_overflow_check_needed y)) 645 ;; Load up the dividend (sign-extended to 64-bit) 646 (ext_x Reg (put_in_reg_sext64 x)) 647 ;; Load up the divisor (sign-extended if necessary). 648 (ext_y Reg (put_in_reg_sext32 y)) 649 (ext_ty Type (ty_ext32 ty)) 650 ;; Perform integer-overflow check if necessary. 651 (_ Reg (maybe_trap_if_sdiv_overflow OFcheck ext_ty ty ext_x ext_y)) 652 ;; Emit the actual divide instruction. 653 (pair RegPair (sdivmod ext_ty ext_x ext_y))) 654 ;; The quotient can be found in the low half of the result. 655 (regpair_lo pair))) 656 657;; Implement `srem`. Same as `sdiv`, but finds the remainder in 658;; the high half of the result register pair instead. Also, handle 659;; the integer overflow case differently, see below. 660(rule (lower (has_type (fits_in_64 ty) (srem _ x y))) 661 (let ((OFcheck bool (div_overflow_check_needed y)) 662 (ext_x Reg (put_in_reg_sext64 x)) 663 (ext_y Reg (put_in_reg_sext32 y)) 664 (ext_ty Type (ty_ext32 ty)) 665 (checked_x Reg (maybe_avoid_srem_overflow OFcheck ext_ty ext_x ext_y)) 666 (pair RegPair (sdivmod ext_ty checked_x ext_y))) 667 (regpair_hi pair))) 668 669;; Determine whether we need to perform an integer-overflow check. 670;; 671;; We never rely on the divide instruction itself to trap; while that trap 672;; would indeed happen, we have no way of signalling two different trap 673;; conditions from the same instruction. By explicitly checking for the 674;; integer-overflow case ahead of time, any hardware trap in the divide 675;; instruction is guaranteed to indicate division-by-zero. 676;; 677;; In addition, for types smaller than 64 bits we would have to perform 678;; the check explicitly anyway, since the instruction provides a 64-bit 679;; quotient and only traps if *that* overflows. 680;; 681;; However, the only case where integer overflow can occur is if the 682;; minimum (signed) integer value is divided by -1, so if the divisor 683;; is any immediate different from -1, the check can be omitted. 684(decl div_overflow_check_needed (Value) bool) 685(rule 1 (div_overflow_check_needed (i64_from_value x)) 686 (if (i64_not_neg1 x)) 687 false) 688(rule (div_overflow_check_needed _) true) 689 690;; Perform the integer-overflow check if necessary. This implements: 691;; 692;; if divisor == INT_MIN && dividend == -1 { trap } 693;; 694;; but to avoid introducing control flow, it is actually done as: 695;; 696;; if ((divisor ^ INT_MAX) & dividend) == -1 { trap } 697;; 698;; instead, using a single conditional trap instruction. 699(decl maybe_trap_if_sdiv_overflow (bool Type Type Reg Reg) Reg) 700(rule (maybe_trap_if_sdiv_overflow false ext_ty _ _ _) (invalid_reg)) 701(rule (maybe_trap_if_sdiv_overflow true ext_ty ty x y) 702 (let ((int_max Reg (imm ext_ty (int_max ty))) 703 (reg Reg (and_reg ext_ty (xor_reg ext_ty int_max x) y))) 704 (icmps_simm16_and_trap ext_ty reg -1 705 (intcc_as_cond (IntCC.Equal)) 706 (trap_code_integer_overflow)))) 707(rule 1 (maybe_trap_if_sdiv_overflow true $I128 $I128 x y) 708 (let ( 709 ;; We need to trap when y == INT_MIN && x == -1 710 ;; y == INT_MIN is implemented as y == -y, as -INT_MIN == INT_MIN. 711 ;; This checks that y == -y, by using Not-Xor for bitwise 712 ;; equality, producing all 0b1's (-1u128) when y == -y. 713 ;; Then it uses band to include the x == -1 check as well. 714 ;; using (band x (bnot (bxor y neg_division))) variant of vec eval 715 (neg_divisor Reg (vec_neg $I128 y)) 716 (reg Reg (vec_eval $I128 0b00001001 x y neg_divisor)) 717 ;; finally, we check that the combination of x & y == -y is -1 718 (flags ProducesFlags (vec_elt_icmps reg (vec_imm $I128 -1)))) 719 (trap_if flags 720 (intcc_as_cond (IntCC.Equal)) 721 (trap_code_integer_overflow)))) 722 723(decl int_max (Type) u64) 724(rule (int_max $I8) 0x7f) 725(rule (int_max $I16) 0x7fff) 726(rule (int_max $I32) 0x7fffffff) 727(rule (int_max $I64) 0x7fffffffffffffff) 728 729;; When performing `srem`, we do not want to trap in the 730;; integer-overflow scenario, because it is only the quotient 731;; that overflows, not the remainder. 732;; 733;; For types smaller than 64 bits, we can simply let the 734;; instruction execute, since (as above) it will never trap. 735;; 736;; For 64-bit inputs, we check whether the divisor is -1, and 737;; if so simply replace the dividend by zero, which will give 738;; the correct result, since any value modulo -1 is zero. 739;; 740;; (We could in fact avoid executing the divide instruction 741;; at all in this case, but that would require introducing 742;; control flow.) 743(decl maybe_avoid_srem_overflow (bool Type Reg Reg) Reg) 744(rule (maybe_avoid_srem_overflow false _ x _) x) 745(rule (maybe_avoid_srem_overflow true $I32 x _) x) 746(rule (maybe_avoid_srem_overflow true $I64 x y) 747 (with_flags_reg (icmps_simm16 $I64 y -1) 748 (cmov_imm $I64 (intcc_as_cond (IntCC.Equal)) 0 x))) 749(rule (maybe_avoid_srem_overflow true $I128 x y) 750 (with_flags_reg 751 (vec_elt_icmps y (vec_imm $I128 -1)) 752 (cmov_reg_reg $I128 753 (intcc_as_cond(IntCC.Equal)) 754 (vec_imm $I128 0) 755 x))) 756 757 758;; Implement `sdiv` for 128-bit integers on z17 (only). 759(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (sdiv _ x y))) 760 (let ((OFcheck bool (div_overflow_check_needed y)) 761 (_ Reg (maybe_trap_if_sdiv_overflow OFcheck $I128 $I128 x y))) 762 (vec_sdiv $I128 x y))) 763 764;; Implement `srem` for 128-bit integers on z17 (only). 765(rule 1 (lower (has_type (and (vxrs_ext3_enabled) $I128) (srem _ x y))) 766 (let ((OFcheck bool (div_overflow_check_needed y)) 767 (top Reg (maybe_avoid_srem_overflow OFcheck $I128 x y))) 768 (vec_srem $I128 top y))) 769 770 771;;;; Rules for `ishl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 772 773;; Shift left, shift amount in register. 774(rule 0 (lower (has_type (fits_in_64 ty) (ishl _ x y))) 775 (let ((masked_amt Reg (mask_amt_reg ty (amt_reg y)))) 776 (lshl_reg ty x masked_amt))) 777 778;; Shift left, immediate shift amount. 779(rule 1 (lower (has_type (fits_in_64 ty) (ishl _ x (i64_from_value y)))) 780 (let ((masked_amt u8 (mask_amt_imm ty y))) 781 (lshl_imm ty x masked_amt))) 782 783;; Vector shift left, shift amount in register. 784(rule 2 (lower (has_type (ty_vec128 ty) (ishl _ x y))) 785 (vec_lshl_reg ty x (amt_reg y))) 786 787;; Vector shift left, immediate shift amount. 788(rule 3 (lower (has_type (ty_vec128 ty) (ishl _ x (i64_from_value y)))) 789 (let ((masked_amt u8 (mask_amt_imm ty y))) 790 (vec_lshl_imm ty x masked_amt))) 791 792;; 128-bit vector shift left. 793(rule 4 (lower (has_type $I128 (ishl _ x y))) 794 (let ((amt Reg (amt_vr y))) 795 (vec_lshl_by_bit (vec_lshl_by_byte x amt) amt))) 796 797 798;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 799 800;; Shift right logical, shift amount in register. 801;; For types smaller than 32-bit, the input value must be zero-extended. 802(rule 0 (lower (has_type (fits_in_64 ty) (ushr _ x y))) 803 (let ((ext_reg Reg (put_in_reg_zext32 x)) 804 (masked_amt Reg (mask_amt_reg ty (amt_reg y)))) 805 (lshr_reg (ty_ext32 ty) ext_reg masked_amt))) 806 807;; Shift right logical, immediate shift amount. 808;; For types smaller than 32-bit, the input value must be zero-extended. 809(rule 1 (lower (has_type (fits_in_64 ty) (ushr _ x (i64_from_value y)))) 810 (let ((ext_reg Reg (put_in_reg_zext32 x)) 811 (masked_amt u8 (mask_amt_imm ty y))) 812 (lshr_imm (ty_ext32 ty) ext_reg masked_amt))) 813 814;; Vector shift right logical, shift amount in register. 815(rule 2 (lower (has_type (ty_vec128 ty) (ushr _ x y))) 816 (vec_lshr_reg ty x (amt_reg y))) 817 818;; Vector shift right logical, immediate shift amount. 819(rule 3 (lower (has_type (ty_vec128 ty) (ushr _ x (i64_from_value y)))) 820 (let ((masked_amt u8 (mask_amt_imm ty y))) 821 (vec_lshr_imm ty x masked_amt))) 822 823;; 128-bit vector shift right logical. 824(rule 4 (lower (has_type $I128 (ushr _ x y))) 825 (let ((amt Reg (amt_vr y))) 826 (vec_lshr_by_bit (vec_lshr_by_byte x amt) amt))) 827 828 829;;;; Rules for `sshr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 830 831;; Shift right arithmetic, shift amount in register. 832;; For types smaller than 32-bit, the input value must be sign-extended. 833(rule 0 (lower (has_type (fits_in_64 ty) (sshr _ x y))) 834 (let ((ext_reg Reg (put_in_reg_sext32 x)) 835 (masked_amt Reg (mask_amt_reg ty (amt_reg y)))) 836 (ashr_reg (ty_ext32 ty) ext_reg masked_amt))) 837 838;; Shift right arithmetic, immediate shift amount. 839;; For types smaller than 32-bit, the input value must be sign-extended. 840(rule 1 (lower (has_type (fits_in_64 ty) (sshr _ x (i64_from_value y)))) 841 (let ((ext_reg Reg (put_in_reg_sext32 x)) 842 (masked_amt u8 (mask_amt_imm ty y))) 843 (ashr_imm (ty_ext32 ty) ext_reg masked_amt))) 844 845;; Vector shift right arithmetic, shift amount in register. 846(rule 2 (lower (has_type (ty_vec128 ty) (sshr _ x y))) 847 (vec_ashr_reg ty x (amt_reg y))) 848 849;; Vector shift right arithmetic, immediate shift amount. 850(rule 3 (lower (has_type (ty_vec128 ty) (sshr _ x (i64_from_value y)))) 851 (let ((masked_amt u8 (mask_amt_imm ty y))) 852 (vec_ashr_imm ty x masked_amt))) 853 854;; 128-bit vector shift right arithmetic. 855(rule 4 (lower (has_type $I128 (sshr _ x y))) 856 (let ((amt Reg (amt_vr y))) 857 (vec_ashr_by_bit (vec_ashr_by_byte x amt) amt))) 858 859 860;;;; Rules for `rotl` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 861 862;; Rotate left, shift amount in register. 32-bit or 64-bit types. 863(rule 0 (lower (has_type (ty_32_or_64 ty) (rotl _ x y))) 864 (rot_reg ty x (amt_reg y))) 865 866;; Rotate left arithmetic, immediate shift amount. 32-bit or 64-bit types. 867(rule 1 (lower (has_type (ty_32_or_64 ty) (rotl _ x (i64_from_value y)))) 868 (let ((masked_amt u8 (mask_amt_imm ty y))) 869 (rot_imm ty x masked_amt))) 870 871;; Rotate left, shift amount in register. 8-bit or 16-bit types. 872;; Implemented via a pair of 32-bit shifts on the zero-extended input. 873(rule 2 (lower (has_type (ty_8_or_16 ty) (rotl _ x y))) 874 (let ((ext_reg Reg (put_in_reg_zext32 x)) 875 (ext_ty Type (ty_ext32 ty)) 876 (pos_amt Reg (amt_reg y)) 877 (neg_amt Reg (neg_reg $I32 pos_amt)) 878 (masked_pos_amt Reg (mask_amt_reg ty pos_amt)) 879 (masked_neg_amt Reg (mask_amt_reg ty neg_amt))) 880 (or_reg ty (lshl_reg ext_ty ext_reg masked_pos_amt) 881 (lshr_reg ext_ty ext_reg masked_neg_amt)))) 882 883;; Rotate left, immediate shift amount. 8-bit or 16-bit types. 884;; Implemented via a pair of 32-bit shifts on the zero-extended input. 885(rule 3 (lower (has_type (ty_8_or_16 ty) (rotl _ x (and (i64_from_value pos_amt) 886 (i64_from_negated_value neg_amt))))) 887 (let ((ext_reg Reg (put_in_reg_zext32 x)) 888 (ext_ty Type (ty_ext32 ty)) 889 (masked_pos_amt u8 (mask_amt_imm ty pos_amt)) 890 (masked_neg_amt u8 (mask_amt_imm ty neg_amt))) 891 (or_reg ty (lshl_imm ext_ty ext_reg masked_pos_amt) 892 (lshr_imm ext_ty ext_reg masked_neg_amt)))) 893 894;; Vector rotate left, shift amount in register. 895(rule 4 (lower (has_type (ty_vec128 ty) (rotl _ x y))) 896 (vec_rot_reg ty x (amt_reg y))) 897 898;; Vector rotate left, immediate shift amount. 899(rule 5 (lower (has_type (ty_vec128 ty) (rotl _ x (i64_from_value y)))) 900 (let ((masked_amt u8 (mask_amt_imm ty y))) 901 (vec_rot_imm ty x masked_amt))) 902 903;; 128-bit full vector rotate left. 904;; Implemented via a pair of 128-bit full vector shifts. 905(rule 6 (lower (has_type $I128 (rotl _ x y))) 906 (let ((x_reg Reg x) 907 (pos_amt Reg (amt_vr y)) 908 (neg_amt Reg (vec_neg $I8X16 pos_amt))) 909 (vec_or $I128 910 (vec_lshl_by_bit (vec_lshl_by_byte x_reg pos_amt) pos_amt) 911 (vec_lshr_by_bit (vec_lshr_by_byte x_reg neg_amt) neg_amt)))) 912 913 914;;;; Rules for `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 915 916;; Rotate right, shift amount in register. 32-bit or 64-bit types. 917;; Implemented as rotate left with negated rotate amount. 918(rule 0 (lower (has_type (ty_32_or_64 ty) (rotr _ x y))) 919 (let ((negated_amt Reg (neg_reg $I32 (amt_reg y)))) 920 (rot_reg ty x negated_amt))) 921 922;; Rotate right arithmetic, immediate shift amount. 32-bit or 64-bit types. 923;; Implemented as rotate left with negated rotate amount. 924(rule 1 (lower (has_type (ty_32_or_64 ty) (rotr _ x (i64_from_negated_value y)))) 925 (let ((negated_amt u8 (mask_amt_imm ty y))) 926 (rot_imm ty x negated_amt))) 927 928;; Rotate right, shift amount in register. 8-bit or 16-bit types. 929;; Implemented as rotate left with negated rotate amount. 930(rule 2 (lower (has_type (ty_8_or_16 ty) (rotr _ x y))) 931 (let ((ext_reg Reg (put_in_reg_zext32 x)) 932 (ext_ty Type (ty_ext32 ty)) 933 (pos_amt Reg (amt_reg y)) 934 (neg_amt Reg (neg_reg $I32 pos_amt)) 935 (masked_pos_amt Reg (mask_amt_reg ty pos_amt)) 936 (masked_neg_amt Reg (mask_amt_reg ty neg_amt))) 937 (or_reg ty (lshl_reg ext_ty ext_reg masked_neg_amt) 938 (lshr_reg ext_ty ext_reg masked_pos_amt)))) 939 940;; Rotate right, immediate shift amount. 8-bit or 16-bit types. 941;; Implemented as rotate left with negated rotate amount. 942(rule 3 (lower (has_type (ty_8_or_16 ty) (rotr _ x (and (i64_from_value pos_amt) 943 (i64_from_negated_value neg_amt))))) 944 (let ((ext_reg Reg (put_in_reg_zext32 x)) 945 (ext_ty Type (ty_ext32 ty)) 946 (masked_pos_amt u8 (mask_amt_imm ty pos_amt)) 947 (masked_neg_amt u8 (mask_amt_imm ty neg_amt))) 948 (or_reg ty (lshl_imm ext_ty ext_reg masked_neg_amt) 949 (lshr_imm ext_ty ext_reg masked_pos_amt)))) 950 951;; Vector rotate right, shift amount in register. 952;; Implemented as rotate left with negated rotate amount. 953(rule 4 (lower (has_type (ty_vec128 ty) (rotr _ x y))) 954 (let ((negated_amt Reg (neg_reg $I32 (amt_reg y)))) 955 (vec_rot_reg ty x negated_amt))) 956 957;; Vector rotate right, immediate shift amount. 958;; Implemented as rotate left with negated rotate amount. 959(rule 5 (lower (has_type (ty_vec128 ty) (rotr _ x (i64_from_negated_value y)))) 960 (let ((negated_amt u8 (mask_amt_imm ty y))) 961 (vec_rot_imm ty x negated_amt))) 962 963;; 128-bit full vector rotate right. 964;; Implemented via a pair of 128-bit full vector shifts. 965(rule 6 (lower (has_type $I128 (rotr _ x y))) 966 (let ((x_reg Reg x) 967 (pos_amt Reg (amt_vr y)) 968 (neg_amt Reg (vec_neg $I8X16 pos_amt))) 969 (vec_or $I128 970 (vec_lshl_by_bit (vec_lshl_by_byte x_reg neg_amt) neg_amt) 971 (vec_lshr_by_bit (vec_lshr_by_byte x_reg pos_amt) pos_amt)))) 972 973 974;;;; Rules for `ireduce` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 975 976;; Up to 64-bit source type: Always a no-op. 977(rule 1 (lower (ireduce _ x @ (value_type (fits_in_64 _ty)))) 978 x) 979 980;; 128-bit source type: Extract the low half. 981(rule (lower (ireduce _ x @ (value_type (vr128_ty _ty)))) 982 (vec_extract_lane $I64X2 x 1 (zero_reg))) 983 984 985;;;; Rules for `uextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 986 987;; 16- or 32-bit target types. 988(rule 1 (lower (has_type (gpr32_ty _ty) (uextend _ x))) 989 (put_in_reg_zext32 x)) 990 991;; 64-bit target types. 992(rule 2 (lower (has_type (gpr64_ty _ty) (uextend _ x))) 993 (put_in_reg_zext64 x)) 994 995;; 128-bit target types. 996(rule (lower (has_type $I128 (uextend _ x @ (value_type $I8)))) 997 (vec_insert_lane $I8X16 (vec_imm $I128 0) x 15 (zero_reg))) 998(rule (lower (has_type $I128 (uextend _ x @ (value_type $I16)))) 999 (vec_insert_lane $I16X8 (vec_imm $I128 0) x 7 (zero_reg))) 1000(rule (lower (has_type $I128 (uextend _ x @ (value_type $I32)))) 1001 (vec_insert_lane $I32X4 (vec_imm $I128 0) x 3 (zero_reg))) 1002(rule (lower (has_type $I128 (uextend _ x @ (value_type $I64)))) 1003 (vec_insert_lane $I64X2 (vec_imm $I128 0) x 1 (zero_reg))) 1004 1005 1006;;;; Rules for `sextend` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1007 1008;; 16- or 32-bit target types. 1009(rule 1 (lower (has_type (gpr32_ty _ty) (sextend _ x))) 1010 (put_in_reg_sext32 x)) 1011 1012;; 64-bit target types. 1013(rule 2 (lower (has_type (gpr64_ty _ty) (sextend _ x))) 1014 (put_in_reg_sext64 x)) 1015 1016;; 128-bit target types. 1017(rule (lower (has_type $I128 (sextend _ x))) 1018 (let ((x_ext Reg (put_in_reg_sext64 x))) 1019 (mov_to_vec128 $I128 (ashr_imm $I64 x_ext 63) x_ext))) 1020 1021 1022;;;; Rules for `snarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1023 1024(rule (lower (snarrow _ x @ (value_type (ty_vec128 ty)) y)) 1025 (vec_pack_ssat_lane_order ty x y)) 1026 1027 1028;;;; Rules for `uunarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1029 1030(rule (lower (uunarrow _ x @ (value_type (ty_vec128 ty)) y)) 1031 (vec_pack_usat_lane_order ty x y)) 1032 1033 1034;;;; Rules for `unarrow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1035 1036(rule (lower (unarrow _ x @ (value_type (ty_vec128 ty)) y)) 1037 (let ((zero Reg (vec_imm ty 0))) 1038 (vec_pack_usat_lane_order ty (vec_smax ty x zero) (vec_smax ty y zero)))) 1039 1040 1041;;;; Rules for `swiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1042 1043(rule (lower (swiden_low _ x @ (value_type (ty_vec128 ty)))) 1044 (vec_unpacks_low_lane_order ty x)) 1045 1046 1047;;;; Rules for `swiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1048 1049(rule (lower (swiden_high _ x @ (value_type (ty_vec128 ty)))) 1050 (vec_unpacks_high_lane_order ty x)) 1051 1052 1053;;;; Rules for `uwiden_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1054 1055(rule (lower (uwiden_low _ x @ (value_type (ty_vec128 ty)))) 1056 (vec_unpacku_low_lane_order ty x)) 1057 1058 1059;;;; Rules for `uwiden_high` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1060 1061(rule (lower (uwiden_high _ x @ (value_type (ty_vec128 ty)))) 1062 (vec_unpacku_high_lane_order ty x)) 1063 1064 1065;;;; Rules for `bnot` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1066 1067;; z15 version using a single instruction (NOR). 1068(rule 2 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bnot _ x))) 1069 (let ((rx Reg x)) 1070 (not_or_reg ty rx rx))) 1071 1072;; z14 version using XOR with -1. 1073(rule 1 (lower (has_type (and (mie3_disabled) (fits_in_64 ty)) (bnot _ x))) 1074 (not_reg ty x)) 1075 1076;; Vector version using vector NOR. 1077(rule (lower (has_type (vr128_ty ty) (bnot _ x))) 1078 (vec_not ty x)) 1079 1080;; Float version using vector NOR. 1081(rule 5 (lower (has_type (ty_scalar_float _) (bnot _ x))) 1082 (vec_not $F64X2 x)) 1083 1084;; With z15 (bnot (bxor ...)) can be a single instruction, similar to the 1085;; (bxor _ (bnot _)) lowering. 1086(rule 3 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bnot _ (bxor _ x y)))) 1087 (not_xor_reg ty x y)) 1088 1089;; Combine a not/xor operation of vector types into one. 1090(rule 4 (lower (has_type (vr128_ty ty) (bnot _ (bxor _ x y)))) 1091 (vec_not_xor ty x y)) 1092 1093 1094;;;; Rules for `band` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1095 1096;; And two registers. 1097(rule -1 (lower (has_type (fits_in_64 ty) (band _ x y))) 1098 (and_reg ty x y)) 1099 1100;; And a register and an immediate. 1101(rule 5 (lower (has_type (fits_in_64 ty) (band _ x (uimm16shifted_from_inverted_value y)))) 1102 (and_uimm16shifted ty x y)) 1103(rule 6 (lower (has_type (fits_in_64 ty) (band _ (uimm16shifted_from_inverted_value x) y))) 1104 (and_uimm16shifted ty y x)) 1105(rule 3 (lower (has_type (fits_in_64 ty) (band _ x (uimm32shifted_from_inverted_value y)))) 1106 (and_uimm32shifted ty x y)) 1107(rule 4 (lower (has_type (fits_in_64 ty) (band _ (uimm32shifted_from_inverted_value x) y))) 1108 (and_uimm32shifted ty y x)) 1109 1110;; And a register and memory (32/64-bit types). 1111(rule 1 (lower (has_type (fits_in_64 ty) (band _ x (sinkable_load_32_64 y)))) 1112 (and_mem ty x (sink_load y))) 1113(rule 2 (lower (has_type (fits_in_64 ty) (band _ (sinkable_load_32_64 x) y))) 1114 (and_mem ty y (sink_load x))) 1115 1116;; And two vector registers. 1117(rule 0 (lower (has_type (vr128_ty ty) (band _ x y))) 1118 (vec_and ty x y)) 1119 1120;; And two float registers, using vector overlay. 1121(rule 11 (lower (has_type (ty_scalar_float _) (band _ x y))) 1122 (vec_and $F64X2 x y)) 1123 1124(rule 12 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ x y) z))) 1125 (vec_eval ty 0b00000001 x y z)) 1126(rule 13 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (band _ y z)))) 1127 (vec_eval ty 0b00000001 x y z)) 1128 1129;; Specialized lowerings for `(band x (bnot y))` which is additionally produced 1130;; by Cranelift's `band_not` instruction that is legalized into the simpler 1131;; forms early on. 1132 1133;; z15 version using a single instruction. 1134(rule 7 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (band _ x (bnot _ y)))) 1135 (and_not_reg ty x y)) 1136(rule 8 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (band _ (bnot _ y) x))) 1137 (and_not_reg ty x y)) 1138 1139;; And-not two vector registers. 1140(rule 9 (lower (has_type (vr128_ty ty) (band _ x (bnot _ y)))) 1141 (vec_and_not ty x y)) 1142(rule 10 (lower (has_type (vr128_ty ty) (band _ (bnot _ y) x))) 1143 (vec_and_not ty x y)) 1144 1145;; And-not three vector registers. 1146(rule 14 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ (bnot _ x) y) z))) 1147 (vec_eval ty 0b00010000 x y z)) 1148(rule 15 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ x) (band _ y z)))) 1149 (vec_eval ty 0b00010000 x y z)) 1150(rule 16 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ x y) (bnot _ z)))) 1151 (vec_eval ty 0b00000010 x y z)) 1152(rule 17 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (band _ y (bnot _ z))))) 1153 (vec_eval ty 0b00000010 x y z)) 1154(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (band _ x (bnot _ y)) z))) 1155 (vec_eval ty 0b00000100 y x z)) 1156(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (band _ (bnot _ y) z)))) 1157 (vec_eval ty 0b00000100 z x y)) 1158 1159;; Not-and three vector registers 1160(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (band _ (band _ x y) z)))) 1161 (vec_eval ty 0b11111110 x y z)) 1162(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (band _ x (band _ y z))))) 1163 (vec_eval ty 0b11111110 x y z)) 1164 1165;; And-Nand three vector registers 1166(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ (band _ x y)) z))) 1167 (vec_eval ty 0b01010100 x y z)) 1168(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bnot _ (band _ y z))))) 1169 (vec_eval ty 0b00001110 x y z)) 1170 1171;; And-Or 3 vector registers 1172(rule 22 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bor _ y z)))) 1173 (vec_eval ty 0b00000111 x y z)) 1174(rule 23 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bor _ x y) z))) 1175 (vec_eval ty 0b00010101 x y z)) 1176 1177;; And-Nor 3 vector registers 1178(rule 24 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bnot _ (bor _ y z))))) 1179 (vec_eval ty 0b00001000 x y z)) 1180(rule 25 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ (bor _ x y)) z))) 1181 (vec_eval ty 0b01000000 x y z)) 1182 1183;; And-Xor 3 vector registers 1184(rule 26 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bxor _ y z)))) 1185 (vec_eval ty 0b00000110 x y z)) 1186(rule 27 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bxor _ x y) z))) 1187 (vec_eval ty 0b00010100 x y z)) 1188 1189;; And-Nxor 3 vector registers 1190(rule 28 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ x (bnot _ (bxor _ y z))))) 1191 (vec_eval ty 0b00001001 x y z)) 1192(rule 29 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (band _ (bnot _ (bxor _ x y)) z))) 1193 (vec_eval ty 0b01000001 x y z)) 1194 1195;;;; Rules for `bor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1196 1197;; Or two registers. 1198(rule -1 (lower (has_type (fits_in_64 ty) (bor _ x y))) 1199 (or_reg ty x y)) 1200 1201;; Or a register and an immediate. 1202(rule 5 (lower (has_type (fits_in_64 ty) (bor _ x (uimm16shifted_from_value y)))) 1203 (or_uimm16shifted ty x y)) 1204(rule 6 (lower (has_type (fits_in_64 ty) (bor _ (uimm16shifted_from_value x) y))) 1205 (or_uimm16shifted ty y x)) 1206(rule 3 (lower (has_type (fits_in_64 ty) (bor _ x (uimm32shifted_from_value y)))) 1207 (or_uimm32shifted ty x y)) 1208(rule 4 (lower (has_type (fits_in_64 ty) (bor _ (uimm32shifted_from_value x) y))) 1209 (or_uimm32shifted ty y x)) 1210 1211;; Or a register and memory (32/64-bit types). 1212(rule 1 (lower (has_type (fits_in_64 ty) (bor _ x (sinkable_load_32_64 y)))) 1213 (or_mem ty x (sink_load y))) 1214(rule 2 (lower (has_type (fits_in_64 ty) (bor _ (sinkable_load_32_64 x) y))) 1215 (or_mem ty y (sink_load x))) 1216 1217;; Or two vector registers. 1218(rule 0 (lower (has_type (vr128_ty ty) (bor _ x y))) 1219 (vec_or ty x y)) 1220 1221;; Or two floating registers, using vector overlay 1222(rule 11 (lower (has_type (ty_scalar_float _) (bor _ x y))) 1223 (vec_or $F64X2 x y)) 1224 1225;; Or three vector registers. 1226(rule 12 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ x y) z))) 1227 (vec_eval ty 0b01111111 x y z)) 1228(rule 13 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bor _ y z)))) 1229 (vec_eval ty 0b01111111 x y z)) 1230 1231;; Specialized lowerings for `(bor x (bnot y))` which is additionally produced 1232;; by Cranelift's `bor_not` instruction that is legalized into the simpler 1233;; forms early on. 1234 1235;; z15 version using a single instruction. 1236(rule 7 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bor _ x (bnot _ y)))) 1237 (or_not_reg ty x y)) 1238(rule 8 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bor _ (bnot _ y) x))) 1239 (or_not_reg ty x y)) 1240 1241;; Or-not two vector registers. 1242(rule 9 (lower (has_type (vr128_ty ty) (bor _ x (bnot _ y)))) 1243 (vec_or_not ty x y)) 1244(rule 10 (lower (has_type (vr128_ty ty) (bor _ (bnot _ y) x))) 1245 (vec_or_not ty x y)) 1246 1247;; 3-input bor with a single not 1248(rule 14 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ (bnot _ x) y) z))) 1249 (vec_eval ty 0b11110111 x y z)) 1250(rule 15 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ x) (bor _ y z)))) 1251 (vec_eval ty 0b11110111 x y z)) 1252(rule 16 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ x (bnot _ y)) z))) 1253 (vec_eval ty 0b11011111 x y z)) 1254(rule 17 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bor _ (bnot _ y) z)))) 1255 (vec_eval ty 0b11011111 x y z)) 1256(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bor _ x y) (bnot _ z)))) 1257 (vec_eval ty 0b10111111 x y z)) 1258(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bor _ y (bnot _ z))))) 1259 (vec_eval ty 0b10111111 x y z)) 1260 1261;; 3-input bnor 1262(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bor _ x y) z)))) 1263 (vec_eval ty 0b10000000 x y z)) 1264(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bor _ y z))))) 1265 (vec_eval ty 0b10000000 x y z)) 1266 1267;; Or-Nor 1268(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ (bor _ x y)) z))) 1269 (vec_eval ty 0b11010101 x y z)) 1270(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bnot _ (bor _ y z))))) 1271 (vec_eval ty 0b10001111 x y z)) 1272 1273;; Or-And 1274(rule 22 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (band _ x y) z))) 1275 (vec_eval ty 0b01010111 x y z)) 1276(rule 23 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (band _ y z)))) 1277 (vec_eval ty 0b00011111 x y z)) 1278 1279;; Or-Nand 1280(rule 24 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ (band _ x y)) z))) 1281 (vec_eval ty 0b11111101 x y z)) 1282(rule 25 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bnot _ (band _ y z))))) 1283 (vec_eval ty 0b11101111 x y z)) 1284 1285;; Or-Xor 1286(rule 26 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bxor _ x y) z))) 1287 (vec_eval ty 0b01111101 x y z)) 1288(rule 27 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bxor _ y z)))) 1289 (vec_eval ty 0b01101111 x y z)) 1290 1291;; Or-Nxor 1292(rule 28 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ (bnot _ (bxor _ x y)) z))) 1293 (vec_eval ty 0b11010111 x y z)) 1294(rule 29 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bor _ x (bnot _ (bxor _ y z))))) 1295 (vec_eval ty 0b10011111 x y z)) 1296 1297;; Nor-And 1298(rule 30 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (band _ x y) z)))) 1299 (vec_eval ty 0b10101000 x y z)) 1300(rule 31 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (band _ y z))))) 1301 (vec_eval ty 0b11100000 x y z)) 1302 1303;; Nor-Nand 1304(rule 32 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bnot _ (band _ x y)) z)))) 1305 (vec_eval ty 0b00000010 x y z)) 1306(rule 33 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bnot _ (band _ y z)))))) 1307 (vec_eval ty 0b00010000 x y z)) 1308 1309;; Nor-Xor 1310(rule 34 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bxor _ x y) z)))) 1311 (vec_eval ty 0b10000010 x y z)) 1312(rule 35 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bxor _ y z))))) 1313 (vec_eval ty 0b10010000 x y z)) 1314 1315;; Nor-Nxor 1316(rule 36 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ (bnot _ (bxor _ x y)) z)))) 1317 (vec_eval ty 0b00101000 x y z)) 1318(rule 37 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bor _ x (bnot _ (bxor _ y z)))))) 1319 (vec_eval ty 0b01100000 x y z)) 1320 1321;;;; Rules for `bxor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1322 1323;; Xor two registers. 1324(rule -1 (lower (has_type (fits_in_64 ty) (bxor _ x y))) 1325 (xor_reg ty x y)) 1326 1327;; Xor a register and an immediate. 1328(rule 3 (lower (has_type (fits_in_64 ty) (bxor _ x (uimm32shifted_from_value y)))) 1329 (xor_uimm32shifted ty x y)) 1330(rule 4 (lower (has_type (fits_in_64 ty) (bxor _ (uimm32shifted_from_value x) y))) 1331 (xor_uimm32shifted ty y x)) 1332 1333;; Xor a register and memory (32/64-bit types). 1334(rule 1 (lower (has_type (fits_in_64 ty) (bxor _ x (sinkable_load_32_64 y)))) 1335 (xor_mem ty x (sink_load y))) 1336(rule 2 (lower (has_type (fits_in_64 ty) (bxor _ (sinkable_load_32_64 x) y))) 1337 (xor_mem ty y (sink_load x))) 1338 1339;; Xor two vector registers. 1340(rule 0 (lower (has_type (vr128_ty ty) (bxor _ x y))) 1341 (vec_xor ty x y)) 1342 1343;; Xor two floating registers, using vector overlay 1344(rule 9 (lower (has_type (ty_scalar_float _) (bxor _ x y))) 1345 (vec_xor $F64X2 x y)) 1346 1347;; Specialized lowerings for `(bxor x (bnot y))` which is additionally produced 1348;; by Cranelift's `bxor_not` instruction that is legalized into the simpler 1349;; forms early on. 1350 1351;; z15 version using a single instruction. 1352(rule 5 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bxor _ x (bnot _ y)))) 1353 (not_xor_reg ty x y)) 1354(rule 6 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bxor _ (bnot _ y) x))) 1355 (not_xor_reg ty x y)) 1356 1357;; Xor-not two vector registers. 1358(rule 7 (lower (has_type (vr128_ty ty) (bxor _ x (bnot _ y)))) 1359 (vec_not_xor ty x y)) 1360(rule 8 (lower (has_type (vr128_ty ty) (bxor _ (bnot _ y) x))) 1361 (vec_not_xor ty x y)) 1362 1363;; 3-input Xor 1364(rule 10 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bxor _ x y) z))) 1365 (vec_eval ty 0b01101001 x y z)) 1366(rule 11 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bxor _ y z)))) 1367 (vec_eval ty 0b01101001 x y z)) 1368 1369;; Xor-And 1370(rule 12 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (band _ x y) z))) 1371 (vec_eval ty 0b01010110 x y z)) 1372(rule 13 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (band _ y z)))) 1373 (vec_eval ty 0b00011110 x y z)) 1374 1375;; Xor-Nand 1376(rule 14 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bnot _ (band _ x y)) z))) 1377 (vec_eval ty 0b10101001 x y z)) 1378(rule 15 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bnot _ (band _ y z))))) 1379 (vec_eval ty 0b11100001 x y z)) 1380 1381;; Xor-Or 1382(rule 16 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bor _ x y) z))) 1383 (vec_eval ty 0b01101010 x y z)) 1384(rule 17 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bor _ y z)))) 1385 (vec_eval ty 0b01111000 x y z)) 1386 1387;; Xor-Nor 1388(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bnot _ (bor _ x y)) z))) 1389 (vec_eval ty 0b10010101 x y z)) 1390(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bnot _ (bor _ y z))))) 1391 (vec_eval ty 0b10000111 x y z)) 1392 1393;; Xor-Nxor 1394(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ (bnot _ (bxor _ x y)) z))) 1395 (vec_eval ty 0b10010110 x y z)) 1396(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bxor _ x (bnot _ (bxor _ y z))))) 1397 (vec_eval ty 0b10010110 x y z)) 1398 1399;; 3-input Nxor 1400(rule 20 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bxor _ x y) z)))) 1401 (vec_eval ty 0b10010110 x y z)) 1402(rule 21 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bxor _ y z))))) 1403 (vec_eval ty 0b10010110 x y z)) 1404 1405;; Nxor-And 1406(rule 22 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (band _ x y) z)))) 1407 (vec_eval ty 0b10101001 x y z)) 1408(rule 23 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (band _ y z))))) 1409 (vec_eval ty 0b11100001 x y z)) 1410 1411;; Nxor-Nand 1412(rule 24 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bnot _ (band _ x y)) z)))) 1413 (vec_eval ty 0b01010110 x y z)) 1414(rule 25 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bnot _ (band _ y z)))))) 1415 (vec_eval ty 0b00011110 x y z)) 1416 1417;; Nxor-Or 1418(rule 26 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bor _ x y) z)))) 1419 (vec_eval ty 0b10010101 x y z)) 1420(rule 27 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bor _ y z))))) 1421 (vec_eval ty 0b10000111 x y z)) 1422 1423;; Nxor-Nor 1424(rule 28 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bnot _ (bor _ x y)) z)))) 1425 (vec_eval ty 0b01101010 x y z)) 1426(rule 29 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bnot _ (bor _ y z)))))) 1427 (vec_eval ty 0b01111000 x y z)) 1428 1429;; Xor-Nxor 1430(rule 18 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ (bnot _ (bxor _ x y)) z)))) 1431 (vec_eval ty 0b01101001 x y z)) 1432(rule 19 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bnot _ (bxor _ x (bnot _ (bxor _ y z)))))) 1433 (vec_eval ty 0b01101001 x y z)) 1434 1435;;;; Rules for `bitselect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1436 1437;; z15 version using a NAND instruction. 1438(rule 2 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (bitselect _ x y z))) 1439 (let ((rx Reg x) 1440 (if_true Reg (and_reg ty y rx)) 1441 (if_false Reg (and_not_reg ty z rx))) 1442 (or_reg ty if_false if_true))) 1443 1444;; z14 version using XOR with -1. 1445(rule 1 (lower (has_type (and (mie3_disabled) (fits_in_64 ty)) (bitselect _ x y z))) 1446 (let ((rx Reg x) 1447 (if_true Reg (and_reg ty y rx)) 1448 (if_false Reg (and_reg ty z (not_reg ty rx)))) 1449 (or_reg ty if_false if_true))) 1450 1451;; Bitselect vector registers. 1452(rule (lower (has_type (vr128_ty ty) (bitselect _ x y z))) 1453 (vec_select ty y z x)) 1454 1455;; Bitselect-not vector registers. 1456(rule 5 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bitselect _ x (bnot _ y) z))) 1457 (vec_eval ty 0b01011100 x y z)) 1458(rule 6 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bitselect _ x y (bnot _ z)))) 1459 (vec_eval ty 0b10100011 x y z)) 1460(rule 7 (lower (has_type (and (vxrs_ext3_enabled) (vr128_ty ty)) (bitselect _ x (bnot _ y) (bnot _ z)))) 1461 (vec_eval ty 0b10101100 x y z)) 1462 1463;; Special-case some float-selection instructions for min/max 1464(rule 3 (lower (has_type (ty_vec128 ty) (bitselect _ (bitcast _ _ (fcmp _ (FloatCC.LessThan) x y)) x y))) 1465 (fmin_pseudo_reg ty y x)) 1466(rule 4 (lower (has_type (ty_vec128 ty) (bitselect _ (bitcast _ _ (fcmp _ (FloatCC.LessThan) y x)) x y))) 1467 (fmax_pseudo_reg ty y x)) 1468 1469 1470 1471;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1472 1473(rule (lower (has_type ty (bmask _ x))) 1474 (lower_bool_to_mask ty (value_nonzero x))) 1475 1476 1477;;;; Rules for `bitrev` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1478 1479(rule (lower (has_type ty (bitrev _ x))) 1480 (bitrev_bytes ty 1481 (bitrev_bits 4 0xf0f0_f0f0_f0f0_f0f0 ty 1482 (bitrev_bits 2 0xcccc_cccc_cccc_cccc ty 1483 (bitrev_bits 1 0xaaaa_aaaa_aaaa_aaaa ty x))))) 1484 1485(decl bitrev_bits (u8 u64 Type Reg) Reg) 1486(rule 1 (bitrev_bits size bitmask (fits_in_64 ty) x) 1487 (let ((mask Reg (imm ty bitmask)) 1488 (xh Reg (lshl_imm (ty_ext32 ty) x size)) 1489 (xl Reg (lshr_imm (ty_ext32 ty) x size)) 1490 (xh_masked Reg (and_reg ty xh mask)) 1491 (xl_masked Reg (and_reg ty xl (not_reg ty mask)))) 1492 (or_reg ty xh_masked xl_masked))) 1493 1494(rule (bitrev_bits size bitmask (vr128_ty ty) x) 1495 (let ((mask Reg (vec_imm_splat $I64X2 bitmask)) 1496 (size_reg Reg (vec_imm_splat $I8X16 size)) 1497 (xh Reg (vec_lshl_by_bit x size_reg)) 1498 (xl Reg (vec_lshr_by_bit x size_reg))) 1499 (vec_select ty xh xl mask))) 1500 1501(decl bitrev_bytes (Type Reg) Reg) 1502(rule (bitrev_bytes $I8 x) x) 1503(rule (bitrev_bytes $I16 x) (lshr_imm $I32 (bswap_reg $I32 x) 16)) 1504(rule (bitrev_bytes $I32 x) (bswap_reg $I32 x)) 1505(rule (bitrev_bytes $I64 x) (bswap_reg $I64 x)) 1506(rule (bitrev_bytes $I128 x) 1507 (vec_permute $I128 x x 1508 (vec_imm $I8X16 (imm8x16 15 14 13 12 11 10 9 8 1509 7 6 5 4 3 2 1 0)))) 1510 1511 1512;;;; Rules for `bswap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1513 1514(rule (lower (has_type ty (bswap _ x))) 1515 (bitrev_bytes ty x)) 1516 1517;;;; Rules for `clz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1518 1519;; The FLOGR hardware instruction always operates on the full 64-bit register. 1520;; We can zero-extend smaller types, but then we have to compensate for the 1521;; additional leading zero bits the instruction will actually see. 1522(decl clz_offset (Type Reg) Reg) 1523(rule (clz_offset $I8 x) (add_simm16 $I8 x -56)) 1524(rule (clz_offset $I16 x) (add_simm16 $I16 x -48)) 1525(rule (clz_offset $I32 x) (add_simm16 $I32 x -32)) 1526(rule (clz_offset $I64 x) x) 1527 1528;; Count leading zeros pre-z17, via FLOGR on an input zero-extended to 64 bits, 1529;; with the result compensated for the extra bits. 1530(rule 1 (lower (has_type (and (mie4_disabled) (fits_in_64 ty)) (clz _ x))) 1531 (let ((ext_reg Reg (put_in_reg_zext64 x)) 1532 ;; Ask for a value of 64 in the all-zero 64-bit input case. 1533 ;; After compensation this will match the expected semantics. 1534 (clz Reg (clz_flogr_reg 64 ext_reg))) 1535 (clz_offset ty clz))) 1536 1537;; Count leading zeros, 128-bit full vector pre-z17. 1538(rule (lower (has_type (and (vxrs_ext3_disabled) $I128) (clz _ x))) 1539 (let ((clz_vec Reg (vec_clz $I64X2 x)) 1540 (zero Reg (vec_imm $I64X2 0)) 1541 (clz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 0)) 1542 (clz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 1)) 1543 (clz_sum Reg (vec_add $I64X2 clz_hi clz_lo)) 1544 (mask Reg (vec_cmpeq $I64X2 clz_hi (vec_imm_splat $I64X2 64)))) 1545 (vec_select $I128 clz_sum clz_hi mask))) 1546 1547;; Count leading zeros on z17, via CLZG on an input zero-extended to 64 bits, 1548;; with the result compensated for the extra bits. 1549(rule 3 (lower (has_type (and (mie4_enabled) (fits_in_64 ty)) (clz _ x))) 1550 (let ((ext_reg Reg (put_in_reg_zext64 x)) 1551 (clz Reg (clz_reg ext_reg))) 1552 (clz_offset ty clz))) 1553 1554;; Count leading zeros, 128-bit full vector on z17. 1555(rule 2 (lower (has_type (and (vxrs_ext3_enabled) $I128) (clz _ x))) 1556 (vec_clz $I128 x)) 1557 1558;;;; Rules for `cls` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1559 1560;; The result of cls is not supposed to count the sign bit itself, just 1561;; additional copies of it. Therefore, when computing cls in terms of clz, 1562;; we need to subtract one. Fold this into the offset computation. 1563(decl cls_offset (Type Reg) Reg) 1564(rule (cls_offset $I8 x) (add_simm16 $I8 x -57)) 1565(rule (cls_offset $I16 x) (add_simm16 $I16 x -49)) 1566(rule (cls_offset $I32 x) (add_simm16 $I32 x -33)) 1567(rule (cls_offset $I64 x) (add_simm16 $I64 x -1)) 1568 1569;; Count leading sign-bit copies pre-z17. We don't have any instruction for that, 1570;; so we instead count the leading zeros after inverting the input if negative, 1571;; i.e. computing 1572;; cls(x) == clz(x ^ (x >> 63)) - 1 1573;; where x is the sign-extended input. 1574(rule 1 (lower (has_type (and (mie4_disabled) (fits_in_64 ty)) (cls _ x))) 1575 (let ((ext_reg Reg (put_in_reg_sext64 x)) 1576 (signbit_copies Reg (ashr_imm $I64 ext_reg 63)) 1577 (inv_reg Reg (xor_reg $I64 ext_reg signbit_copies)) 1578 (clz Reg (clz_flogr_reg 64 inv_reg))) 1579 (cls_offset ty clz))) 1580 1581;; Count leading sign-bit copies, 128-bit full vector pre-z17. 1582(rule (lower (has_type (and (vxrs_ext3_disabled) $I128) (cls _ x))) 1583 (let ((x_reg Reg x) 1584 (ones Reg (vec_imm_splat $I8X16 255)) 1585 (signbit_copies Reg (vec_ashr_by_bit (vec_ashr_by_byte x_reg ones) ones)) 1586 (inv_reg Reg (vec_xor $I128 x_reg signbit_copies)) 1587 (clz_vec Reg (vec_clz $I64X2 inv_reg)) 1588 (zero Reg (vec_imm $I64X2 0)) 1589 (clz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 0)) 1590 (clz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 clz_vec 1)) 1591 (clz_sum Reg (vec_add $I64X2 clz_hi clz_lo)) 1592 (mask Reg (vec_cmpeq $I64X2 clz_hi (vec_imm_splat $I64X2 64)))) 1593 (vec_add $I128 (vec_select $I128 clz_sum clz_hi mask) ones))) 1594 1595;; Count leading sign-bit copies on z17, similar to above. 1596(rule 3 (lower (has_type (and (mie4_enabled) (fits_in_64 ty)) (cls _ x))) 1597 (let ((ext_reg Reg (put_in_reg_sext64 x)) 1598 (signbit_copies Reg (ashr_imm $I64 ext_reg 63)) 1599 (inv_reg Reg (xor_reg $I64 ext_reg signbit_copies)) 1600 (clz Reg (clz_reg inv_reg))) 1601 (cls_offset ty clz))) 1602 1603;; Count leading sign-bit copies, 128-bit full vector on z17. 1604(rule 2 (lower (has_type (and (vxrs_ext3_enabled) $I128) (cls _ x))) 1605 (let ((x_reg Reg x) 1606 (ones Reg (vec_imm_splat $I8X16 255)) 1607 (signbit_copies Reg (vec_ashr_by_bit (vec_ashr_by_byte x_reg ones) ones)) 1608 (inv_reg Reg (vec_xor $I128 x_reg signbit_copies)) 1609 (clz_vec Reg (vec_clz $I128 inv_reg))) 1610 (vec_add $I128 clz_vec ones))) 1611 1612;;;; Rules for `ctz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1613 1614;; To count trailing zeros, we find the last bit set in the input via (x & -x), 1615;; count the leading zeros of that value, and subtract from 63: 1616;; 1617;; ctz(x) == 63 - clz(x & -x) 1618;; 1619;; This works for all cases except a zero input, where the above formula would 1620;; return -1, but we are expected to return the type size. The compensation 1621;; for this case is handled differently for 64-bit types vs. smaller types. 1622 1623;; For smaller types, we simply ensure that the extended 64-bit input is 1624;; never zero by setting a "guard bit" in the position corresponding to 1625;; the input type size. This way the 64-bit algorithm above will handle 1626;; that case correctly automatically. 1627(rule 2 (lower (has_type (and (mie4_disabled) (gpr32_ty ty)) (ctz _ x))) 1628 (let ((rx Reg (or_uimm16shifted $I64 x (ctz_guardbit ty))) 1629 (lastbit Reg (and_reg $I64 rx (neg_reg $I64 rx))) 1630 (clz Reg (clz_flogr_reg 64 lastbit))) 1631 (sub_reg ty (imm ty 63) clz))) 1632 1633(decl ctz_guardbit (Type) UImm16Shifted) 1634(rule (ctz_guardbit $I8) (uimm16shifted 256 0)) 1635(rule (ctz_guardbit $I16) (uimm16shifted 1 16)) 1636(rule (ctz_guardbit $I32) (uimm16shifted 1 32)) 1637 1638;; For 64-bit types, the FLOGR instruction will indicate the zero input case 1639;; via its condition code. We check for that and replace the instruction 1640;; result with the value -1 via a conditional move, which will then lead to 1641;; the correct result after the final subtraction from 63. 1642(rule 1 (lower (has_type (and (mie4_disabled) (gpr64_ty _ty)) (ctz _ x))) 1643 (let ((rx Reg x) 1644 (lastbit Reg (and_reg $I64 rx (neg_reg $I64 rx))) 1645 (clz Reg (clz_flogr_reg -1 lastbit))) 1646 (sub_reg $I64 (imm $I64 63) clz))) 1647 1648;; Count trailing zeros, 128-bit full vector pre-z17. 1649(rule 0 (lower (has_type (and (vxrs_ext3_disabled) $I128) (ctz _ x))) 1650 (let ((ctz_vec Reg (vec_ctz $I64X2 x)) 1651 (zero Reg (vec_imm $I64X2 0)) 1652 (ctz_hi Reg (vec_permute_dw_imm $I64X2 zero 0 ctz_vec 0)) 1653 (ctz_lo Reg (vec_permute_dw_imm $I64X2 zero 0 ctz_vec 1)) 1654 (ctz_sum Reg (vec_add $I64X2 ctz_hi ctz_lo)) 1655 (mask Reg (vec_cmpeq $I64X2 ctz_lo (vec_imm_splat $I64X2 64)))) 1656 (vec_select $I128 ctz_sum ctz_lo mask))) 1657 1658;; Count leading zeros on z17, via CTZG on types smaller than 64-bit, 1659;; using the same guard bit mechanism as above. 1660(rule 5 (lower (has_type (and (mie4_enabled) (gpr32_ty ty)) (ctz _ x))) 1661 (ctz_reg (or_uimm16shifted $I64 x (ctz_guardbit ty)))) 1662 1663;; Count leading zeros on z17, via CTZG directly on 64-bit types. 1664(rule 4 (lower (has_type (and (mie4_enabled) (gpr64_ty _ty)) (ctz _ x))) 1665 (ctz_reg x)) 1666 1667;; Count trailing zeros, 128-bit full vector on z17. 1668(rule 3 (lower (has_type (and (vxrs_ext3_enabled) $I128) (ctz _ x))) 1669 (vec_ctz $I128 x)) 1670 1671 1672;;;; Rules for `popcnt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1673 1674;; Population count for 8-bit types is supported by the POPCNT instruction. 1675(rule (lower (has_type $I8 (popcnt _ x))) 1676 (popcnt_byte x)) 1677 1678;; On z15, the POPCNT instruction has a variant to compute a full 64-bit 1679;; population count, which we also use for 16- and 32-bit types. 1680(rule -1 (lower (has_type (and (mie3_enabled) (fits_in_64 ty)) (popcnt _ x))) 1681 (popcnt_reg (put_in_reg_zext64 x))) 1682 1683;; On z14, we use the regular POPCNT, which computes the population count 1684;; of each input byte separately, so we need to accumulate those partial 1685;; results via a series of log2(type size in bytes) - 1 additions. We 1686;; accumulate in the high byte, so that a final right shift will zero out 1687;; any unrelated bits to give a clean result. (This does not work with 1688;; $I16, where we instead accumulate in the low byte and clear high bits 1689;; via an explicit and operation.) 1690 1691(rule (lower (has_type (and (mie3_disabled) $I16) (popcnt _ x))) 1692 (let ((cnt2 Reg (popcnt_byte x)) 1693 (cnt1 Reg (add_reg $I32 cnt2 (lshr_imm $I32 cnt2 8)))) 1694 (and_uimm16shifted $I32 cnt1 (uimm16shifted 255 0)))) 1695 1696(rule (lower (has_type (and (mie3_disabled) $I32) (popcnt _ x))) 1697 (let ((cnt4 Reg (popcnt_byte x)) 1698 (cnt2 Reg (add_reg $I32 cnt4 (lshl_imm $I32 cnt4 16))) 1699 (cnt1 Reg (add_reg $I32 cnt2 (lshl_imm $I32 cnt2 8)))) 1700 (lshr_imm $I32 cnt1 24))) 1701 1702(rule (lower (has_type (and (mie3_disabled) $I64) (popcnt _ x))) 1703 (let ((cnt8 Reg (popcnt_byte x)) 1704 (cnt4 Reg (add_reg $I64 cnt8 (lshl_imm $I64 cnt8 32))) 1705 (cnt2 Reg (add_reg $I64 cnt4 (lshl_imm $I64 cnt4 16))) 1706 (cnt1 Reg (add_reg $I64 cnt2 (lshl_imm $I64 cnt2 8)))) 1707 (lshr_imm $I64 cnt1 56))) 1708 1709;; Population count for vector types. 1710(rule 1 (lower (has_type (ty_vec128 ty) (popcnt _ x))) 1711 (vec_popcnt ty x)) 1712 1713;; Population count, 128-bit full vector. 1714(rule (lower (has_type $I128 (popcnt _ x))) 1715 (let ((popcnt_vec Reg (vec_popcnt $I64X2 x)) 1716 (zero Reg (vec_imm $I64X2 0)) 1717 (popcnt_hi Reg (vec_permute_dw_imm $I64X2 zero 0 popcnt_vec 0)) 1718 (popcnt_lo Reg (vec_permute_dw_imm $I64X2 zero 0 popcnt_vec 1))) 1719 (vec_add $I64X2 popcnt_hi popcnt_lo))) 1720 1721 1722;;;; Rules for `fadd` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1723 1724;; Add two registers. 1725(rule (lower (has_type ty (fadd _ x y))) 1726 (fadd_reg ty x y)) 1727 1728 1729;;;; Rules for `fsub` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1730 1731;; Subtract two registers. 1732(rule (lower (has_type ty (fsub _ x y))) 1733 (fsub_reg ty x y)) 1734 1735 1736;;;; Rules for `fmul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1737 1738;; Multiply two registers. 1739(rule (lower (has_type ty (fmul _ x y))) 1740 (fmul_reg ty x y)) 1741 1742 1743;;;; Rules for `fdiv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1744 1745;; Divide two registers. 1746(rule (lower (has_type ty (fdiv _ x y))) 1747 (fdiv_reg ty x y)) 1748 1749 1750;;;; Rules for `fmin` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1751 1752;; Minimum of two registers. 1753(rule (lower (has_type ty (fmin _ x y))) 1754 (fmin_reg ty x y)) 1755 1756 1757;;;; Rules for `fmax` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1758 1759;; Maximum of two registers. 1760(rule (lower (has_type ty (fmax _ x y))) 1761 (fmax_reg ty x y)) 1762 1763 1764;;;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1765 1766;; Copysign of two registers. 1767(rule (lower (has_type $F32 (fcopysign _ x y))) 1768 (vec_select $F32 x y (imm $F32 2147483647))) 1769(rule (lower (has_type $F64 (fcopysign _ x y))) 1770 (vec_select $F64 x y (imm $F64 9223372036854775807))) 1771(rule (lower (has_type $F128 (fcopysign _ x y))) 1772 (vec_select $F128 x y (vec_imm $F128 (imm8x16 127 255 255 255 255 255 255 255 1773 255 255 255 255 255 255 255 255)))) 1774(rule (lower (has_type $F32X4 (fcopysign _ x y))) 1775 (vec_select $F32X4 x y (vec_imm_bit_mask $F32X4 1 31))) 1776(rule (lower (has_type $F64X2 (fcopysign _ x y))) 1777 (vec_select $F64X2 x y (vec_imm_bit_mask $F64X2 1 63))) 1778 1779 1780;;;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1781 1782;; Multiply-and-add of three registers. 1783(rule (lower (has_type ty (fma _ x y z))) 1784 (fma_reg ty x y z)) 1785 1786 1787;;;; Rules for `sqrt` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1788 1789;; Square root of a register. 1790(rule (lower (has_type ty (sqrt _ x))) 1791 (sqrt_reg ty x)) 1792 1793 1794;;;; Rules for `fneg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1795 1796;; Negated value of a register. 1797(rule (lower (has_type ty (fneg _ x))) 1798 (fneg_reg ty x)) 1799 1800 1801;;;; Rules for `fabs` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1802 1803;; Absolute value of a register. 1804(rule (lower (has_type ty (fabs _ x))) 1805 (fabs_reg ty x)) 1806 1807 1808;;;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1809 1810;; Round value in a register towards positive infinity. 1811(rule (lower (has_type ty (ceil _ x))) 1812 (ceil_reg ty x)) 1813 1814 1815;;;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1816 1817;; Round value in a register towards negative infinity. 1818(rule (lower (has_type ty (floor _ x))) 1819 (floor_reg ty x)) 1820 1821 1822;;;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1823 1824;; Round value in a register towards zero. 1825(rule (lower (has_type ty (trunc _ x))) 1826 (trunc_reg ty x)) 1827 1828 1829;;;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1830 1831;; Round value in a register towards nearest. 1832(rule (lower (has_type ty (nearest _ x))) 1833 (nearest_reg ty x)) 1834 1835 1836;;;; Rules for `fpromote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1837 1838;; Promote a register. 1839(rule (lower (has_type dst_ty (fpromote _ x @ (value_type src_ty)))) 1840 (fpromote_reg dst_ty src_ty x)) 1841 1842(rule 1 (lower (has_type $F128 (fpromote _ x @ (value_type $F32)))) 1843 (fpromote_reg $F128 $F64 (fpromote_reg $F64 $F32 x))) 1844 1845 1846;;;; Rules for `fvpromote_low` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1847 1848;; Promote a register. 1849(rule (lower (has_type $F64X2 (fvpromote_low _ x @ (value_type $F32X4)))) 1850 (fpromote_reg $F64X2 $F32X4 (vec_merge_low_lane_order $I32X4 x x))) 1851 1852 1853;;;; Rules for `fdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1854 1855;; Demote a register. 1856(rule (lower (has_type dst_ty (fdemote _ x @ (value_type src_ty)))) 1857 (fdemote_reg dst_ty src_ty (FpuRoundMode.Current) x)) 1858 1859(rule 1 (lower (has_type $F32 (fdemote _ x @ (value_type $F128)))) 1860 (fdemote_reg $F32 $F64 (FpuRoundMode.Current) 1861 (fdemote_reg $F64 $F128 (FpuRoundMode.ShorterPrecision) x))) 1862 1863 1864;;;; Rules for `fvdemote` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1865 1866;; Demote a register. 1867(rule (lower (has_type $F32X4 (fvdemote _ x @ (value_type $F64X2)))) 1868 (let ((dst Reg (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.Current) x))) 1869 (vec_pack_lane_order $I64X2 (vec_lshr_imm $I64X2 dst 32) 1870 (vec_imm $I64X2 0)))) 1871 1872 1873;;;; Rules for `fcvt_from_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1874 1875;; Convert a 32-bit or smaller unsigned integer to $F32 (z15 instruction). 1876(rule 1 (lower (has_type $F32 1877 (fcvt_from_uint _ x @ (value_type (and (vxrs_ext2_enabled) (fits_in_32 ty)))))) 1878 (fcvt_from_uint_reg $F32 $I32 (FpuRoundMode.ToNearestTiesToEven) 1879 (put_in_reg_zext32 x))) 1880 1881;; Convert a 64-bit or smaller unsigned integer to $F32, via an intermediate $F64. 1882(rule (lower (has_type $F32 (fcvt_from_uint _ x @ (value_type (fits_in_64 ty))))) 1883 (fdemote_reg $F32 $F64 (FpuRoundMode.ToNearestTiesToEven) 1884 (fcvt_from_uint_reg $F64 $I64 (FpuRoundMode.ShorterPrecision) 1885 (put_in_reg_zext64 x)))) 1886 1887;; Convert a 64-bit or smaller unsigned integer to $F64. 1888(rule (lower (has_type $F64 (fcvt_from_uint _ x @ (value_type (fits_in_64 ty))))) 1889 (fcvt_from_uint_reg $F64 $I64 (FpuRoundMode.ToNearestTiesToEven) 1890 (put_in_reg_zext64 x))) 1891 1892;; Convert a 32-bit or smaller unsigned integer to $F128. 1893(rule 1 (lower (has_type $F128 (fcvt_from_uint _ x @ (value_type (fits_in_32 ty))))) 1894 (fcvt_from_uint_reg $F128 $I32 (FpuRoundMode.ToNearestTiesToEven) 1895 (put_in_reg_zext32 x))) 1896 1897;; Convert a 64-bit or smaller unsigned integer to $F128. 1898(rule (lower (has_type $F128 (fcvt_from_uint _ x @ (value_type (fits_in_64 ty))))) 1899 (fcvt_from_uint_reg $F128 $I64 (FpuRoundMode.ToNearestTiesToEven) 1900 (put_in_reg_zext64 x))) 1901 1902;; Convert $I32X4 to $F32X4 (z15 instruction). 1903(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $F32X4) 1904 (fcvt_from_uint _ x @ (value_type $I32X4)))) 1905 (fcvt_from_uint_reg $F32X4 $I32X4 (FpuRoundMode.ToNearestTiesToEven) x)) 1906 1907;; Convert $I32X4 to $F32X4 (via two $F64X2 on z14). 1908(rule (lower (has_type (and (vxrs_ext2_disabled) $F32X4) 1909 (fcvt_from_uint _ x @ (value_type $I32X4)))) 1910 (vec_permute $F32X4 1911 (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) 1912 (fcvt_from_uint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision) 1913 (vec_unpacku_high $I32X4 x))) 1914 (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) 1915 (fcvt_from_uint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision) 1916 (vec_unpacku_low $I32X4 x))) 1917 (vec_imm $I8X16 (imm8x16 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27)))) 1918 1919;; Convert $I64X2 to $F64X2. 1920(rule (lower (has_type $F64X2 (fcvt_from_uint _ x @ (value_type $I64X2)))) 1921 (fcvt_from_uint_reg $F64X2 $I64X2 (FpuRoundMode.ToNearestTiesToEven) x)) 1922 1923 1924;;;; Rules for `fcvt_from_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1925 1926;; Convert a 32-bit or smaller signed integer to $F32 (z15 instruction). 1927(rule 1 (lower (has_type $F32 1928 (fcvt_from_sint _ x @ (value_type (and (vxrs_ext2_enabled) (fits_in_32 ty)))))) 1929 (fcvt_from_sint_reg $F32 $I32 (FpuRoundMode.ToNearestTiesToEven) 1930 (put_in_reg_sext32 x))) 1931 1932;; Convert a 64-bit or smaller signed integer to $F32, via an intermediate $F64. 1933(rule (lower (has_type $F32 (fcvt_from_sint _ x @ (value_type (fits_in_64 ty))))) 1934 (fdemote_reg $F32 $F64 (FpuRoundMode.ToNearestTiesToEven) 1935 (fcvt_from_sint_reg $F64 $I64 (FpuRoundMode.ShorterPrecision) 1936 (put_in_reg_sext64 x)))) 1937 1938;; Convert a 64-bit or smaller signed integer to $F64. 1939(rule (lower (has_type $F64 (fcvt_from_sint _ x @ (value_type (fits_in_64 ty))))) 1940 (fcvt_from_sint_reg $F64 $I64 (FpuRoundMode.ToNearestTiesToEven) 1941 (put_in_reg_sext64 x))) 1942 1943;; Convert a 32-bit or smaller signed integer to $F128. 1944(rule 1 (lower (has_type $F128 (fcvt_from_sint _ x @ (value_type (fits_in_32 ty))))) 1945 (fcvt_from_sint_reg $F128 $I32 (FpuRoundMode.ToNearestTiesToEven) 1946 (put_in_reg_sext32 x))) 1947 1948;; Convert a 64-bit or smaller signed integer to $F128. 1949(rule (lower (has_type $F128 (fcvt_from_sint _ x @ (value_type (fits_in_64 ty))))) 1950 (fcvt_from_sint_reg $F128 $I64 (FpuRoundMode.ToNearestTiesToEven) 1951 (put_in_reg_sext64 x))) 1952 1953;; Convert $I32X4 to $F32X4 (z15 instruction). 1954(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $F32X4) 1955 (fcvt_from_sint _ x @ (value_type $I32X4)))) 1956 (fcvt_from_sint_reg $F32X4 $I32X4 (FpuRoundMode.ToNearestTiesToEven) x)) 1957 1958;; Convert $I32X4 to $F32X4 (via two $F64X2 on z14). 1959(rule (lower (has_type (and (vxrs_ext2_disabled) $F32X4) 1960 (fcvt_from_sint _ x @ (value_type $I32X4)))) 1961 (vec_permute $F32X4 1962 (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) 1963 (fcvt_from_sint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision) 1964 (vec_unpacks_high $I32X4 x))) 1965 (fdemote_reg $F32X4 $F64X2 (FpuRoundMode.ToNearestTiesToEven) 1966 (fcvt_from_sint_reg $F64X2 $I64X2 (FpuRoundMode.ShorterPrecision) 1967 (vec_unpacks_low $I32X4 x))) 1968 (vec_imm $I8X16 (imm8x16 0 1 2 3 8 9 10 11 16 17 18 19 24 25 26 27)))) 1969 1970;; Convert $I64X2 to $F64X2. 1971(rule (lower (has_type $F64X2 (fcvt_from_sint _ x @ (value_type $I64X2)))) 1972 (fcvt_from_sint_reg $F64X2 $I64X2 (FpuRoundMode.ToNearestTiesToEven) x)) 1973 1974 1975;;;; Rules for `fcvt_to_uint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1976 1977;; Convert a scalar floating-point value in a register to an unsigned integer. 1978;; Traps if the input cannot be represented in the output type. 1979(rule (lower (has_type (fits_in_64 dst_ty) 1980 (fcvt_to_uint _ x @ (value_type src_ty)))) 1981 (let ((src Reg (put_in_reg x)) 1982 ;; First, check whether the input is a NaN, and trap if so. 1983 (_ Reg (trap_if (fcmp_reg src_ty src src) 1984 (floatcc_as_cond (FloatCC.Unordered)) 1985 (trap_code_bad_conversion_to_integer))) 1986 ;; Now check whether the input is out of range for the target type. 1987 (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_uint_ub src_ty dst_ty)) 1988 (floatcc_as_cond (FloatCC.GreaterThanOrEqual)) 1989 (trap_code_integer_overflow))) 1990 (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_uint_lb src_ty)) 1991 (floatcc_as_cond (FloatCC.LessThanOrEqual)) 1992 (trap_code_integer_overflow))) 1993 ;; Perform the conversion using the larger type size. 1994 (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) 1995 (int_ty Type (fcvt_int_ty dst_ty src_ty)) 1996 (src_ext Reg (fpromote_reg flt_ty src_ty src))) 1997 (fcvt_to_uint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext))) 1998 1999 2000;;;; Rules for `fcvt_to_sint` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2001 2002;; Convert a scalar floating-point value in a register to a signed integer. 2003;; Traps if the input cannot be represented in the output type. 2004(rule (lower (has_type (fits_in_64 dst_ty) 2005 (fcvt_to_sint _ x @ (value_type src_ty)))) 2006 (let ((src Reg (put_in_reg x)) 2007 ;; First, check whether the input is a NaN, and trap if so. 2008 (_ Reg (trap_if (fcmp_reg src_ty src src) 2009 (floatcc_as_cond (FloatCC.Unordered)) 2010 (trap_code_bad_conversion_to_integer))) 2011 ;; Now check whether the input is out of range for the target type. 2012 (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_sint_ub src_ty dst_ty)) 2013 (floatcc_as_cond (FloatCC.GreaterThanOrEqual)) 2014 (trap_code_integer_overflow))) 2015 (_ Reg (trap_if (fcmp_reg src_ty src (fcvt_to_sint_lb src_ty dst_ty)) 2016 (floatcc_as_cond (FloatCC.LessThanOrEqual)) 2017 (trap_code_integer_overflow))) 2018 ;; Perform the conversion using the larger type size. 2019 (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) 2020 (int_ty Type (fcvt_int_ty dst_ty src_ty)) 2021 (src_ext Reg (fpromote_reg flt_ty src_ty src))) 2022 ;; Perform the conversion. 2023 (fcvt_to_sint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext))) 2024 2025 2026;;;; Rules for `fcvt_to_uint_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2027 2028;; Convert a scalar floating-point value in a register to an unsigned integer. 2029(rule -1 (lower (has_type (fits_in_64 dst_ty) 2030 (fcvt_to_uint_sat _ x @ (value_type src_ty)))) 2031 (let ((src Reg (put_in_reg x)) 2032 ;; Perform the conversion using the larger type size. 2033 (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) 2034 (int_ty Type (fcvt_int_ty dst_ty src_ty)) 2035 (src_ext Reg (fpromote_reg flt_ty src_ty src)) 2036 (dst Reg (fcvt_to_uint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext))) 2037 ;; Clamp the output to the destination type bounds. 2038 (uint_sat_reg dst_ty int_ty dst))) 2039 2040;; Convert $F32X4 to $I32X4 (z15 instruction). 2041(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $I32X4) 2042 (fcvt_to_uint_sat _ x @ (value_type $F32X4)))) 2043 (fcvt_to_uint_reg $I32X4 $F32X4 (FpuRoundMode.ToZero) x)) 2044 2045;; Convert $F32X4 to $I32X4 (via two $F64X2 on z14). 2046(rule (lower (has_type (and (vxrs_ext2_disabled) $I32X4) 2047 (fcvt_to_uint_sat _ x @ (value_type $F32X4)))) 2048 (vec_pack_usat $I64X2 2049 (fcvt_to_uint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) 2050 (fpromote_reg $F64X2 $F32X4 (vec_merge_high $I32X4 x x))) 2051 (fcvt_to_uint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) 2052 (fpromote_reg $F64X2 $F32X4 (vec_merge_low $I32X4 x x))))) 2053 2054;; Convert $F64X2 to $I64X2. 2055(rule (lower (has_type $I64X2 (fcvt_to_uint_sat _ x @ (value_type $F64X2)))) 2056 (fcvt_to_uint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) x)) 2057 2058 2059;;;; Rules for `fcvt_to_sint_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2060 2061;; Convert a scalar floating-point value in a register to a signed integer. 2062(rule -1 (lower (has_type (fits_in_64 dst_ty) 2063 (fcvt_to_sint_sat _ x @ (value_type src_ty)))) 2064 (let ((src Reg (put_in_reg x)) 2065 ;; Perform the conversion using the larger type size. 2066 (flt_ty Type (fcvt_flt_ty dst_ty src_ty)) 2067 (int_ty Type (fcvt_int_ty dst_ty src_ty)) 2068 (src_ext Reg (fpromote_reg flt_ty src_ty src)) 2069 (dst Reg (fcvt_to_sint_reg int_ty flt_ty (FpuRoundMode.ToZero) src_ext)) 2070 ;; In most special cases, the Z instruction already yields the 2071 ;; result expected by Cranelift semantics. The only exception 2072 ;; it the case where the input was a NaN. We explicitly check 2073 ;; for that and force the output to 0 in that case. 2074 (sat Reg (with_flags_reg (fcmp_reg src_ty src src) 2075 (cmov_imm int_ty 2076 (floatcc_as_cond (FloatCC.Unordered)) 0 dst)))) 2077 ;; Clamp the output to the destination type bounds. 2078 (sint_sat_reg dst_ty int_ty sat))) 2079 2080;; Convert $F32X4 to $I32X4 (z15 instruction). 2081(rule 1 (lower (has_type (and (vxrs_ext2_enabled) $I32X4) 2082 (fcvt_to_sint_sat _ src @ (value_type $F32X4)))) 2083 ;; See above for why we need to handle NaNs specially. 2084 (vec_select $I32X4 2085 (fcvt_to_sint_reg $I32X4 $F32X4 (FpuRoundMode.ToZero) src) 2086 (vec_imm $I32X4 0) (vec_fcmpeq $F32X4 src src))) 2087 2088;; Convert $F32X4 to $I32X4 (via two $F64X2 on z14). 2089(rule (lower (has_type (and (vxrs_ext2_disabled) $I32X4) 2090 (fcvt_to_sint_sat _ src @ (value_type $F32X4)))) 2091 ;; See above for why we need to handle NaNs specially. 2092 (vec_select $I32X4 2093 (vec_pack_ssat $I64X2 2094 (fcvt_to_sint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) 2095 (fpromote_reg $F64X2 $F32X4 (vec_merge_high $I32X4 src src))) 2096 (fcvt_to_sint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) 2097 (fpromote_reg $F64X2 $F32X4 (vec_merge_low $I32X4 src src)))) 2098 (vec_imm $I32X4 0) (vec_fcmpeq $F32X4 src src))) 2099 2100;; Convert $F64X2 to $I64X2. 2101(rule (lower (has_type $I64X2 (fcvt_to_sint_sat _ src @ (value_type $F64X2)))) 2102 ;; See above for why we need to handle NaNs specially. 2103 (vec_select $I64X2 2104 (fcvt_to_sint_reg $I64X2 $F64X2 (FpuRoundMode.ToZero) src) 2105 (vec_imm $I64X2 0) (vec_fcmpeq $F64X2 src src))) 2106 2107 2108;;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2109 2110;; Reinterpret a 64-bit integer value as floating-point. 2111(rule (lower (has_type $F64 (bitcast _ _ x @ (value_type $I64)))) 2112 (vec_insert_lane_undef $F64X2 x 0 (zero_reg))) 2113 2114;; Reinterpret a 64-bit floating-point value as integer. 2115(rule (lower (has_type $I64 (bitcast _ _ x @ (value_type $F64)))) 2116 (vec_extract_lane $F64X2 x 0 (zero_reg))) 2117 2118;; Reinterpret a 32-bit integer value as floating-point. 2119(rule (lower (has_type $F32 (bitcast _ _ x @ (value_type $I32)))) 2120 (vec_insert_lane_undef $F32X4 x 0 (zero_reg))) 2121 2122;; Reinterpret a 32-bit floating-point value as integer. 2123(rule (lower (has_type $I32 (bitcast _ _ x @ (value_type $F32)))) 2124 (vec_extract_lane $F32X4 x 0 (zero_reg))) 2125 2126;; Reinterpret a 16-bit integer value as floating-point. 2127(rule (lower (has_type $F16 (bitcast _ _ x @ (value_type $I16)))) 2128 (vec_insert_lane_undef $F16X8 x 0 (zero_reg))) 2129 2130;; Reinterpret a 16-bit floating-point value as integer. 2131(rule (lower (has_type $I16 (bitcast _ _ x @ (value_type $F16)))) 2132 (vec_extract_lane $F16X8 x 0 (zero_reg))) 2133 2134;; Bitcast between types residing in GPRs is a no-op. 2135(rule 1 (lower (has_type (gpr32_ty _) 2136 (bitcast _ _ x @ (value_type (gpr32_ty _))))) 2137 x) 2138(rule 2 (lower (has_type (gpr64_ty _) 2139 (bitcast _ _ x @ (value_type (gpr64_ty _))))) 2140 x) 2141 2142;; Bitcast between types residing in FPRs is a no-op. 2143(rule 3 (lower (has_type (ty_scalar_float _) 2144 (bitcast _ _ x @ (value_type (ty_scalar_float _))))) 2145 x) 2146 2147;; Bitcast between types residing in VRs is a no-op if lane count is unchanged. 2148(rule 5 (lower (has_type (multi_lane bits count) 2149 (bitcast _ _ x @ (value_type (multi_lane bits count))))) 2150 x) 2151 2152;; Bitcast between types residing in VRs with different lane counts is a 2153;; no-op if the operation's MemFlags indicate a byte order compatible with 2154;; the current lane order. Otherwise, lane elements need to be swapped, 2155;; first in the input type, and then again in the output type. This could 2156;; be optimized further, but we don't bother at the moment since due to our 2157;; choice of lane order depending on the current function ABI, this case will 2158;; currently never arise in practice. 2159(rule 4 (lower (has_type (vr128_ty out_ty) 2160 (bitcast _ flags x @ (value_type (vr128_ty in_ty))))) 2161 (abi_vec_elt_rev (lane_order_from_memflags flags) out_ty 2162 (abi_vec_elt_rev (lane_order_from_memflags flags) in_ty x))) 2163 2164(decl abi_vec_elt_rev (LaneOrder Type Reg) Reg) 2165(rule 1 (abi_vec_elt_rev callee_lane_order (ty_vec128 ty) reg) 2166 (if-let false (lane_order_equal callee_lane_order (lane_order))) 2167 (vec_elt_rev ty reg)) 2168(rule 0 (abi_vec_elt_rev _ _ reg) reg) 2169 2170 2171;;;; Rules for `insertlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2172 2173;; Insert vector lane from general-purpose register. 2174(rule 1 (lower (insertlane _ x @ (value_type ty) 2175 y @ (value_type in_ty) 2176 (u8_from_uimm8 idx))) 2177 (if (ty_int_ref_scalar_64 in_ty)) 2178 (vec_insert_lane ty x y (be_lane_idx ty idx) (zero_reg))) 2179 2180;; Insert vector lane from floating-point register. 2181(rule 0 (lower (insertlane _ x @ (value_type ty) 2182 y @ (value_type (ty_scalar_float _)) 2183 (u8_from_uimm8 idx))) 2184 (vec_move_lane_and_insert ty x (be_lane_idx ty idx) y 0)) 2185 2186;; Insert vector lane from another vector lane. 2187(rule 2 (lower (insertlane _ x @ (value_type ty) 2188 (extractlane _ y (u8_from_uimm8 src_idx)) 2189 (u8_from_uimm8 dst_idx))) 2190 (vec_move_lane_and_insert ty x (be_lane_idx ty dst_idx) 2191 y (be_lane_idx ty src_idx))) 2192 2193;; Insert vector lane from signed 16-bit immediate. 2194(rule 3 (lower (insertlane _ x @ (value_type ty) (i16_from_value y) 2195 (u8_from_uimm8 idx))) 2196 (vec_insert_lane_imm ty x y (be_lane_idx ty idx))) 2197 2198;; Insert vector lane from big-endian memory. 2199(rule 4 (lower (insertlane _ x @ (value_type ty) (sinkable_load y) 2200 (u8_from_uimm8 idx))) 2201 (vec_load_lane ty x (sink_load y) (be_lane_idx ty idx))) 2202 2203;; Insert vector lane from little-endian memory. 2204(rule 5 (lower (insertlane _ x @ (value_type ty) (sinkable_load_little y) 2205 (u8_from_uimm8 idx))) 2206 (vec_load_lane_little ty x (sink_load y) (be_lane_idx ty idx))) 2207 2208 2209;; Helper to extract one lane from a vector and insert it into another. 2210(decl vec_move_lane_and_insert (Type Reg u8 Reg u8) Reg) 2211 2212;; For 64-bit elements we always use VPDI. 2213(rule (vec_move_lane_and_insert ty @ (multi_lane 64 _) dst 0 src src_idx) 2214 (vec_permute_dw_imm ty src src_idx dst 1)) 2215(rule (vec_move_lane_and_insert ty @ (multi_lane 64 _) dst 1 src src_idx) 2216 (vec_permute_dw_imm ty dst 0 src src_idx)) 2217 2218;; If source and destination index are the same, use vec_select. 2219(rule -1 (vec_move_lane_and_insert ty dst idx src idx) 2220 (vec_select ty src 2221 dst (vec_imm_byte_mask ty (lane_byte_mask ty idx)))) 2222 2223;; Otherwise replicate source first and then use vec_select. 2224(rule -2 (vec_move_lane_and_insert ty dst dst_idx src src_idx) 2225 (vec_select ty (vec_replicate_lane ty src src_idx) 2226 dst (vec_imm_byte_mask ty (lane_byte_mask ty dst_idx)))) 2227 2228 2229;; Helper to implement a generic little-endian variant of vec_load_lane. 2230(decl vec_load_lane_little (Type Reg MemArg u8) Reg) 2231 2232;; 8-byte little-endian loads can be performed via a normal load. 2233(rule (vec_load_lane_little ty @ (multi_lane 8 _) dst addr lane_imm) 2234 (vec_load_lane ty dst addr lane_imm)) 2235 2236;; On z15, we have instructions to perform little-endian loads. 2237(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled) 2238 ty @ (multi_lane 16 _)) dst addr lane_imm) 2239 (vec_load_lane_rev ty dst addr lane_imm)) 2240(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled) 2241 ty @ (multi_lane 32 _)) dst addr lane_imm) 2242 (vec_load_lane_rev ty dst addr lane_imm)) 2243(rule 1 (vec_load_lane_little (and (vxrs_ext2_enabled) 2244 ty @ (multi_lane 64 _)) dst addr lane_imm) 2245 (vec_load_lane_rev ty dst addr lane_imm)) 2246 2247;; On z14, use a little-endian load to GPR followed by vec_insert_lane. 2248(rule (vec_load_lane_little (and (vxrs_ext2_disabled) 2249 ty @ (multi_lane 16 _)) dst addr lane_imm) 2250 (vec_insert_lane ty dst (loadrev16 addr) lane_imm (zero_reg))) 2251(rule (vec_load_lane_little (and (vxrs_ext2_disabled) 2252 ty @ (multi_lane 32 _)) dst addr lane_imm) 2253 (vec_insert_lane ty dst (loadrev32 addr) lane_imm (zero_reg))) 2254(rule (vec_load_lane_little (and (vxrs_ext2_disabled) 2255 ty @ (multi_lane 64 _)) dst addr lane_imm) 2256 (vec_insert_lane ty dst (loadrev64 addr) lane_imm (zero_reg))) 2257 2258;; Helper to implement a generic little-endian variant of vec_load_lane_undef. 2259(decl vec_load_lane_little_undef (Type MemArg u8) Reg) 2260 2261;; 8-byte little-endian loads can be performed via a normal load. 2262(rule (vec_load_lane_little_undef ty @ (multi_lane 8 _) addr lane_imm) 2263 (vec_load_lane_undef ty addr lane_imm)) 2264 2265;; On z15, we have instructions to perform little-endian loads. 2266(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled) 2267 ty @ (multi_lane 16 _)) addr lane_imm) 2268 (vec_load_lane_rev_undef ty addr lane_imm)) 2269(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled) 2270 ty @ (multi_lane 32 _)) addr lane_imm) 2271 (vec_load_lane_rev_undef ty addr lane_imm)) 2272(rule 1 (vec_load_lane_little_undef (and (vxrs_ext2_enabled) 2273 ty @ (multi_lane 64 _)) addr lane_imm) 2274 (vec_load_lane_rev_undef ty addr lane_imm)) 2275 2276;; On z14, use a little-endian load to GPR followed by vec_insert_lane_undef. 2277(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled) 2278 ty @ (multi_lane 16 _)) addr lane_imm) 2279 (vec_insert_lane_undef ty (loadrev16 addr) lane_imm (zero_reg))) 2280(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled) 2281 ty @ (multi_lane 32 _)) addr lane_imm) 2282 (vec_insert_lane_undef ty (loadrev32 addr) lane_imm (zero_reg))) 2283(rule (vec_load_lane_little_undef (and (vxrs_ext2_disabled) 2284 ty @ (multi_lane 64 _)) addr lane_imm) 2285 (vec_insert_lane_undef ty (loadrev64 addr) lane_imm (zero_reg))) 2286 2287 2288;;;; Rules for `extractlane` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2289 2290;; Extract vector lane to general-purpose register. 2291(rule 1 (lower (has_type out_ty 2292 (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx)))) 2293 (if (ty_int_ref_scalar_64 out_ty)) 2294 (vec_extract_lane ty x (be_lane_idx ty idx) (zero_reg))) 2295 2296;; Extract vector lane to floating-point register. 2297(rule 0 (lower (has_type (ty_scalar_float _) 2298 (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx)))) 2299 (vec_replicate_lane ty x (be_lane_idx ty idx))) 2300 2301;; Extract vector lane and store to big-endian memory. 2302(rule 6 (lower (store flags @ (bigendian) 2303 (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx)) 2304 addr offset)) 2305 (side_effect (vec_store_lane ty x 2306 (lower_address flags addr offset) (be_lane_idx ty idx)))) 2307 2308;; Extract vector lane and store to little-endian memory. 2309(rule 5 (lower (store flags @ (littleendian) 2310 (extractlane _ x @ (value_type ty) (u8_from_uimm8 idx)) 2311 addr offset)) 2312 (side_effect (vec_store_lane_little ty x 2313 (lower_address flags addr offset) (be_lane_idx ty idx)))) 2314 2315 2316;; Helper to implement a generic little-endian variant of vec_store_lane. 2317(decl vec_store_lane_little (Type Reg MemArg u8) SideEffectNoResult) 2318 2319;; 8-byte little-endian stores can be performed via a normal store. 2320(rule (vec_store_lane_little ty @ (multi_lane 8 _) src addr lane_imm) 2321 (vec_store_lane ty src addr lane_imm)) 2322 2323;; On z15, we have instructions to perform little-endian stores. 2324(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled) 2325 ty @ (multi_lane 16 _)) src addr lane_imm) 2326 (vec_store_lane_rev ty src addr lane_imm)) 2327(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled) 2328 ty @ (multi_lane 32 _)) src addr lane_imm) 2329 (vec_store_lane_rev ty src addr lane_imm)) 2330(rule 1 (vec_store_lane_little (and (vxrs_ext2_enabled) 2331 ty @ (multi_lane 64 _)) src addr lane_imm) 2332 (vec_store_lane_rev ty src addr lane_imm)) 2333 2334;; On z14, use vec_extract_lane followed by a little-endian store from GPR. 2335(rule (vec_store_lane_little (and (vxrs_ext2_disabled) 2336 ty @ (multi_lane 16 _)) src addr lane_imm) 2337 (storerev16 (vec_extract_lane ty src lane_imm (zero_reg)) addr)) 2338(rule (vec_store_lane_little (and (vxrs_ext2_disabled) 2339 ty @ (multi_lane 32 _)) src addr lane_imm) 2340 (storerev32 (vec_extract_lane ty src lane_imm (zero_reg)) addr)) 2341(rule (vec_store_lane_little (and (vxrs_ext2_disabled) 2342 ty @ (multi_lane 64 _)) src addr lane_imm) 2343 (storerev64 (vec_extract_lane ty src lane_imm (zero_reg)) addr)) 2344 2345 2346;;;; Rules for `splat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2347 2348;; Load replicated value from general-purpose register. 2349(rule 1 (lower (has_type ty (splat _ x @ (value_type in_ty)))) 2350 (if (ty_int_ref_scalar_64 in_ty)) 2351 (vec_replicate_lane ty (vec_insert_lane_undef ty x 0 (zero_reg)) 0)) 2352 2353;; Load replicated value from floating-point register. 2354(rule 0 (lower (has_type ty (splat _ 2355 x @ (value_type (ty_scalar_float _))))) 2356 (vec_replicate_lane ty x 0)) 2357 2358;; Load replicated value from vector lane. 2359(rule 2 (lower (has_type ty (splat _ (extractlane _ x (u8_from_uimm8 idx))))) 2360 (vec_replicate_lane ty x (be_lane_idx ty idx))) 2361 2362;; Load replicated 16-bit immediate value. 2363(rule 3 (lower (has_type ty (splat _ (i16_from_value x)))) 2364 (vec_imm_replicate ty x)) 2365 2366;; Load replicated value from big-endian memory. 2367(rule 4 (lower (has_type ty (splat _ (sinkable_load x)))) 2368 (vec_load_replicate ty (sink_load x))) 2369 2370;; Load replicated value from little-endian memory. 2371(rule 5 (lower (has_type ty (splat _ (sinkable_load_little x)))) 2372 (vec_load_replicate_little ty (sink_load x))) 2373 2374 2375;; Helper to implement a generic little-endian variant of vec_load_replicate 2376(decl vec_load_replicate_little (Type MemArg) Reg) 2377 2378;; 8-byte little-endian loads can be performed via a normal load. 2379(rule (vec_load_replicate_little ty @ (multi_lane 8 _) addr) 2380 (vec_load_replicate ty addr)) 2381 2382;; On z15, we have instructions to perform little-endian loads. 2383(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled) 2384 ty @ (multi_lane 16 _)) addr) 2385 (vec_load_replicate_rev ty addr)) 2386(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled) 2387 ty @ (multi_lane 32 _)) addr) 2388 (vec_load_replicate_rev ty addr)) 2389(rule 1 (vec_load_replicate_little (and (vxrs_ext2_enabled) 2390 ty @ (multi_lane 64 _)) addr) 2391 (vec_load_replicate_rev ty addr)) 2392 2393;; On z14, use a little-endian load (via GPR) and replicate. 2394(rule (vec_load_replicate_little (and (vxrs_ext2_disabled) 2395 ty @ (multi_lane 16 _)) addr) 2396 (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0)) 2397(rule (vec_load_replicate_little (and (vxrs_ext2_disabled) 2398 ty @ (multi_lane 32 _)) addr) 2399 (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0)) 2400(rule (vec_load_replicate_little (and (vxrs_ext2_disabled) 2401 ty @ (multi_lane 64 _)) addr) 2402 (vec_replicate_lane ty (vec_load_lane_little_undef ty addr 0) 0)) 2403 2404 2405;;;; Rules for `scalar_to_vector` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2406 2407;; Load scalar value from general-purpose register. 2408(rule 1 (lower (has_type ty (scalar_to_vector _ 2409 x @ (value_type in_ty)))) 2410 (if (ty_int_ref_scalar_64 in_ty)) 2411 (vec_insert_lane ty (vec_imm ty 0) x (be_lane_idx ty 0) (zero_reg))) 2412 2413;; Load scalar value from floating-point register. 2414(rule 0 (lower (has_type ty (scalar_to_vector _ 2415 x @ (value_type (ty_scalar_float _))))) 2416 (vec_move_lane_and_zero ty (be_lane_idx ty 0) x 0)) 2417 2418;; Load scalar value from vector lane. 2419(rule 2 (lower (has_type ty (scalar_to_vector _ 2420 (extractlane _ x (u8_from_uimm8 idx))))) 2421 (vec_move_lane_and_zero ty (be_lane_idx ty 0) x (be_lane_idx ty idx))) 2422 2423;; Load scalar 16-bit immediate value. 2424(rule 3 (lower (has_type ty (scalar_to_vector _ (i16_from_value x)))) 2425 (vec_insert_lane_imm ty (vec_imm ty 0) x (be_lane_idx ty 0))) 2426 2427;; Load scalar value from big-endian memory. 2428(rule 4 (lower (has_type ty (scalar_to_vector _ (sinkable_load x)))) 2429 (vec_load_lane ty (vec_imm ty 0) (sink_load x) (be_lane_idx ty 0))) 2430 2431;; Load scalar value lane from little-endian memory. 2432(rule 5 (lower (has_type ty (scalar_to_vector _ (sinkable_load_little x)))) 2433 (vec_load_lane_little ty (vec_imm ty 0) (sink_load x) (be_lane_idx ty 0))) 2434 2435 2436;; Helper to extract one lane from a vector and insert it into a zero vector. 2437(decl vec_move_lane_and_zero (Type u8 Reg u8) Reg) 2438 2439;; For 64-bit elements we always use VPDI. 2440(rule (vec_move_lane_and_zero ty @ (multi_lane 64 _) 0 src src_idx) 2441 (vec_permute_dw_imm ty src src_idx (vec_imm ty 0) 0)) 2442(rule (vec_move_lane_and_zero ty @ (multi_lane 64 _) 1 src src_idx) 2443 (vec_permute_dw_imm ty (vec_imm ty 0) 0 src src_idx)) 2444 2445;; If source and destination index are the same, simply mask to this lane. 2446(rule -1 (vec_move_lane_and_zero ty idx src idx) 2447 (vec_and ty src 2448 (vec_imm_byte_mask ty (lane_byte_mask ty idx)))) 2449 2450;; Otherwise replicate source first and then mask to the lane. 2451(rule -2 (vec_move_lane_and_zero ty dst_idx src src_idx) 2452 (vec_and ty (vec_replicate_lane ty src src_idx) 2453 (vec_imm_byte_mask ty (lane_byte_mask ty dst_idx)))) 2454 2455 2456;;;; Rules for `shuffle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2457 2458;; General case: use vec_permute and then mask off zero lanes. 2459(rule -2 (lower (shuffle _ x y (shuffle_mask permute_mask and_mask))) 2460 (vec_and $I8X16 (vec_imm_byte_mask $I8X16 and_mask) 2461 (vec_permute $I8X16 x y (vec_imm $I8X16 permute_mask)))) 2462 2463;; If the pattern has no zero lanes, just a vec_permute suffices. 2464(rule -1 (lower (shuffle _ x y (shuffle_mask permute_mask 65535))) 2465 (vec_permute $I8X16 x y (vec_imm $I8X16 permute_mask))) 2466 2467;; Special patterns that can be implemented via MERGE HIGH. 2468(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23) 65535))) 2469 (vec_merge_high $I64X2 x y)) 2470(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 16 17 18 19 4 5 6 7 20 21 22 23) 65535))) 2471 (vec_merge_high $I32X4 x y)) 2472(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 16 17 2 3 18 19 4 5 20 21 6 7 22 23) 65535))) 2473 (vec_merge_high $I16X8 x y)) 2474(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 16 1 17 2 18 3 19 4 20 5 21 6 22 7 23) 65535))) 2475 (vec_merge_high $I8X16 x y)) 2476(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 0 1 2 3 4 5 6 7) 65535))) 2477 (vec_merge_high $I64X2 y x)) 2478(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 0 1 2 3 20 21 22 23 4 5 6 7) 65535))) 2479 (vec_merge_high $I32X4 y x)) 2480(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 0 1 18 19 2 3 20 21 4 5 22 23 6 7) 65535))) 2481 (vec_merge_high $I16X8 y x)) 2482(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 0 17 1 18 2 19 3 20 4 21 5 22 6 23 7) 65535))) 2483 (vec_merge_high $I8X16 y x)) 2484(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7) 65535))) 2485 (vec_merge_high $I64X2 x x)) 2486(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 0 1 2 3 4 5 6 7 4 5 6 7) 65535))) 2487 (vec_merge_high $I32X4 x x)) 2488(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 0 1 2 3 2 3 4 5 4 5 6 7 6 7) 65535))) 2489 (vec_merge_high $I16X8 x x)) 2490(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7) 65535))) 2491 (vec_merge_high $I8X16 x x)) 2492(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23) 65535))) 2493 (vec_merge_high $I64X2 y y)) 2494(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 16 17 18 19 20 21 22 23 20 21 22 23) 65535))) 2495 (vec_merge_high $I32X4 y y)) 2496(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 16 17 18 19 18 19 20 21 20 21 22 23 22 23) 65535))) 2497 (vec_merge_high $I16X8 y y)) 2498(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23) 65535))) 2499 (vec_merge_high $I8X16 y y)) 2500 2501;; Special patterns that can be implemented via MERGE LOW. 2502(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31) 65535))) 2503 (vec_merge_low $I64X2 x y)) 2504(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 24 25 26 27 12 13 14 15 28 29 30 31) 65535))) 2505 (vec_merge_low $I32X4 x y)) 2506(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 24 25 10 11 26 27 12 13 28 29 14 15 30 31) 65535))) 2507 (vec_merge_low $I16X8 x y)) 2508(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 24 9 25 10 26 11 27 12 28 13 29 14 30 15 31) 65535))) 2509 (vec_merge_low $I8X16 x y)) 2510(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 8 9 10 11 12 13 14 15) 65535))) 2511 (vec_merge_low $I64X2 y x)) 2512(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 8 9 10 11 28 29 30 31 12 13 14 15) 65535))) 2513 (vec_merge_low $I32X4 y x)) 2514(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 8 9 26 27 10 11 28 29 12 13 30 31 14 15) 65535))) 2515 (vec_merge_low $I16X8 y x)) 2516(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 8 25 9 26 10 27 11 28 12 29 13 30 14 31 15) 65535))) 2517 (vec_merge_low $I8X16 y x)) 2518(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15) 65535))) 2519 (vec_merge_low $I64X2 x x)) 2520(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 8 9 10 11 12 13 14 15 12 13 14 15) 65535))) 2521 (vec_merge_low $I32X4 x x)) 2522(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 8 9 10 11 10 11 12 13 12 13 14 15 14 15) 65535))) 2523 (vec_merge_low $I16X8 x x)) 2524(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15) 65535))) 2525 (vec_merge_low $I8X16 x x)) 2526(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31) 65535))) 2527 (vec_merge_low $I64X2 y y)) 2528(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 24 25 26 27 28 29 30 31 28 29 30 31) 65535))) 2529 (vec_merge_low $I32X4 y y)) 2530(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 24 25 26 27 26 27 28 29 28 29 30 31 30 31) 65535))) 2531 (vec_merge_low $I16X8 y y)) 2532(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 31) 65535))) 2533 (vec_merge_low $I8X16 y y)) 2534 2535;; Special patterns that can be implemented via PACK. 2536(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 4 5 6 7 12 13 14 15 20 21 22 23 28 29 30 31) 65535))) 2537 (vec_pack $I64X2 x y)) 2538(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 2 3 6 7 10 11 14 15 18 19 22 23 26 27 30 31) 65535))) 2539 (vec_pack $I32X4 x y)) 2540(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31) 65535))) 2541 (vec_pack $I16X8 x y)) 2542(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 20 21 22 23 28 29 30 31 4 5 6 7 12 13 14 15) 65535))) 2543 (vec_pack $I64X2 y x)) 2544(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 18 19 22 23 26 27 30 31 2 3 6 7 10 11 14 15) 65535))) 2545 (vec_pack $I32X4 y x)) 2546(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 17 19 21 23 25 27 29 31 1 3 5 7 9 11 13 15) 65535))) 2547 (vec_pack $I16X8 y x)) 2548(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 4 5 6 7 12 13 14 15 4 5 6 7 12 13 14 15) 65535))) 2549 (vec_pack $I64X2 x x)) 2550(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 2 3 6 7 10 11 14 15 2 3 6 7 10 11 14 15) 65535))) 2551 (vec_pack $I32X4 x x)) 2552(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 1 3 5 7 9 11 13 15 1 3 5 7 9 11 13 15) 65535))) 2553 (vec_pack $I16X8 x x)) 2554(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 20 21 22 23 28 29 30 31 20 21 22 23 28 29 30 31) 65535))) 2555 (vec_pack $I64X2 y y)) 2556(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 18 19 22 23 26 27 30 31 18 19 22 23 26 27 30 31) 65535))) 2557 (vec_pack $I32X4 y y)) 2558(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 17 19 21 23 25 27 29 31 17 19 21 23 25 27 29 31) 65535))) 2559 (vec_pack $I16X8 y y)) 2560 2561;; Special patterns that can be implemented via UNPACK HIGH. 2562(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 0 1 2 3 _ _ _ _ 4 5 6 7) 3855))) 2563 (vec_unpacku_high $I32X4 x)) 2564(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 0 1 _ _ 2 3 _ _ 4 5 _ _ 6 7) 13107))) 2565 (vec_unpacku_high $I16X8 x)) 2566(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 0 _ 1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7) 21845))) 2567 (vec_unpacku_high $I8X16 x)) 2568(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 16 17 18 19 _ _ _ _ 20 21 22 23) 3855))) 2569 (vec_unpacku_high $I32X4 y)) 2570(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 16 17 _ _ 18 19 _ _ 20 21 _ _ 22 23) 13107))) 2571 (vec_unpacku_high $I16X8 y)) 2572(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 16 _ 17 _ 18 _ 19 _ 20 _ 21 _ 22 _ 23) 21845))) 2573 (vec_unpacku_high $I8X16 y)) 2574 2575;; Special patterns that can be implemented via UNPACK LOW. 2576(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 8 9 10 11 _ _ _ _ 12 13 14 15) 3855))) 2577 (vec_unpacku_low $I32X4 x)) 2578(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 8 9 _ _ 10 11 _ _ 12 13 _ _ 14 15) 13107))) 2579 (vec_unpacku_low $I16X8 x)) 2580(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 8 _ 9 _ 10 _ 11 _ 12 _ 13 _ 14 _ 15) 21845))) 2581 (vec_unpacku_low $I8X16 x)) 2582(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ _ _ 24 25 26 27 _ _ _ _ 28 29 30 31) 3855))) 2583 (vec_unpacku_low $I32X4 y)) 2584(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ _ 24 25 _ _ 26 27 _ _ 28 29 _ _ 30 31) 13107))) 2585 (vec_unpacku_low $I16X8 y)) 2586(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 _ 24 _ 25 _ 26 _ 27 _ 28 _ 29 _ 30 _ 31) 21845))) 2587 (vec_unpacku_low $I8X16 y)) 2588 2589;; Special patterns that can be implemented via PERMUTE DOUBLEWORD IMMEDIATE. 2590(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 24 25 26 27 28 29 30 31) 65535))) 2591 (vec_permute_dw_imm $I8X16 x 0 y 1)) 2592(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23) 65535))) 2593 (vec_permute_dw_imm $I8X16 x 1 y 0)) 2594(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15) 65535))) 2595 (vec_permute_dw_imm $I8X16 y 0 x 1)) 2596(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7) 65535))) 2597 (vec_permute_dw_imm $I8X16 y 1 x 0)) 2598(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) 65535))) 2599 (vec_permute_dw_imm $I8X16 x 0 x 1)) 2600(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7) 65535))) 2601 (vec_permute_dw_imm $I8X16 x 1 x 0)) 2602(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) 65535))) 2603 (vec_permute_dw_imm $I8X16 y 0 y 1)) 2604(rule (lower (shuffle _ x y (shuffle_mask (imm8x16 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23) 65535))) 2605 (vec_permute_dw_imm $I8X16 y 1 y 0)) 2606 2607;;;; Rules for `blendv` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2608 2609(rule 1 (lower (has_type (and (ty_vec128 ty) (vxrs_ext3_enabled)) (blendv _ p x y))) 2610 (vec_blend ty p x y)) 2611 2612 2613;;;; Rules for `swizzle` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2614 2615;; When using big-endian lane order, the lane mask is mostly correct, but we 2616;; need to handle mask elements outside the range 0..15 by zeroing the lane. 2617;; 2618;; To do so efficiently, we compute: 2619;; permute-lane-element := umin (16, swizzle-lane-element) 2620;; and pass a zero vector as second operand to the permute instruction. 2621 2622(rule 1 (lower (has_type (ty_vec128 ty) (swizzle _ x y))) 2623 (if-let (LaneOrder.BigEndian) (lane_order)) 2624 (vec_permute ty x (vec_imm ty 0) 2625 (vec_umin $I8X16 (vec_imm_splat $I8X16 16) y))) 2626 2627;; When using little-endian lane order, in addition to zeroing (as above), 2628;; we need to convert from little-endian to big-endian lane numbering. 2629;; 2630;; To do so efficiently, we compute: 2631;; permute-lane-element := umax (239, ~ swizzle-lane-element) 2632;; which has the following effect: 2633;; elements 0 .. 15 --> 255 .. 240 (i.e. 31 .. 16 mod 32) 2634;; everything else --> 239 (i.e. 15 mod 32) 2635;; 2636;; Then, we can use a single permute instruction with 2637;; a zero vector as first operand (covering lane 15) 2638;; the input vector as second operand (covering lanes 16 .. 31) 2639;; to implement the required swizzle semantics. 2640 2641(rule (lower (has_type (ty_vec128 ty) (swizzle _ x y))) 2642 (if-let (LaneOrder.LittleEndian) (lane_order)) 2643 (vec_permute ty (vec_imm ty 0) x 2644 (vec_umax $I8X16 (vec_imm_splat $I8X16 239) 2645 (vec_not $I8X16 y)))) 2646 2647 2648;;;; Rules for `stack_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2649 2650;; Load the address of a stack slot. 2651(rule (lower (has_type ty (stack_addr _ stack_slot offset))) 2652 (stack_addr_impl ty stack_slot offset)) 2653 2654 2655;;;; Rules for `func_addr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2656 2657;; Load the address of a function, target reachable via PC-relative instruction. 2658(rule 1 (lower (func_addr _ (func_ref_data _ name (RelocDistance.Near) _))) 2659 (load_addr (memarg_symbol name 0 (memflags_trusted)))) 2660 2661;; Load the address of a function, general case. 2662(rule (lower (func_addr _ (func_ref_data _ name _ _))) 2663 (load_symbol_reloc (SymbolReloc.Absolute name 0))) 2664 2665 2666;;;; Rules for `symbol_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2667 2668;; Load the address of a symbol, target reachable via PC-relative instruction. 2669(rule 1 (lower (symbol_value _ (symbol_value_data name (RelocDistance.Near) 2670 off))) 2671 (if-let offset (memarg_symbol_offset off)) 2672 (load_addr (memarg_symbol name offset (memflags_trusted)))) 2673 2674;; Load the address of a symbol, general case. 2675(rule (lower (symbol_value _ (symbol_value_data name _ offset))) 2676 (load_symbol_reloc (SymbolReloc.Absolute name offset))) 2677 2678 2679;;;; Rules for `tls_value` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2680 2681;; Load the address of a TLS symbol (ELF general-dynamic model). 2682(rule (lower (tls_value _ (symbol_value_data name _ 0))) 2683 (if (tls_model_is_elf_gd)) 2684 (let ((symbol SymbolReloc (SymbolReloc.TlsGd name)) 2685 (got Reg (load_addr (memarg_got))) 2686 (got_offset Reg (load_symbol_reloc symbol)) 2687 (tls_offset Reg (lib_call_tls_get_offset got got_offset symbol))) 2688 (add_reg $I64 tls_offset (thread_pointer)))) 2689 2690;; Helper to perform a call to the __tls_get_offset library routine. 2691(decl lib_call_tls_get_offset (Reg Reg SymbolReloc) Reg) 2692(rule (lib_call_tls_get_offset got got_offset symbol) 2693 (let ((tls_offset WritableReg (temp_writable_reg $I64)) 2694 (_ Unit (abi_for_elf_tls_get_offset)) 2695 (_ Unit (emit (MInst.ElfTlsGetOffset tls_offset got got_offset symbol)))) 2696 tls_offset)) 2697 2698(decl abi_for_elf_tls_get_offset () Unit) 2699(extern constructor abi_for_elf_tls_get_offset abi_for_elf_tls_get_offset) 2700 2701;; Helper to extract the current thread pointer from %a0/%a1. 2702(decl thread_pointer () Reg) 2703(rule (thread_pointer) 2704 (insert_ar (lshl_imm $I64 (load_ar 0) 32) 1)) 2705 2706 2707;;;; Rules for `load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2708 2709;; Load 8-bit integers. 2710(rule (lower (has_type $I8 (load _ flags addr offset))) 2711 (zext32_mem $I8 (lower_address flags addr offset))) 2712 2713;; Load 16-bit big-endian integers. 2714(rule (lower (has_type $I16 (load _ flags @ (bigendian) addr offset))) 2715 (zext32_mem $I16 (lower_address flags addr offset))) 2716 2717;; Load 16-bit little-endian integers. 2718(rule -1 (lower (has_type $I16 (load _ flags @ (littleendian) addr offset))) 2719 (loadrev16 (lower_address flags addr offset))) 2720 2721;; Load 32-bit big-endian integers. 2722(rule (lower (has_type $I32 (load _ flags @ (bigendian) addr offset))) 2723 (load32 (lower_address flags addr offset))) 2724 2725;; Load 32-bit little-endian integers. 2726(rule -1 (lower (has_type $I32 (load _ flags @ (littleendian) addr offset))) 2727 (loadrev32 (lower_address flags addr offset))) 2728 2729;; Load 64-bit big-endian integers. 2730(rule (lower (has_type $I64 (load _ flags @ (bigendian) addr offset))) 2731 (load64 (lower_address flags addr offset))) 2732 2733;; Load 64-bit little-endian integers. 2734(rule -1 (lower (has_type $I64 (load _ flags @ (littleendian) addr offset))) 2735 (loadrev64 (lower_address flags addr offset))) 2736 2737;; Load 16-bit big-endian floating-point values (as vector lane). 2738(rule (lower (has_type $F16 (load _ flags @ (bigendian) addr offset))) 2739 (vec_load_lane_undef $F16X8 (lower_address flags addr offset) 0)) 2740 2741;; Load 16-bit little-endian floating-point values (as vector lane). 2742(rule -1 (lower (has_type $F16 (load _ flags @ (littleendian) addr offset))) 2743 (vec_load_lane_little_undef $F16X8 (lower_address flags addr offset) 0)) 2744 2745;; Load 32-bit big-endian floating-point values (as vector lane). 2746(rule (lower (has_type $F32 (load _ flags @ (bigendian) addr offset))) 2747 (vec_load_lane_undef $F32X4 (lower_address flags addr offset) 0)) 2748 2749;; Load 32-bit little-endian floating-point values (as vector lane). 2750(rule -1 (lower (has_type $F32 (load _ flags @ (littleendian) addr offset))) 2751 (vec_load_lane_little_undef $F32X4 (lower_address flags addr offset) 0)) 2752 2753;; Load 64-bit big-endian floating-point values (as vector lane). 2754(rule (lower (has_type $F64 (load _ flags @ (bigendian) addr offset))) 2755 (vec_load_lane_undef $F64X2 (lower_address flags addr offset) 0)) 2756 2757;; Load 64-bit little-endian floating-point values (as vector lane). 2758(rule -1 (lower (has_type $F64 (load _ flags @ (littleendian) addr offset))) 2759 (vec_load_lane_little_undef $F64X2 (lower_address flags addr offset) 0)) 2760 2761;; Load 128-bit big-endian vector values, BE lane order - direct load. 2762(rule 4 (lower (has_type (vr128_ty ty) (load _ flags @ (bigendian) addr offset))) 2763 (if-let (LaneOrder.BigEndian) (lane_order)) 2764 (vec_load ty (lower_address flags addr offset))) 2765 2766;; Load 128-bit little-endian vector values, BE lane order - byte-reversed load. 2767(rule 3 (lower (has_type (vr128_ty ty) (load _ flags @ (littleendian) addr offset))) 2768 (if-let (LaneOrder.BigEndian) (lane_order)) 2769 (vec_load_byte_rev ty flags addr offset)) 2770 2771;; Load 128-bit big-endian vector values, LE lane order - element-reversed load. 2772(rule 2 (lower (has_type (vr128_ty ty) (load _ flags @ (bigendian) addr offset))) 2773 (if-let (LaneOrder.LittleEndian) (lane_order)) 2774 (vec_load_elt_rev ty flags addr offset)) 2775 2776;; Load 128-bit little-endian vector values, LE lane order - fully-reversed load. 2777(rule 1 (lower (has_type (vr128_ty ty) (load _ flags @ (littleendian) addr offset))) 2778 (if-let (LaneOrder.LittleEndian) (lane_order)) 2779 (vec_load_full_rev ty flags addr offset)) 2780 2781 2782;; Helper to perform a 128-bit full-vector byte-reversed load. 2783(decl vec_load_full_rev (Type MemFlags Value Offset32) Reg) 2784 2785;; Full-vector byte-reversed load via single instruction on z15. 2786(rule 1 (vec_load_full_rev (and (vxrs_ext2_enabled) (vr128_ty ty)) flags addr offset) 2787 (vec_loadrev ty (lower_address flags addr offset))) 2788 2789;; Full-vector byte-reversed load via GPRs on z14. 2790(rule (vec_load_full_rev (and (vxrs_ext2_disabled) (vr128_ty ty)) flags addr offset) 2791 (let ((lo_addr MemArg (lower_address_bias flags addr offset 0)) 2792 (hi_addr MemArg (lower_address_bias flags addr offset 8)) 2793 (lo_val Reg (loadrev64 lo_addr)) 2794 (hi_val Reg (loadrev64 hi_addr))) 2795 (mov_to_vec128 ty hi_val lo_val))) 2796 2797 2798;; Helper to perform an element-wise byte-reversed load. 2799(decl vec_load_byte_rev (Type MemFlags Value Offset32) Reg) 2800 2801;; Element-wise byte-reversed 1x128-bit load is a full byte-reversed load. 2802(rule -1 (vec_load_byte_rev $I128 flags addr offset) 2803 (vec_load_full_rev $I128 flags addr offset)) 2804 2805;; Same for `f128`. 2806(rule -1 (vec_load_byte_rev $F128 flags addr offset) 2807 (vec_load_full_rev $F128 flags addr offset)) 2808 2809;; Element-wise byte-reversed 16x8-bit load is a direct load. 2810(rule (vec_load_byte_rev ty @ (multi_lane 8 16) flags addr offset) 2811 (vec_load ty (lower_address flags addr offset))) 2812 2813;; Element-wise byte-reversed load via single instruction on z15. 2814(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) 2815 flags addr offset) 2816 (vec_load_byte64rev ty (lower_address flags addr offset))) 2817(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) 2818 flags addr offset) 2819 (vec_load_byte32rev ty (lower_address flags addr offset))) 2820(rule 1 (vec_load_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) 2821 flags addr offset) 2822 (vec_load_byte16rev ty (lower_address flags addr offset))) 2823 2824;; Element-wise byte-reversed load as element-swapped byte-reversed load on z14. 2825(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) 2826 flags addr offset) 2827 (vec_elt_rev ty (vec_load_full_rev ty flags addr offset))) 2828(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) 2829 flags addr offset) 2830 (vec_elt_rev ty (vec_load_full_rev ty flags addr offset))) 2831(rule (vec_load_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) 2832 flags addr offset) 2833 (vec_elt_rev ty (vec_load_full_rev ty flags addr offset))) 2834 2835 2836;; Helper to perform an element-reversed load. 2837(decl vec_load_elt_rev (Type MemFlags Value Offset32) Reg) 2838 2839;; Element-reversed 1x128-bit load is a direct load. 2840;; For 1x128-bit types, this is a direct load. 2841(rule -1 (vec_load_elt_rev $I128 flags addr offset) 2842 (vec_load $I128 (lower_address flags addr offset))) 2843 2844;; Same for `f128`. 2845(rule -1 (vec_load_elt_rev $F128 flags addr offset) 2846 (vec_load $F128 (lower_address flags addr offset))) 2847 2848;; Element-reversed 16x8-bit load is a full byte-reversed load. 2849(rule (vec_load_elt_rev ty @ (multi_lane 8 16) flags addr offset) 2850 (vec_load_full_rev ty flags addr offset)) 2851 2852;; Element-reversed load via single instruction on z15. 2853(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) 2854 flags addr offset) 2855 (vec_load_elt64rev ty (lower_address flags addr offset))) 2856(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) 2857 flags addr offset) 2858 (vec_load_elt32rev ty (lower_address flags addr offset))) 2859(rule 1 (vec_load_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) 2860 flags addr offset) 2861 (vec_load_elt16rev ty (lower_address flags addr offset))) 2862 2863;; Element-reversed load as element-swapped direct load on z14. 2864(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) 2865 flags addr offset) 2866 (vec_elt_rev ty (vec_load ty (lower_address flags addr offset)))) 2867(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) 2868 flags addr offset) 2869 (vec_elt_rev ty (vec_load ty (lower_address flags addr offset)))) 2870(rule (vec_load_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) 2871 flags addr offset) 2872 (vec_elt_rev ty (vec_load ty (lower_address flags addr offset)))) 2873 2874 2875;;;; Rules for `uload8` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2876 2877;; 16- or 32-bit target types. 2878(rule (lower (has_type (gpr32_ty _ty) (uload8 _ flags addr offset))) 2879 (zext32_mem $I8 (lower_address flags addr offset))) 2880 2881;; 64-bit target types. 2882(rule 1 (lower (has_type (gpr64_ty _ty) (uload8 _ flags addr offset))) 2883 (zext64_mem $I8 (lower_address flags addr offset))) 2884 2885 2886;;;; Rules for `sload8` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2887 2888;; 16- or 32-bit target types. 2889(rule (lower (has_type (gpr32_ty _ty) (sload8 _ flags addr offset))) 2890 (sext32_mem $I8 (lower_address flags addr offset))) 2891 2892;; 64-bit target types. 2893(rule 1 (lower (has_type (gpr64_ty _ty) (sload8 _ flags addr offset))) 2894 (sext64_mem $I8 (lower_address flags addr offset))) 2895 2896 2897;;;; Rules for `uload16` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2898 2899;; 32-bit target type, big-endian source value. 2900(rule 3 (lower (has_type (gpr32_ty _ty) 2901 (uload16 _ flags @ (bigendian) addr offset))) 2902 (zext32_mem $I16 (lower_address flags addr offset))) 2903 2904;; 32-bit target type, little-endian source value (via explicit extension). 2905(rule 1 (lower (has_type (gpr32_ty _ty) 2906 (uload16 _ flags @ (littleendian) addr offset))) 2907 (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) 2908 (zext32_reg $I16 reg16))) 2909 2910;; 64-bit target type, big-endian source value. 2911(rule 4 (lower (has_type (gpr64_ty _ty) 2912 (uload16 _ flags @ (bigendian) addr offset))) 2913 (zext64_mem $I16 (lower_address flags addr offset))) 2914 2915;; 64-bit target type, little-endian source value (via explicit extension). 2916(rule 2 (lower (has_type (gpr64_ty _ty) 2917 (uload16 _ flags @ (littleendian) addr offset))) 2918 (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) 2919 (zext64_reg $I16 reg16))) 2920 2921 2922;;;; Rules for `sload16` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2923 2924;; 32-bit target type, big-endian source value. 2925(rule 2 (lower (has_type (gpr32_ty _ty) 2926 (sload16 _ flags @ (bigendian) addr offset))) 2927 (sext32_mem $I16 (lower_address flags addr offset))) 2928 2929;; 32-bit target type, little-endian source value (via explicit extension). 2930(rule 0 (lower (has_type (gpr32_ty _ty) 2931 (sload16 _ flags @ (littleendian) addr offset))) 2932 (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) 2933 (sext32_reg $I16 reg16))) 2934 2935;; 64-bit target type, big-endian source value. 2936(rule 3 (lower (has_type (gpr64_ty _ty) 2937 (sload16 _ flags @ (bigendian) addr offset))) 2938 (sext64_mem $I16 (lower_address flags addr offset))) 2939 2940;; 64-bit target type, little-endian source value (via explicit extension). 2941(rule 1 (lower (has_type (gpr64_ty _ty) 2942 (sload16 _ flags @ (littleendian) addr offset))) 2943 (let ((reg16 Reg (loadrev16 (lower_address flags addr offset)))) 2944 (sext64_reg $I16 reg16))) 2945 2946 2947;;;; Rules for `uload32` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2948 2949;; 64-bit target type, big-endian source value. 2950(rule 1 (lower (has_type (gpr64_ty _ty) 2951 (uload32 _ flags @ (bigendian) addr offset))) 2952 (zext64_mem $I32 (lower_address flags addr offset))) 2953 2954;; 64-bit target type, little-endian source value (via explicit extension). 2955(rule (lower (has_type (gpr64_ty _ty) 2956 (uload32 _ flags @ (littleendian) addr offset))) 2957 (let ((reg32 Reg (loadrev32 (lower_address flags addr offset)))) 2958 (zext64_reg $I32 reg32))) 2959 2960 2961;;;; Rules for `sload32` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2962 2963;; 64-bit target type, big-endian source value. 2964(rule 1 (lower (has_type (gpr64_ty _ty) 2965 (sload32 _ flags @ (bigendian) addr offset))) 2966 (sext64_mem $I32 (lower_address flags addr offset))) 2967 2968;; 64-bit target type, little-endian source value (via explicit extension). 2969(rule (lower (has_type (gpr64_ty _ty) 2970 (sload32 _ flags @ (littleendian) addr offset))) 2971 (let ((reg32 Reg (loadrev32 (lower_address flags addr offset)))) 2972 (sext64_reg $I32 reg32))) 2973 2974 2975;;;; Rules for `uloadNxM` and `sloadNxM` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2976 2977;; Unsigned 8->16 bit extension. 2978(rule (lower (has_type $I16X8 (uload8x8 _ flags addr offset))) 2979 (vec_unpacku_high $I8X16 (load_v64 $I8X16 flags addr offset))) 2980 2981;; Signed 8->16 bit extension. 2982(rule (lower (has_type $I16X8 (sload8x8 _ flags addr offset))) 2983 (vec_unpacks_high $I8X16 (load_v64 $I8X16 flags addr offset))) 2984 2985;; Unsigned 16->32 bit extension. 2986(rule (lower (has_type $I32X4 (uload16x4 _ flags addr offset))) 2987 (vec_unpacku_high $I16X8 (load_v64 $I16X8 flags addr offset))) 2988 2989;; Signed 16->32 bit extension. 2990(rule (lower (has_type $I32X4 (sload16x4 _ flags addr offset))) 2991 (vec_unpacks_high $I16X8 (load_v64 $I16X8 flags addr offset))) 2992 2993;; Unsigned 32->64 bit extension. 2994(rule (lower (has_type $I64X2 (uload32x2 _ flags addr offset))) 2995 (vec_unpacku_high $I32X4 (load_v64 $I32X4 flags addr offset))) 2996 2997;; Signed 32->64 bit extension. 2998(rule (lower (has_type $I64X2 (sload32x2 _ flags addr offset))) 2999 (vec_unpacks_high $I32X4 (load_v64 $I32X4 flags addr offset))) 3000 3001 3002;; Helper to load a 64-bit half-size vector from memory. 3003(decl load_v64 (Type MemFlags Value Offset32) Reg) 3004 3005;; Any big-endian source value, BE lane order. 3006(rule -1 (load_v64 _ flags @ (bigendian) addr offset) 3007 (if-let (LaneOrder.BigEndian) (lane_order)) 3008 (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0)) 3009 3010;; Any little-endian source value, LE lane order. 3011(rule -2 (load_v64 _ flags @ (littleendian) addr offset) 3012 (if-let (LaneOrder.LittleEndian) (lane_order)) 3013 (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0)) 3014 3015;; Big-endian or little-endian 8x8-bit source value, BE lane order. 3016(rule (load_v64 (multi_lane 8 16) flags addr offset) 3017 (if-let (LaneOrder.BigEndian) (lane_order)) 3018 (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0)) 3019 3020;; Big-endian or little-endian 8x8-bit source value, LE lane order. 3021(rule 1 (load_v64 (multi_lane 8 16) flags addr offset) 3022 (if-let (LaneOrder.LittleEndian) (lane_order)) 3023 (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0)) 3024 3025;; Little-endian 4x16-bit source value, BE lane order. 3026(rule (load_v64 (multi_lane 16 8) flags @ (littleendian) addr offset) 3027 (if-let (LaneOrder.BigEndian) (lane_order)) 3028 (vec_rot_imm $I16X8 3029 (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0) 8)) 3030 3031;; Big-endian 4x16-bit source value, LE lane order. 3032(rule 1 (load_v64 (multi_lane 16 8) flags @ (bigendian) addr offset) 3033 (if-let (LaneOrder.LittleEndian) (lane_order)) 3034 (vec_rot_imm $I16X8 3035 (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0) 8)) 3036 3037;; Little-endian 2x32-bit source value, BE lane order. 3038(rule (load_v64 (multi_lane 32 4) flags @ (littleendian) addr offset) 3039 (if-let (LaneOrder.BigEndian) (lane_order)) 3040 (vec_rot_imm $I64X2 3041 (vec_load_lane_little_undef $I64X2 (lower_address flags addr offset) 0) 32)) 3042 3043;; Big-endian 2x32-bit source value, LE lane order. 3044(rule 1 (load_v64 (multi_lane 32 4) flags @ (bigendian) addr offset) 3045 (if-let (LaneOrder.LittleEndian) (lane_order)) 3046 (vec_rot_imm $I64X2 3047 (vec_load_lane_undef $I64X2 (lower_address flags addr offset) 0) 32)) 3048 3049 3050;;;; Rules for `store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3051 3052;; The actual store logic for integer types is identical for the `store`, 3053;; `istoreNN`, and `atomic_store` instructions, so we share common helpers. 3054 3055;; Store 8-bit integer type, main lowering entry point. 3056(rule (lower (store flags val @ (value_type $I8) addr offset)) 3057 (side_effect (istore8_impl flags val addr offset))) 3058 3059;; Store 16-bit integer type, main lowering entry point. 3060(rule (lower (store flags val @ (value_type $I16) addr offset)) 3061 (side_effect (istore16_impl flags val addr offset))) 3062 3063;; Store 32-bit integer type, main lowering entry point. 3064(rule (lower (store flags val @ (value_type $I32) addr offset)) 3065 (side_effect (istore32_impl flags val addr offset))) 3066 3067;; Store 64-bit integer type, main lowering entry point. 3068(rule (lower (store flags val @ (value_type $I64) addr offset)) 3069 (side_effect (istore64_impl flags val addr offset))) 3070 3071;; Store 16-bit big-endian floating-point type (as vector lane). 3072(rule -1 (lower (store flags @ (bigendian) 3073 val @ (value_type $F16) addr offset)) 3074 (side_effect (vec_store_lane $F16X8 val 3075 (lower_address flags addr offset) 0))) 3076 3077;; Store 16-bit little-endian floating-point type (as vector lane). 3078(rule (lower (store flags @ (littleendian) 3079 val @ (value_type $F16) addr offset)) 3080 (side_effect (vec_store_lane_little $F16X8 val 3081 (lower_address flags addr offset) 0))) 3082 3083;; Store 32-bit big-endian floating-point type (as vector lane). 3084(rule -1 (lower (store flags @ (bigendian) 3085 val @ (value_type $F32) addr offset)) 3086 (side_effect (vec_store_lane $F32X4 val 3087 (lower_address flags addr offset) 0))) 3088 3089;; Store 32-bit little-endian floating-point type (as vector lane). 3090(rule (lower (store flags @ (littleendian) 3091 val @ (value_type $F32) addr offset)) 3092 (side_effect (vec_store_lane_little $F32X4 val 3093 (lower_address flags addr offset) 0))) 3094 3095;; Store 64-bit big-endian floating-point type (as vector lane). 3096(rule -1 (lower (store flags @ (bigendian) 3097 val @ (value_type $F64) addr offset)) 3098 (side_effect (vec_store_lane $F64X2 val 3099 (lower_address flags addr offset) 0))) 3100 3101;; Store 64-bit little-endian floating-point type (as vector lane). 3102(rule (lower (store flags @ (littleendian) 3103 val @ (value_type $F64) addr offset)) 3104 (side_effect (vec_store_lane_little $F64X2 val 3105 (lower_address flags addr offset) 0))) 3106 3107;; Store 128-bit big-endian vector type, BE lane order - direct store. 3108(rule 4 (lower (store flags @ (bigendian) 3109 val @ (value_type (vr128_ty ty)) addr offset)) 3110 (if-let (LaneOrder.BigEndian) (lane_order)) 3111 (side_effect (vec_store val (lower_address flags addr offset)))) 3112 3113;; Store 128-bit little-endian vector type, BE lane order - byte-reversed store. 3114(rule 3 (lower (store flags @ (littleendian) 3115 val @ (value_type (vr128_ty ty)) addr offset)) 3116 (if-let (LaneOrder.BigEndian) (lane_order)) 3117 (side_effect (vec_store_byte_rev ty val flags addr offset))) 3118 3119;; Store 128-bit big-endian vector type, LE lane order - element-reversed store. 3120(rule 2 (lower (store flags @ (bigendian) 3121 val @ (value_type (vr128_ty ty)) addr offset)) 3122 (if-let (LaneOrder.LittleEndian) (lane_order)) 3123 (side_effect (vec_store_elt_rev ty val flags addr offset))) 3124 3125;; Store 128-bit little-endian vector type, LE lane order - fully-reversed store. 3126(rule 1 (lower (store flags @ (littleendian) 3127 val @ (value_type (vr128_ty ty)) addr offset)) 3128 (if-let (LaneOrder.LittleEndian) (lane_order)) 3129 (side_effect (vec_store_full_rev ty val flags addr offset))) 3130 3131 3132;; Helper to perform a 128-bit full-vector byte-reversed store. 3133(decl vec_store_full_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult) 3134 3135;; Full-vector byte-reversed store via single instruction on z15. 3136(rule 1 (vec_store_full_rev (vxrs_ext2_enabled) val flags addr offset) 3137 (vec_storerev val (lower_address flags addr offset))) 3138 3139;; Full-vector byte-reversed store via GPRs on z14. 3140(rule (vec_store_full_rev (vxrs_ext2_disabled) val flags addr offset) 3141 (let ((lo_addr MemArg (lower_address_bias flags addr offset 0)) 3142 (hi_addr MemArg (lower_address_bias flags addr offset 8)) 3143 (lo_val Reg (vec_extract_lane $I64X2 val 1 (zero_reg))) 3144 (hi_val Reg (vec_extract_lane $I64X2 val 0 (zero_reg)))) 3145 (side_effect_concat (storerev64 lo_val lo_addr) 3146 (storerev64 hi_val hi_addr)))) 3147 3148 3149;; Helper to perform an element-wise byte-reversed store. 3150(decl vec_store_byte_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult) 3151 3152;; Element-wise byte-reversed 1x128-bit store is a full byte-reversed store. 3153(rule -1 (vec_store_byte_rev $I128 val flags addr offset) 3154 (vec_store_full_rev $I128 val flags addr offset)) 3155 3156;; Same for `f128`. 3157(rule -1 (vec_store_byte_rev $F128 val flags addr offset) 3158 (vec_store_full_rev $F128 val flags addr offset)) 3159 3160;; Element-wise byte-reversed 16x8-bit store is a direct store. 3161(rule (vec_store_byte_rev (multi_lane 8 16) val flags addr offset) 3162 (vec_store val (lower_address flags addr offset))) 3163 3164;; Element-wise byte-reversed store via single instruction on z15. 3165(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) 3166 val flags addr offset) 3167 (vec_store_byte64rev val (lower_address flags addr offset))) 3168(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) 3169 val flags addr offset) 3170 (vec_store_byte32rev val (lower_address flags addr offset))) 3171(rule 1 (vec_store_byte_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) 3172 val flags addr offset) 3173 (vec_store_byte16rev val (lower_address flags addr offset))) 3174 3175;; Element-wise byte-reversed load as element-swapped byte-reversed store on z14. 3176(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) 3177 val flags addr offset) 3178 (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset)) 3179(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) 3180 val flags addr offset) 3181 (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset)) 3182(rule (vec_store_byte_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) 3183 val flags addr offset) 3184 (vec_store_full_rev ty (vec_elt_rev ty val) flags addr offset)) 3185 3186 3187;; Helper to perform an element-reversed store. 3188(decl vec_store_elt_rev (Type Reg MemFlags Value Offset32) SideEffectNoResult) 3189 3190;; Element-reversed 1x128-bit store is a direct store. 3191(rule -1 (vec_store_elt_rev $I128 val flags addr offset) 3192 (vec_store val (lower_address flags addr offset))) 3193 3194;; Same for `f128`. 3195(rule -1 (vec_store_elt_rev $F128 val flags addr offset) 3196 (vec_store val (lower_address flags addr offset))) 3197 3198;; Element-reversed 16x8-bit store is a full byte-reversed store. 3199(rule (vec_store_elt_rev ty @ (multi_lane 8 16) val flags addr offset) 3200 (vec_store_full_rev ty val flags addr offset)) 3201 3202;; Element-reversed store via single instruction on z15. 3203(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 64 2)) 3204 val flags addr offset) 3205 (vec_store_elt64rev val (lower_address flags addr offset))) 3206(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 32 4)) 3207 val flags addr offset) 3208 (vec_store_elt32rev val (lower_address flags addr offset))) 3209(rule 1 (vec_store_elt_rev (and (vxrs_ext2_enabled) ty @ (multi_lane 16 8)) 3210 val flags addr offset) 3211 (vec_store_elt16rev val (lower_address flags addr offset))) 3212 3213;; Element-reversed store as element-swapped direct store on z14. 3214(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 64 2)) 3215 val flags addr offset) 3216 (vec_store (vec_elt_rev ty val) (lower_address flags addr offset))) 3217(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 32 4)) 3218 val flags addr offset) 3219 (vec_store (vec_elt_rev ty val) (lower_address flags addr offset))) 3220(rule (vec_store_elt_rev (and (vxrs_ext2_disabled) ty @ (multi_lane 16 8)) 3221 val flags addr offset) 3222 (vec_store (vec_elt_rev ty val) (lower_address flags addr offset))) 3223 3224 3225;;;; Rules for 8-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3226 3227;; Main `istore8` lowering entry point, dispatching to the helper. 3228(rule (lower (istore8 flags val addr offset)) 3229 (side_effect (istore8_impl flags val addr offset))) 3230 3231;; Helper to store 8-bit integer types. 3232(decl istore8_impl (MemFlags Value Value Offset32) SideEffectNoResult) 3233 3234;; Store 8-bit integer types, register input. 3235(rule (istore8_impl flags val addr offset) 3236 (store8 (put_in_reg val) (lower_address flags addr offset))) 3237 3238;; Store 8-bit integer types, immediate input. 3239(rule 1 (istore8_impl flags (u8_from_value imm) addr offset) 3240 (store8_imm imm (lower_address flags addr offset))) 3241 3242 3243;;;; Rules for 16-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3244 3245;; Main `istore16` lowering entry point, dispatching to the helper. 3246(rule (lower (istore16 flags val addr offset)) 3247 (side_effect (istore16_impl flags val addr offset))) 3248 3249;; Helper to store 16-bit integer types. 3250(decl istore16_impl (MemFlags Value Value Offset32) SideEffectNoResult) 3251 3252;; Store 16-bit big-endian integer types, register input. 3253(rule 2 (istore16_impl flags @ (bigendian) val addr offset) 3254 (store16 (put_in_reg val) (lower_address flags addr offset))) 3255 3256;; Store 16-bit little-endian integer types, register input. 3257(rule 0 (istore16_impl flags @ (littleendian) val addr offset) 3258 (storerev16 (put_in_reg val) (lower_address flags addr offset))) 3259 3260;; Store 16-bit big-endian integer types, immediate input. 3261(rule 3 (istore16_impl flags @ (bigendian) (i16_from_value imm) addr offset) 3262 (store16_imm imm (lower_address flags addr offset))) 3263 3264;; Store 16-bit little-endian integer types, immediate input. 3265(rule 1 (istore16_impl flags @ (littleendian) (i16_from_swapped_value imm) addr offset) 3266 (store16_imm imm (lower_address flags addr offset))) 3267 3268 3269;;;; Rules for 32-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3270 3271;; Main `istore32` lowering entry point, dispatching to the helper. 3272(rule (lower (istore32 flags val addr offset)) 3273 (side_effect (istore32_impl flags val addr offset))) 3274 3275;; Helper to store 32-bit integer types. 3276(decl istore32_impl (MemFlags Value Value Offset32) SideEffectNoResult) 3277 3278;; Store 32-bit big-endian integer types, register input. 3279(rule 1 (istore32_impl flags @ (bigendian) val addr offset) 3280 (store32 (put_in_reg val) (lower_address flags addr offset))) 3281 3282;; Store 32-bit big-endian integer types, immediate input. 3283(rule 2 (istore32_impl flags @ (bigendian) (i16_from_value imm) addr offset) 3284 (store32_simm16 imm (lower_address flags addr offset))) 3285 3286;; Store 32-bit little-endian integer types. 3287(rule 0 (istore32_impl flags @ (littleendian) val addr offset) 3288 (storerev32 (put_in_reg val) (lower_address flags addr offset))) 3289 3290 3291;;;; Rules for 64-bit integer stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3292 3293;; Helper to store 64-bit integer types. 3294(decl istore64_impl (MemFlags Value Value Offset32) SideEffectNoResult) 3295 3296;; Store 64-bit big-endian integer types, register input. 3297(rule 1 (istore64_impl flags @ (bigendian) val addr offset) 3298 (store64 (put_in_reg val) (lower_address flags addr offset))) 3299 3300;; Store 64-bit big-endian integer types, immediate input. 3301(rule 2 (istore64_impl flags @ (bigendian) (i16_from_value imm) addr offset) 3302 (store64_simm16 imm (lower_address flags addr offset))) 3303 3304;; Store 64-bit little-endian integer types. 3305(rule 0 (istore64_impl flags @ (littleendian) val addr offset) 3306 (storerev64 (put_in_reg val) (lower_address flags addr offset))) 3307 3308 3309;;;; Rules for `atomic_rmw` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3310 3311;; Atomic operations that do not require a compare-and-swap loop. 3312 3313;; Atomic AND for 32/64-bit big-endian types, using a single instruction. 3314(rule 1 (lower (has_type (ty_32_or_64 ty) 3315 (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.And) addr src))) 3316 (atomic_rmw_and ty (put_in_reg src) 3317 (lower_address flags addr (zero_offset)))) 3318 3319;; Atomic AND for 32/64-bit big-endian types, using byte-swapped input/output. 3320(rule (lower (has_type (ty_32_or_64 ty) 3321 (atomic_rmw _ flags @ (littleendian) (AtomicRmwOp.And) addr src))) 3322 (bswap_reg ty (atomic_rmw_and ty (bswap_reg ty (put_in_reg src)) 3323 (lower_address flags addr (zero_offset))))) 3324 3325;; Atomic OR for 32/64-bit big-endian types, using a single instruction. 3326(rule 1 (lower (has_type (ty_32_or_64 ty) 3327 (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Or) addr src))) 3328 (atomic_rmw_or ty (put_in_reg src) 3329 (lower_address flags addr (zero_offset)))) 3330 3331;; Atomic OR for 32/64-bit little-endian types, using byte-swapped input/output. 3332(rule (lower (has_type (ty_32_or_64 ty) 3333 (atomic_rmw _ flags @ (littleendian) (AtomicRmwOp.Or) addr src))) 3334 (bswap_reg ty (atomic_rmw_or ty (bswap_reg ty (put_in_reg src)) 3335 (lower_address flags addr (zero_offset))))) 3336 3337;; Atomic XOR for 32/64-bit big-endian types, using a single instruction. 3338(rule 1 (lower (has_type (ty_32_or_64 ty) 3339 (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Xor) addr src))) 3340 (atomic_rmw_xor ty (put_in_reg src) 3341 (lower_address flags addr (zero_offset)))) 3342 3343;; Atomic XOR for 32/64-bit little-endian types, using byte-swapped input/output. 3344(rule (lower (has_type (ty_32_or_64 ty) 3345 (atomic_rmw _ flags @ (littleendian) (AtomicRmwOp.Xor) addr src))) 3346 (bswap_reg ty (atomic_rmw_xor ty (bswap_reg ty (put_in_reg src)) 3347 (lower_address flags addr (zero_offset))))) 3348 3349;; Atomic ADD for 32/64-bit big-endian types, using a single instruction. 3350(rule (lower (has_type (ty_32_or_64 ty) 3351 (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Add) addr src))) 3352 (atomic_rmw_add ty (put_in_reg src) 3353 (lower_address flags addr (zero_offset)))) 3354 3355;; Atomic SUB for 32/64-bit big-endian types, using atomic ADD with negated input. 3356(rule (lower (has_type (ty_32_or_64 ty) 3357 (atomic_rmw _ flags @ (bigendian) (AtomicRmwOp.Sub) addr src))) 3358 (atomic_rmw_add ty (neg_reg ty (put_in_reg src)) 3359 (lower_address flags addr (zero_offset)))) 3360 3361 3362;; Atomic operations that require a compare-and-swap loop. 3363 3364;; Operations for 32/64-bit types can use a fullword compare-and-swap loop. 3365(rule -1 (lower (has_type (ty_32_or_64 ty) (atomic_rmw _ flags op addr src))) 3366 (let ((src_reg Reg (put_in_reg src)) 3367 (addr_reg Reg (put_in_reg addr)) 3368 ;; Create body of compare-and-swap loop. 3369 (ib VecMInstBuilder (inst_builder_new)) 3370 (val0 Reg (writable_reg_to_reg (casloop_val_reg))) 3371 (val1 Reg (atomic_rmw_body ib ty flags op 3372 (casloop_tmp_reg) val0 src_reg))) 3373 ;; Emit compare-and-swap loop and extract final result. 3374 (casloop ib ty flags addr_reg val1))) 3375 3376;; Operations for 8/16-bit types must operate on the surrounding aligned word. 3377(rule -2 (lower (has_type (ty_8_or_16 ty) (atomic_rmw _ flags op addr src))) 3378 (let ((src_reg Reg (put_in_reg src)) 3379 (addr_reg Reg (put_in_reg addr)) 3380 ;; Prepare access to surrounding aligned word. 3381 (bitshift Reg (casloop_bitshift addr_reg)) 3382 (aligned_addr Reg (casloop_aligned_addr addr_reg)) 3383 ;; Create body of compare-and-swap loop. 3384 (ib VecMInstBuilder (inst_builder_new)) 3385 (val0 Reg (writable_reg_to_reg (casloop_val_reg))) 3386 (val1 Reg (casloop_rotate_in ib ty flags bitshift val0)) 3387 (val2 Reg (atomic_rmw_body ib ty flags op 3388 (casloop_tmp_reg) val1 src_reg)) 3389 (val3 Reg (casloop_rotate_out ib ty flags bitshift val2))) 3390 ;; Emit compare-and-swap loop and extract final result. 3391 (casloop_subword ib ty flags aligned_addr bitshift val3))) 3392 3393;; Loop bodies for atomic read-modify-write operations. 3394(decl atomic_rmw_body (VecMInstBuilder Type MemFlags AtomicRmwOp 3395 WritableReg Reg Reg) Reg) 3396 3397;; Loop bodies for 32-/64-bit atomic XCHG operations. 3398;; Simply use the source (possibly byte-swapped) as new target value. 3399(rule 2 (atomic_rmw_body ib (ty_32_or_64 ty) (bigendian) 3400 (AtomicRmwOp.Xchg) tmp val src) 3401 src) 3402(rule 1 (atomic_rmw_body ib (ty_32_or_64 ty) (littleendian) 3403 (AtomicRmwOp.Xchg) tmp val src) 3404 (bswap_reg ty src)) 3405 3406;; Loop bodies for 32-/64-bit atomic NAND operations. 3407;; On z15 this can use the NN(G)RK instruction. On z14, perform an And 3408;; operation and invert the result. In the little-endian case, we can 3409;; simply byte-swap the source operand. 3410(rule 4 (atomic_rmw_body ib (and (mie3_enabled) (ty_32_or_64 ty)) (bigendian) 3411 (AtomicRmwOp.Nand) tmp val src) 3412 (push_alu_reg ib (aluop_not_and ty) tmp val src)) 3413(rule 3 (atomic_rmw_body ib (and (mie3_enabled) (ty_32_or_64 ty)) (littleendian) 3414 (AtomicRmwOp.Nand) tmp val src) 3415 (push_alu_reg ib (aluop_not_and ty) tmp val (bswap_reg ty src))) 3416(rule 2 (atomic_rmw_body ib (and (mie3_disabled) (ty_32_or_64 ty)) (bigendian) 3417 (AtomicRmwOp.Nand) tmp val src) 3418 (push_not_reg ib ty tmp 3419 (push_alu_reg ib (aluop_and ty) tmp val src))) 3420(rule 1 (atomic_rmw_body ib (and (mie3_disabled) (ty_32_or_64 ty)) (littleendian) 3421 (AtomicRmwOp.Nand) tmp val src) 3422 (push_not_reg ib ty tmp 3423 (push_alu_reg ib (aluop_and ty) tmp val (bswap_reg ty src)))) 3424 3425;; Loop bodies for 8-/16-bit atomic bit operations. 3426;; These use the "rotate-then-<op>-selected bits" family of instructions. 3427;; For the Nand operation, we again perform And and invert the result. 3428(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Xchg) tmp val src) 3429 (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Insert) tmp val src)) 3430(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.And) tmp val src) 3431 (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.And) tmp val src)) 3432(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Or) tmp val src) 3433 (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Or) tmp val src)) 3434(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Xor) tmp val src) 3435 (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.Xor) tmp val src)) 3436(rule (atomic_rmw_body ib (ty_8_or_16 ty) flags (AtomicRmwOp.Nand) tmp val src) 3437 (atomic_rmw_body_invert ib ty flags tmp 3438 (atomic_rmw_body_rxsbg ib ty flags (RxSBGOp.And) tmp val src))) 3439 3440;; RxSBG subword operation. 3441(decl atomic_rmw_body_rxsbg (VecMInstBuilder Type MemFlags RxSBGOp 3442 WritableReg Reg Reg) Reg) 3443;; 8-bit case: use the low byte of "src" and the high byte of "val". 3444(rule (atomic_rmw_body_rxsbg ib $I8 _ op tmp val src) 3445 (push_rxsbg ib op tmp val src 32 40 24)) 3446;; 16-bit big-endian case: use the low two bytes of "src" and the 3447;; high two bytes of "val". 3448(rule 1 (atomic_rmw_body_rxsbg ib $I16 (bigendian) op tmp val src) 3449 (push_rxsbg ib op tmp val src 32 48 16)) 3450;; 16-bit little-endian case: use the low two bytes of "src", byte-swapped 3451;; so they end up in the high two bytes, and the low two bytes of "val". 3452(rule (atomic_rmw_body_rxsbg ib $I16 (littleendian) op tmp val src) 3453 (push_rxsbg ib op tmp val (bswap_reg $I32 src) 48 64 -16)) 3454 3455;; Invert a subword. 3456(decl atomic_rmw_body_invert (VecMInstBuilder Type MemFlags WritableReg Reg) Reg) 3457;; 8-bit case: invert the high byte. 3458(rule (atomic_rmw_body_invert ib $I8 _ tmp val) 3459 (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xff000000 0))) 3460;; 16-bit big-endian case: invert the two high bytes. 3461(rule 1 (atomic_rmw_body_invert ib $I16 (bigendian) tmp val) 3462 (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xffff0000 0))) 3463;; 16-bit little-endian case: invert the two low bytes. 3464(rule (atomic_rmw_body_invert ib $I16 (littleendian) tmp val) 3465 (push_xor_uimm32shifted ib $I32 tmp val (uimm32shifted 0xffff 0))) 3466 3467;; Loop bodies for atomic ADD/SUB operations. 3468(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Add) tmp val src) 3469 (atomic_rmw_body_addsub ib ty flags (aluop_add (ty_ext32 ty)) tmp val src)) 3470(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Sub) tmp val src) 3471 (atomic_rmw_body_addsub ib ty flags (aluop_sub (ty_ext32 ty)) tmp val src)) 3472 3473;; Addition or subtraction operation. 3474(decl atomic_rmw_body_addsub (VecMInstBuilder Type MemFlags ALUOp 3475 WritableReg Reg Reg) Reg) 3476;; 32/64-bit big-endian case: just a regular add/sub operation. 3477(rule 2 (atomic_rmw_body_addsub ib (ty_32_or_64 ty) (bigendian) op tmp val src) 3478 (push_alu_reg ib op tmp val src)) 3479;; 32/64-bit little-endian case: byte-swap the value loaded from memory before 3480;; and after performing the operation in native endianness. 3481(rule 1 (atomic_rmw_body_addsub ib (ty_32_or_64 ty) (littleendian) op tmp val src) 3482 (let ((val_swapped Reg (push_bswap_reg ib ty tmp val)) 3483 (res_swapped Reg (push_alu_reg ib op tmp val_swapped src))) 3484 (push_bswap_reg ib ty tmp res_swapped))) 3485;; 8-bit case: perform a 32-bit addition of the source value shifted by 24 bits 3486;; to the memory value, which contains the target in its high byte. 3487(rule (atomic_rmw_body_addsub ib $I8 _ op tmp val src) 3488 (let ((src_shifted Reg (lshl_imm $I32 src 24))) 3489 (push_alu_reg ib op tmp val src_shifted))) 3490;; 16-bit big-endian case: similar, just shift the source by 16 bits. 3491(rule 3 (atomic_rmw_body_addsub ib $I16 (bigendian) op tmp val src) 3492 (let ((src_shifted Reg (lshl_imm $I32 src 16))) 3493 (push_alu_reg ib op tmp val src_shifted))) 3494;; 16-bit little-endian case: the same, but in addition we need to byte-swap 3495;; the memory value before and after the operation. Since the value was placed 3496;; in the low two bytes by our standard rotation, we can use a 32-bit byte-swap 3497;; and the native-endian value will end up in the high bytes where we need it 3498;; to perform the operation. 3499(rule (atomic_rmw_body_addsub ib $I16 (littleendian) op tmp val src) 3500 (let ((src_shifted Reg (lshl_imm $I32 src 16)) 3501 (val_swapped Reg (push_bswap_reg ib $I32 tmp val)) 3502 (res_swapped Reg (push_alu_reg ib op tmp val_swapped src_shifted))) 3503 (push_bswap_reg ib $I32 tmp res_swapped))) 3504 3505;; Loop bodies for atomic MIN/MAX operations. 3506(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Smin) tmp val src) 3507 (atomic_rmw_body_minmax ib ty flags (cmpop_cmps (ty_ext32 ty)) 3508 (intcc_as_cond (IntCC.SignedLessThan)) tmp val src)) 3509(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Smax) tmp val src) 3510 (atomic_rmw_body_minmax ib ty flags (cmpop_cmps (ty_ext32 ty)) 3511 (intcc_as_cond (IntCC.SignedGreaterThan)) tmp val src)) 3512(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Umin) tmp val src) 3513 (atomic_rmw_body_minmax ib ty flags (cmpop_cmpu (ty_ext32 ty)) 3514 (intcc_as_cond (IntCC.UnsignedLessThan)) tmp val src)) 3515(rule (atomic_rmw_body ib ty flags (AtomicRmwOp.Umax) tmp val src) 3516 (atomic_rmw_body_minmax ib ty flags (cmpop_cmpu (ty_ext32 ty)) 3517 (intcc_as_cond (IntCC.UnsignedGreaterThan)) tmp val src)) 3518 3519;; Minimum or maximum operation. 3520(decl atomic_rmw_body_minmax (VecMInstBuilder Type MemFlags CmpOp Cond 3521 WritableReg Reg Reg) Reg) 3522;; 32/64-bit big-endian case: just a comparison followed by a conditional 3523;; break out of the loop if the memory value does not need to change. 3524;; If it does need to change, the new value is simply the source operand. 3525(rule 2 (atomic_rmw_body_minmax ib (ty_32_or_64 ty) (bigendian) 3526 op cond tmp val src) 3527 (let ((_ Reg (push_break_if ib (cmp_rr op src val) (invert_cond cond)))) 3528 src)) 3529;; 32/64-bit little-endian case: similar, but we need to byte-swap the 3530;; memory value before the comparison. If we need to store the new value, 3531;; it also needs to be byte-swapped. 3532(rule 1 (atomic_rmw_body_minmax ib (ty_32_or_64 ty) (littleendian) 3533 op cond tmp val src) 3534 (let ((val_swapped Reg (push_bswap_reg ib ty tmp val)) 3535 (_ Reg (push_break_if ib (cmp_rr op src val_swapped) 3536 (invert_cond cond)))) 3537 (push_bswap_reg ib ty tmp src))) 3538;; 8-bit case: compare the memory value (which contains the target in the 3539;; high byte) with the source operand shifted by 24 bits. Note that in 3540;; the case where the high bytes are equal, the comparison may succeed 3541;; or fail depending on the unrelated low bits of the memory value, and 3542;; so we either may or may not perform the update. But it would be an 3543;; update with the same value in any case, so this does not matter. 3544(rule (atomic_rmw_body_minmax ib $I8 _ op cond tmp val src) 3545 (let ((src_shifted Reg (lshl_imm $I32 src 24)) 3546 (_ Reg (push_break_if ib (cmp_rr op src_shifted val) 3547 (invert_cond cond)))) 3548 (push_rxsbg ib (RxSBGOp.Insert) tmp val src_shifted 32 40 0))) 3549;; 16-bit big-endian case: similar, just shift the source by 16 bits. 3550(rule 3 (atomic_rmw_body_minmax ib $I16 (bigendian) op cond tmp val src) 3551 (let ((src_shifted Reg (lshl_imm $I32 src 16)) 3552 (_ Reg (push_break_if ib (cmp_rr op src_shifted val) 3553 (invert_cond cond)))) 3554 (push_rxsbg ib (RxSBGOp.Insert) tmp val src_shifted 32 48 0))) 3555;; 16-bit little-endian case: similar, but in addition byte-swap the 3556;; memory value before and after the operation, like for _addsub_. 3557(rule (atomic_rmw_body_minmax ib $I16 (littleendian) op cond tmp val src) 3558 (let ((src_shifted Reg (lshl_imm $I32 src 16)) 3559 (val_swapped Reg (push_bswap_reg ib $I32 tmp val)) 3560 (_ Reg (push_break_if ib (cmp_rr op src_shifted val_swapped) 3561 (invert_cond cond))) 3562 (res_swapped Reg (push_rxsbg ib (RxSBGOp.Insert) 3563 tmp val_swapped src_shifted 32 48 0))) 3564 (push_bswap_reg ib $I32 tmp res_swapped))) 3565 3566 3567;;;; Rules for `atomic_cas` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3568 3569;; 32/64-bit big-endian atomic compare-and-swap instruction. 3570(rule 2 (lower (has_type (ty_32_or_64 ty) 3571 (atomic_cas _ flags @ (bigendian) addr src1 src2))) 3572 (atomic_cas_impl ty (put_in_reg src1) (put_in_reg src2) 3573 (lower_address flags addr (zero_offset)))) 3574 3575;; 32/64-bit little-endian atomic compare-and-swap instruction. 3576;; Implemented by byte-swapping old/new inputs and the output. 3577(rule 1 (lower (has_type (ty_32_or_64 ty) 3578 (atomic_cas _ flags @ (littleendian) addr src1 src2))) 3579 (bswap_reg ty (atomic_cas_impl ty (bswap_reg ty (put_in_reg src1)) 3580 (bswap_reg ty (put_in_reg src2)) 3581 (lower_address flags addr (zero_offset))))) 3582 3583;; 8/16-bit atomic compare-and-swap implemented via loop. 3584(rule (lower (has_type (ty_8_or_16 ty) (atomic_cas _ flags addr src1 src2))) 3585 (let ((src1_reg Reg (put_in_reg src1)) 3586 (src2_reg Reg (put_in_reg src2)) 3587 (addr_reg Reg (put_in_reg addr)) 3588 ;; Prepare access to the surrounding aligned word. 3589 (bitshift Reg (casloop_bitshift addr_reg)) 3590 (aligned_addr Reg (casloop_aligned_addr addr_reg)) 3591 ;; Create body of compare-and-swap loop. 3592 (ib VecMInstBuilder (inst_builder_new)) 3593 (val0 Reg (writable_reg_to_reg (casloop_val_reg))) 3594 (val1 Reg (casloop_rotate_in ib ty flags bitshift val0)) 3595 (val2 Reg (atomic_cas_body ib ty flags 3596 (casloop_tmp_reg) val1 src1_reg src2_reg)) 3597 (val3 Reg (casloop_rotate_out ib ty flags bitshift val2))) 3598 ;; Emit compare-and-swap loop and extract final result. 3599 (casloop_subword ib ty flags aligned_addr bitshift val3))) 3600 3601;; Emit loop body instructions to perform a subword compare-and-swap. 3602(decl atomic_cas_body (VecMInstBuilder Type MemFlags 3603 WritableReg Reg Reg Reg) Reg) 3604 3605;; 8-bit case: "val" contains the value loaded from memory in the high byte. 3606;; Compare with the comparison value in the low byte of "src1". If unequal, 3607;; break out of the loop, otherwise replace the target byte in "val" with 3608;; the low byte of "src2". 3609(rule (atomic_cas_body ib $I8 _ tmp val src1 src2) 3610 (let ((_ Reg (push_break_if ib (rxsbg_test (RxSBGOp.Xor) val src1 32 40 24) 3611 (intcc_as_cond (IntCC.NotEqual))))) 3612 (push_rxsbg ib (RxSBGOp.Insert) tmp val src2 32 40 24))) 3613 3614;; 16-bit big-endian case: Same as above, except with values in the high 3615;; two bytes of "val" and low two bytes of "src1" and "src2". 3616(rule 1 (atomic_cas_body ib $I16 (bigendian) tmp val src1 src2) 3617 (let ((_ Reg (push_break_if ib (rxsbg_test (RxSBGOp.Xor) val src1 32 48 16) 3618 (intcc_as_cond (IntCC.NotEqual))))) 3619 (push_rxsbg ib (RxSBGOp.Insert) tmp val src2 32 48 16))) 3620 3621;; 16-bit little-endian case: "val" here contains a little-endian value in the 3622;; *low* two bytes. "src1" and "src2" contain native (i.e. big-endian) values 3623;; in their low two bytes. Perform the operation in little-endian mode by 3624;; byte-swapping "src1" and "src" ahead of the loop. Note that this is a 3625;; 32-bit operation so the little-endian 16-bit values end up in the *high* 3626;; two bytes of the swapped values. 3627(rule (atomic_cas_body ib $I16 (littleendian) tmp val src1 src2) 3628 (let ((src1_swapped Reg (bswap_reg $I32 src1)) 3629 (src2_swapped Reg (bswap_reg $I32 src2)) 3630 (_ Reg (push_break_if ib 3631 (rxsbg_test (RxSBGOp.Xor) val src1_swapped 48 64 -16) 3632 (intcc_as_cond (IntCC.NotEqual))))) 3633 (push_rxsbg ib (RxSBGOp.Insert) tmp val src2_swapped 48 64 -16))) 3634 3635 3636;;;; Rules for `atomic_load` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3637 3638;; Atomic loads can be implemented via regular loads on this platform. 3639 3640;; 8-bit atomic load. 3641(rule (lower (has_type $I8 (atomic_load _ flags addr))) 3642 (zext32_mem $I8 (lower_address flags addr (zero_offset)))) 3643 3644;; 16-bit big-endian atomic load. 3645(rule 1 (lower (has_type $I16 (atomic_load _ flags @ (bigendian) addr))) 3646 (zext32_mem $I16 (lower_address flags addr (zero_offset)))) 3647 3648;; 16-bit little-endian atomic load. 3649(rule (lower (has_type $I16 (atomic_load _ flags @ (littleendian) addr))) 3650 (loadrev16 (lower_address flags addr (zero_offset)))) 3651 3652;; 32-bit big-endian atomic load. 3653(rule 1 (lower (has_type $I32 (atomic_load _ flags @ (bigendian) addr))) 3654 (load32 (lower_address flags addr (zero_offset)))) 3655 3656;; 32-bit little-endian atomic load. 3657(rule (lower (has_type $I32 (atomic_load _ flags @ (littleendian) addr))) 3658 (loadrev32 (lower_address flags addr (zero_offset)))) 3659 3660;; 64-bit big-endian atomic load. 3661(rule 1 (lower (has_type $I64 (atomic_load _ flags @ (bigendian) addr))) 3662 (load64 (lower_address flags addr (zero_offset)))) 3663 3664;; 64-bit little-endian atomic load. 3665(rule (lower (has_type $I64 (atomic_load _ flags @ (littleendian) addr))) 3666 (loadrev64 (lower_address flags addr (zero_offset)))) 3667 3668 3669;;;; Rules for `atomic_store` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3670 3671;; Atomic stores can be implemented via regular stores followed by a fence. 3672(decl atomic_store_impl (SideEffectNoResult) InstOutput) 3673(rule (atomic_store_impl store) 3674 (let ((_ InstOutput (side_effect store))) 3675 (side_effect (fence_impl)))) 3676 3677;; 8-bit atomic store. 3678(rule (lower (atomic_store flags val @ (value_type $I8) addr)) 3679 (atomic_store_impl (istore8_impl flags val addr (zero_offset)))) 3680 3681;; 16-bit atomic store. 3682(rule (lower (atomic_store flags val @ (value_type $I16) addr)) 3683 (atomic_store_impl (istore16_impl flags val addr (zero_offset)))) 3684 3685;; 32-bit atomic store. 3686(rule (lower (atomic_store flags val @ (value_type $I32) addr)) 3687 (atomic_store_impl (istore32_impl flags val addr (zero_offset)))) 3688 3689;; 64-bit atomic store. 3690(rule (lower (atomic_store flags val @ (value_type $I64) addr)) 3691 (atomic_store_impl (istore64_impl flags val addr (zero_offset)))) 3692 3693 3694;;;; Rules for `fence` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3695 3696;; Fence to ensure sequential consistency. 3697(rule (lower (fence)) 3698 (side_effect (fence_impl))) 3699 3700 3701;;;; Rules for `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3702 3703;; We want to optimize the typical use of `icmp` (generating an integer 0/1 3704;; result) followed by some user, like a `select` or a conditional branch. 3705;; Instead of first generating the integer result and later testing it again, 3706;; we want to sink the comparison to be performed at the site of use. 3707;; 3708;; To enable this, we provide generic helpers that return a `ProducesBool` 3709;; encapsulating the comparison in question, which can be used by all the 3710;; above scenarios. 3711;; 3712;; N.B. There are specific considerations when sinking a memory load into a 3713;; comparison. When emitting an `icmp` directly, this can of course be done 3714;; as usual. However, when we use the `ProducesBool` elsewhere, we need to 3715;; consider *three* instructions: the load, the `icmp`, and the final user 3716;; (e.g. a conditional branch). The only way to safely sink the load would 3717;; be to sink it direct into the final user, which is only possible if there 3718;; is no *other* user of the `icmp` result. This is not currently being 3719;; verified by the `SinkableInst` logic, so to be safe we do not perform this 3720;; optimization at all. 3721;; 3722;; The generic `icmp_val` helper therefore has a flag indicating whether 3723;; it is being invoked in a context where it is safe to sink memory loads 3724;; (e.g. when directly emitting an `icmp`), or whether it is not (e.g. when 3725;; sinking the `icmp` result into a conditional branch or select). 3726 3727;; Main `icmp` entry point. Generate a `ProducesBool` capturing the 3728;; integer comparison and immediately lower it to a 0/1 integer result. 3729;; In this case, it is safe to sink memory loads. 3730(rule -1 (lower (has_type (fits_in_64 ty) (icmp _ int_cc x y))) 3731 (lower_bool ty (icmp_val true int_cc x y))) 3732 3733 3734;; Return a `ProducesBool` to implement any integer comparison. 3735;; The first argument is a flag to indicate whether it is safe to sink 3736;; memory loads as discussed above. 3737(decl icmp_val (bool IntCC Value Value) ProducesBool) 3738 3739;; Dispatch for signed comparisons. 3740(rule -1 (icmp_val allow_mem int_cc @ (signed) x @ (value_type (fits_in_64 _)) y) 3741 (bool (icmps_val allow_mem x y) (intcc_as_cond int_cc))) 3742;; Dispatch for unsigned comparisons. 3743(rule -2 (icmp_val allow_mem int_cc @ (unsigned) x @ (value_type (fits_in_64 _)) y) 3744 (bool (icmpu_val allow_mem x y) (intcc_as_cond int_cc))) 3745 3746 3747;; Return a `ProducesBool` to implement signed integer comparisons. 3748(decl icmps_val (bool Value Value) ProducesFlags) 3749 3750;; Compare (signed) two registers. 3751(rule 0 (icmps_val _ x @ (value_type (fits_in_64 ty)) y) 3752 (icmps_reg (ty_ext32 ty) (put_in_reg_sext32 x) (put_in_reg_sext32 y))) 3753 3754;; Compare (signed) a register and a sign-extended register. 3755(rule 3 (icmps_val _ x @ (value_type (fits_in_64 ty)) (sext32_value y)) 3756 (icmps_reg_sext32 ty x y)) 3757 3758;; Compare (signed) a register and an immediate. 3759(rule 2 (icmps_val _ x @ (value_type (fits_in_64 ty)) (i16_from_value y)) 3760 (icmps_simm16 (ty_ext32 ty) (put_in_reg_sext32 x) y)) 3761(rule 1 (icmps_val _ x @ (value_type (fits_in_64 ty)) (i32_from_value y)) 3762 (icmps_simm32 (ty_ext32 ty) (put_in_reg_sext32 x) y)) 3763 3764;; Compare (signed) a register and memory (32/64-bit types). 3765(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_32_64 y)) 3766 (icmps_mem ty x (sink_load y))) 3767 3768;; Compare (signed) a register and memory (16-bit types). 3769(rule 5 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_16 y)) 3770 (icmps_mem_sext16 (ty_ext32 ty) (put_in_reg_sext32 x) (sink_load y))) 3771 3772;; Compare (signed) a register and sign-extended memory. 3773(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_sload16 y)) 3774 (icmps_mem_sext16 ty x (sink_sload16 y))) 3775(rule 4 (icmps_val true x @ (value_type (fits_in_64 ty)) (sinkable_sload32 y)) 3776 (icmps_mem_sext32 ty x (sink_sload32 y))) 3777 3778 3779;; Return a `ProducesBool` to implement unsigned integer comparisons. 3780(decl icmpu_val (bool Value Value) ProducesFlags) 3781 3782;; Compare (unsigned) two registers. 3783(rule (icmpu_val _ x @ (value_type (fits_in_64 ty)) y) 3784 (icmpu_reg (ty_ext32 ty) (put_in_reg_zext32 x) (put_in_reg_zext32 y))) 3785 3786;; Compare (unsigned) a register and a sign-extended register. 3787(rule 1 (icmpu_val _ x @ (value_type (fits_in_64 ty)) (zext32_value y)) 3788 (icmpu_reg_zext32 ty x y)) 3789 3790;; Compare (unsigned) a register and an immediate. 3791(rule 2 (icmpu_val _ x @ (value_type (fits_in_64 ty)) (u32_from_value y)) 3792 (icmpu_uimm32 (ty_ext32 ty) (put_in_reg_zext32 x) y)) 3793 3794;; Compare (unsigned) a register and memory (32/64-bit types). 3795(rule 4 (icmpu_val true x @ (value_type (fits_in_64 ty)) (sinkable_load_32_64 y)) 3796 (icmpu_mem ty x (sink_load y))) 3797 3798;; Compare (unsigned) a register and memory (16-bit types). 3799;; Note that the ISA only provides instructions with a PC-relative memory 3800;; address here, so we need to check whether the sinkable load matches this. 3801(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) 3802 (sinkable_load_16 ld)) 3803 (if-let y (load_sym ld)) 3804 (icmpu_mem_zext16 (ty_ext32 ty) (put_in_reg_zext32 x) (sink_load y))) 3805 3806;; Compare (unsigned) a register and zero-extended memory. 3807;; Note that the ISA only provides instructions with a PC-relative memory 3808;; address here, so we need to check whether the sinkable load matches this. 3809(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) 3810 (sinkable_uload16 ld)) 3811 (if-let y (uload16_sym ld)) 3812 (icmpu_mem_zext16 ty x (sink_uload16 y))) 3813(rule 3 (icmpu_val true x @ (value_type (fits_in_64 ty)) (sinkable_uload32 y)) 3814 (icmpu_mem_zext32 ty x (sink_uload32 y))) 3815 3816 3817;; Compare (signed) 128-bit integers on z17. 3818(rule 2 (icmp_val _ int_cc @ (signed) x @ (value_type (and (vxrs_ext3_enabled) (vr128_ty _))) y) 3819 (bool (vec_elt_icmps x y) (intcc_as_cond int_cc))) 3820 3821;; Compare (unsigned) 128-bit integers on z17. 3822(rule 1 (icmp_val _ int_cc @ (unsigned) x @ (value_type (and (vxrs_ext3_enabled) (vr128_ty _))) y) 3823 (bool (vec_elt_icmpu x y) (intcc_as_cond int_cc))) 3824 3825;; Compare 128-bit integers for equality pre-z17. 3826;; Implemented via element-wise comparison using the all-element true CC flag. 3827(rule (icmp_val _ (IntCC.Equal) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty _))) y) 3828 (bool (vec_cmpeqs $I64X2 x y) 3829 (floatcc_as_cond (FloatCC.Equal)))) 3830(rule (icmp_val _ (IntCC.NotEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty _))) y) 3831 (bool (vec_cmpeqs $I64X2 x y) 3832 (floatcc_as_cond (FloatCC.NotEqual)))) 3833 3834;; Compare (signed) 128-bit integers for relational inequality pre-z17. 3835;; Implemented via synthetic instruction using VECG and VCHLGS. 3836(rule (icmp_val _ (IntCC.SignedGreaterThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3837 (vec_int128_scmphi x y)) 3838(rule (icmp_val _ (IntCC.SignedLessThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3839 (vec_int128_scmphi y x)) 3840(rule (icmp_val _ (IntCC.SignedGreaterThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3841 (invert_bool (vec_int128_scmphi y x))) 3842(rule (icmp_val _ (IntCC.SignedLessThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3843 (invert_bool (vec_int128_scmphi x y))) 3844 3845;; Compare (unsigned) 128-bit integers for relational inequality pre-z17. 3846;; Implemented via synthetic instruction using VECLG and VCHLGS. 3847(rule (icmp_val _ (IntCC.UnsignedGreaterThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3848 (vec_int128_ucmphi x y)) 3849(rule (icmp_val _ (IntCC.UnsignedLessThan) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3850 (vec_int128_ucmphi y x)) 3851(rule (icmp_val _ (IntCC.UnsignedGreaterThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3852 (invert_bool (vec_int128_ucmphi y x))) 3853(rule (icmp_val _ (IntCC.UnsignedLessThanOrEqual) x @ (value_type (and (vxrs_ext3_disabled) (vr128_ty ty))) y) 3854 (invert_bool (vec_int128_ucmphi x y))) 3855 3856 3857;; Vector `icmp` produces a boolean vector. 3858;; We need to handle the various IntCC flags separately here. 3859 3860(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.Equal) x y))) 3861 (vec_cmpeq ty x y)) 3862(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.NotEqual) x y))) 3863 (vec_not ty (vec_cmpeq ty x y))) 3864(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedGreaterThan) x y))) 3865 (vec_cmph ty x y)) 3866(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedLessThanOrEqual) x y))) 3867 (vec_not ty (vec_cmph ty x y))) 3868(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedLessThan) x y))) 3869 (vec_cmph ty y x)) 3870(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.SignedGreaterThanOrEqual) x y))) 3871 (vec_not ty (vec_cmph ty y x))) 3872(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedGreaterThan) x y))) 3873 (vec_cmphl ty x y)) 3874(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedLessThanOrEqual) x y))) 3875 (vec_not ty (vec_cmphl ty x y))) 3876(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedLessThan) x y))) 3877 (vec_cmphl ty y x)) 3878(rule (lower (has_type (ty_vec128 ty) (icmp _ (IntCC.UnsignedGreaterThanOrEqual) x y))) 3879 (vec_not ty (vec_cmphl ty y x))) 3880 3881 3882;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3883 3884;; Main `fcmp` entry point. Generate a `ProducesBool` capturing the 3885;; integer comparison and immediately lower it to a 0/1 integer result. 3886(rule -1 (lower (has_type (fits_in_64 ty) (fcmp _ float_cc x y))) 3887 (lower_bool ty (fcmp_val float_cc x y))) 3888 3889;; Return a `ProducesBool` to implement any floating-point comparison. 3890(decl fcmp_val (FloatCC Value Value) ProducesBool) 3891(rule (fcmp_val float_cc x @ (value_type ty) y) 3892 (bool (fcmp_reg ty x y) 3893 (floatcc_as_cond float_cc))) 3894 3895;; Vector `fcmp` produces a boolean vector. 3896;; We need to handle the various FloatCC flags separately here. 3897 3898(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.Equal) x y))) 3899 (vec_fcmpeq ty x y)) 3900(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.NotEqual) x y))) 3901 (vec_not ty (vec_fcmpeq ty x y))) 3902(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.GreaterThan) x y))) 3903 (vec_fcmph ty x y)) 3904(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrLessThanOrEqual) x y))) 3905 (vec_not ty (vec_fcmph ty x y))) 3906(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.GreaterThanOrEqual) x y))) 3907 (vec_fcmphe ty x y)) 3908(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrLessThan) x y))) 3909 (vec_not ty (vec_fcmphe ty x y))) 3910(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.LessThan) x y))) 3911 (vec_fcmph ty y x)) 3912(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrGreaterThanOrEqual) x y))) 3913 (vec_not ty (vec_fcmph ty y x))) 3914(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.LessThanOrEqual) x y))) 3915 (vec_fcmphe ty y x)) 3916(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrGreaterThan) x y))) 3917 (vec_not ty (vec_fcmphe ty y x))) 3918(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.Ordered) x y))) 3919 (vec_or ty (vec_fcmphe ty x y) (vec_fcmphe ty y x))) 3920(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.Unordered) x y))) 3921 (vec_not_or ty (vec_fcmphe ty x y) (vec_fcmphe ty y x))) 3922(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.OrderedNotEqual) x y))) 3923 (vec_or ty (vec_fcmph ty x y) (vec_fcmph ty y x))) 3924(rule (lower (has_type (ty_vec128 ty) (fcmp _ (FloatCC.UnorderedOrEqual) x y))) 3925 (vec_not_or ty (vec_fcmph ty x y) (vec_fcmph ty y x))) 3926 3927 3928;;;; Rules for `vall_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3929 3930;; Main `vall_true` entry point. Generate a `ProducesBool` capturing the 3931;; comparison and immediately lower it to a 0/1 integer result. 3932(rule (lower (has_type (fits_in_64 ty) (vall_true _ x))) 3933 (lower_bool ty (vall_true_val x))) 3934 3935;; Return a `ProducesBool` to implement `vall_true`. 3936(decl vall_true_val (Value) ProducesBool) 3937(rule -1 (vall_true_val x @ (value_type ty)) 3938 (bool (vec_cmpeqs ty x (vec_imm ty 0)) 3939 (floatcc_as_cond (FloatCC.Unordered)))) 3940 3941;; Short-circuit `vall_true` on the result of a `icmp`. 3942(rule (vall_true_val (has_type ty (icmp _ (IntCC.Equal) x y))) 3943 (bool (vec_cmpeqs ty x y) 3944 (floatcc_as_cond (FloatCC.Equal)))) 3945(rule (vall_true_val (has_type ty (icmp _ (IntCC.NotEqual) x y))) 3946 (bool (vec_cmpeqs ty x y) 3947 (floatcc_as_cond (FloatCC.Unordered)))) 3948(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThan) x y))) 3949 (bool (vec_cmphs ty x y) 3950 (floatcc_as_cond (FloatCC.Equal)))) 3951(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedLessThanOrEqual) x y))) 3952 (bool (vec_cmphs ty x y) 3953 (floatcc_as_cond (FloatCC.Unordered)))) 3954(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedLessThan) x y))) 3955 (bool (vec_cmphs ty y x) 3956 (floatcc_as_cond (FloatCC.Equal)))) 3957(rule (vall_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThanOrEqual) x y))) 3958 (bool (vec_cmphs ty y x) 3959 (floatcc_as_cond (FloatCC.Unordered)))) 3960(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThan) x y))) 3961 (bool (vec_cmphls ty x y) 3962 (floatcc_as_cond (FloatCC.Equal)))) 3963(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThanOrEqual) x y))) 3964 (bool (vec_cmphls ty x y) 3965 (floatcc_as_cond (FloatCC.Unordered)))) 3966(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThan) x y))) 3967 (bool (vec_cmphls ty y x) 3968 (floatcc_as_cond (FloatCC.Equal)))) 3969(rule (vall_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThanOrEqual) x y))) 3970 (bool (vec_cmphls ty y x) 3971 (floatcc_as_cond (FloatCC.Unordered)))) 3972 3973;; Short-circuit `vall_true` on the result of a `fcmp` where possible. 3974(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.Equal) x y))) 3975 (bool (vec_fcmpeqs ty x y) 3976 (floatcc_as_cond (FloatCC.Equal)))) 3977(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.NotEqual) x y))) 3978 (bool (vec_fcmpeqs ty x y) 3979 (floatcc_as_cond (FloatCC.Unordered)))) 3980(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.GreaterThan) x y))) 3981 (bool (vec_fcmphs ty x y) 3982 (floatcc_as_cond (FloatCC.Equal)))) 3983(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThanOrEqual) x y))) 3984 (bool (vec_fcmphs ty x y) 3985 (floatcc_as_cond (FloatCC.Unordered)))) 3986(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.GreaterThanOrEqual) x y))) 3987 (bool (vec_fcmphes ty x y) 3988 (floatcc_as_cond (FloatCC.Equal)))) 3989(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThan) x y))) 3990 (bool (vec_fcmphes ty x y) 3991 (floatcc_as_cond (FloatCC.Unordered)))) 3992(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.LessThan) x y))) 3993 (bool (vec_fcmphs ty y x) 3994 (floatcc_as_cond (FloatCC.Equal)))) 3995(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThanOrEqual) x y))) 3996 (bool (vec_fcmphs ty y x) 3997 (floatcc_as_cond (FloatCC.Unordered)))) 3998(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.LessThanOrEqual) x y))) 3999 (bool (vec_fcmphes ty y x) 4000 (floatcc_as_cond (FloatCC.Equal)))) 4001(rule (vall_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThan) x y))) 4002 (bool (vec_fcmphes ty y x) 4003 (floatcc_as_cond (FloatCC.Unordered)))) 4004 4005 4006;;;; Rules for `vany_true` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4007 4008;; Main `vany_true` entry point. Generate a `ProducesBool` capturing the 4009;; comparison and immediately lower it to a 0/1 integer result. 4010(rule (lower (has_type (fits_in_64 ty) (vany_true _ x))) 4011 (lower_bool ty (vany_true_val x))) 4012 4013;; Return a `ProducesBool` to implement `vany_true`. 4014(decl vany_true_val (Value) ProducesBool) 4015(rule -1 (vany_true_val x @ (value_type ty)) 4016 (bool (vec_cmpeqs ty x (vec_imm ty 0)) 4017 (floatcc_as_cond (FloatCC.NotEqual)))) 4018 4019;; Short-circuit `vany_true` on the result of a `icmp`. 4020(rule (vany_true_val (has_type ty (icmp _ (IntCC.Equal) x y))) 4021 (bool (vec_cmpeqs ty x y) 4022 (floatcc_as_cond (FloatCC.Ordered)))) 4023(rule (vany_true_val (has_type ty (icmp _ (IntCC.NotEqual) x y))) 4024 (bool (vec_cmpeqs ty x y) 4025 (floatcc_as_cond (FloatCC.NotEqual)))) 4026(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThan) x y))) 4027 (bool (vec_cmphs ty x y) 4028 (floatcc_as_cond (FloatCC.Ordered)))) 4029(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedLessThanOrEqual) x y))) 4030 (bool (vec_cmphs ty x y) 4031 (floatcc_as_cond (FloatCC.NotEqual)))) 4032(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedLessThan) x y))) 4033 (bool (vec_cmphs ty y x) 4034 (floatcc_as_cond (FloatCC.Ordered)))) 4035(rule (vany_true_val (has_type ty (icmp _ (IntCC.SignedGreaterThanOrEqual) x y))) 4036 (bool (vec_cmphs ty y x) 4037 (floatcc_as_cond (FloatCC.NotEqual)))) 4038(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThan) x y))) 4039 (bool (vec_cmphls ty x y) 4040 (floatcc_as_cond (FloatCC.Ordered)))) 4041(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThanOrEqual) x y))) 4042 (bool (vec_cmphls ty x y) 4043 (floatcc_as_cond (FloatCC.NotEqual)))) 4044(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedLessThan) x y))) 4045 (bool (vec_cmphls ty y x) 4046 (floatcc_as_cond (FloatCC.Ordered)))) 4047(rule (vany_true_val (has_type ty (icmp _ (IntCC.UnsignedGreaterThanOrEqual) x y))) 4048 (bool (vec_cmphls ty y x) 4049 (floatcc_as_cond (FloatCC.NotEqual)))) 4050 4051;; Short-circuit `vany_true` on the result of a `fcmp` where possible. 4052(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.Equal) x y))) 4053 (bool (vec_fcmpeqs ty x y) 4054 (floatcc_as_cond (FloatCC.Ordered)))) 4055(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.NotEqual) x y))) 4056 (bool (vec_fcmpeqs ty x y) 4057 (floatcc_as_cond (FloatCC.NotEqual)))) 4058(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.GreaterThan) x y))) 4059 (bool (vec_fcmphs ty x y) 4060 (floatcc_as_cond (FloatCC.Ordered)))) 4061(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThanOrEqual) x y))) 4062 (bool (vec_fcmphs ty x y) 4063 (floatcc_as_cond (FloatCC.NotEqual)))) 4064(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.GreaterThanOrEqual) x y))) 4065 (bool (vec_fcmphes ty x y) 4066 (floatcc_as_cond (FloatCC.Ordered)))) 4067(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrLessThan) x y))) 4068 (bool (vec_fcmphes ty x y) 4069 (floatcc_as_cond (FloatCC.NotEqual)))) 4070(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.LessThan) x y))) 4071 (bool (vec_fcmphs ty y x) 4072 (floatcc_as_cond (FloatCC.Ordered)))) 4073(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThanOrEqual) x y))) 4074 (bool (vec_fcmphs ty y x) 4075 (floatcc_as_cond (FloatCC.NotEqual)))) 4076(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.LessThanOrEqual) x y))) 4077 (bool (vec_fcmphes ty y x) 4078 (floatcc_as_cond (FloatCC.Ordered)))) 4079(rule (vany_true_val (has_type ty (fcmp _ (FloatCC.UnorderedOrGreaterThan) x y))) 4080 (bool (vec_fcmphes ty y x) 4081 (floatcc_as_cond (FloatCC.NotEqual)))) 4082 4083 4084;;;; Rules for `vhigh_bits` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4085 4086(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 8 16)))) 4087 (if-let (LaneOrder.LittleEndian) (lane_order)) 4088 (let ((mask Reg (vec_imm $I8X16 (imm8x16 0 8 16 24 32 40 48 56 4089 64 72 80 88 96 104 112 120)))) 4090 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4091(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 8 16)))) 4092 (if-let (LaneOrder.BigEndian) (lane_order)) 4093 (let ((mask Reg (vec_imm $I8X16 (imm8x16 120 112 104 96 88 80 72 64 4094 56 48 40 32 24 16 8 0)))) 4095 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4096 4097(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 16 8)))) 4098 (if-let (LaneOrder.LittleEndian) (lane_order)) 4099 (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 4100 0 16 32 48 64 80 96 112)))) 4101 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4102(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 16 8)))) 4103 (if-let (LaneOrder.BigEndian) (lane_order)) 4104 (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 4105 112 96 80 64 48 32 16 0)))) 4106 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4107 4108(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 32 4)))) 4109 (if-let (LaneOrder.LittleEndian) (lane_order)) 4110 (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 4111 128 128 128 128 0 32 64 96)))) 4112 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4113(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 32 4)))) 4114 (if-let (LaneOrder.BigEndian) (lane_order)) 4115 (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 4116 128 128 128 128 96 64 32 0)))) 4117 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4118 4119(rule (lower (vhigh_bits _ x @ (value_type (multi_lane 64 2)))) 4120 (if-let (LaneOrder.LittleEndian) (lane_order)) 4121 (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 4122 128 128 128 128 128 128 0 64)))) 4123 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4124(rule 1 (lower (vhigh_bits _ x @ (value_type (multi_lane 64 2)))) 4125 (if-let (LaneOrder.BigEndian) (lane_order)) 4126 (let ((mask Reg (vec_imm $I8X16 (imm8x16 128 128 128 128 128 128 128 128 4127 128 128 128 128 128 128 64 0)))) 4128 (vec_extract_lane $I64X2 (vec_bitpermute x mask) 0 (zero_reg)))) 4129 4130 4131;;;; Rules for `select` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4132 4133;; Return a `ProducesBool` to capture the fact that the input value is nonzero. 4134;; In the common case where that input is the result of an `icmp` or `fcmp` 4135;; instruction, directly use that compare. Note that it is not safe to sink 4136;; memory loads here, see the `icmp` comment. 4137(decl value_nonzero (Value) ProducesBool) 4138(rule (value_nonzero (icmp _ int_cc x y)) (icmp_val false int_cc x y)) 4139(rule (value_nonzero (fcmp _ float_cc x y)) (fcmp_val float_cc x y)) 4140(rule -1 (value_nonzero val @ (value_type (gpr32_ty ty))) 4141 (bool (icmps_simm16 $I32 (put_in_reg_sext32 val) 0) 4142 (intcc_as_cond (IntCC.NotEqual)))) 4143(rule -2 (value_nonzero val @ (value_type (gpr64_ty ty))) 4144 (bool (icmps_simm16 $I64 (put_in_reg val) 0) 4145 (intcc_as_cond (IntCC.NotEqual)))) 4146(rule -3 (value_nonzero val @ (value_type (vr128_ty ty))) 4147 (bool (vec_cmpeqs $I64X2 val (vec_imm $I64X2 0)) 4148 (floatcc_as_cond (FloatCC.NotEqual)))) 4149 4150;; Main `select` entry point. Lower the `value_nonzero` result. 4151(rule (lower (has_type ty (select _ val_cond val_true val_false))) 4152 (select_bool_reg ty (value_nonzero val_cond) 4153 (put_in_reg val_true) (put_in_reg val_false))) 4154 4155;; Special-case some float-selection instructions for min/max 4156(rule 1 (lower (has_type (ty_scalar_float ty) (select _ (maybe_uextend (fcmp _ (FloatCC.LessThan) x y)) x y))) 4157 (fmin_pseudo_reg ty y x)) 4158(rule 2 (lower (has_type (ty_scalar_float ty) (select _ (maybe_uextend (fcmp _ (FloatCC.LessThan) y x)) x y))) 4159 (fmax_pseudo_reg ty y x)) 4160 4161 4162;;;; Rules for `select_spectre_guard` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4163 4164;; We need to guarantee a conditional move instruction. But on this platform 4165;; this is already the best way to implement select in general, so the 4166;; implementation of `select_spectre_guard` is identical to `select`. 4167(rule (lower (has_type ty (select_spectre_guard _ 4168 val_cond val_true val_false))) 4169 (select_bool_reg ty (value_nonzero val_cond) 4170 (put_in_reg val_true) (put_in_reg val_false))) 4171 4172 4173;;;; Rules for `jump` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4174 4175;; Unconditional branch. The target is found as first (and only) element in 4176;; the list of the current block's branch targets passed as `targets`. 4177(rule (lower_branch (jump _) (single_target label)) 4178 (emit_side_effect (jump_impl label))) 4179 4180 4181;;;; Rules for `br_table` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4182 4183;; Jump table. `targets` contains the default target followed by the 4184;; list of branch targets per index value. 4185(rule (lower_branch (br_table val_idx _) (jump_table_targets default targets)) 4186 (let ((idx Reg (put_in_reg_zext64 val_idx)) 4187 ;; Bounds-check the index and create a ProducesBool that 4188 ;; denotes the "default target" condition. 4189 (cond ProducesBool 4190 (bool (icmpu_uimm32 $I64 idx (jump_table_size targets)) 4191 (intcc_as_cond (IntCC.UnsignedGreaterThanOrEqual))))) 4192 ;; Scale the index by the element size, and then emit the 4193 ;; compound instruction that does: 4194 ;; 4195 ;; [cond branch to default] 4196 ;; larl %r1, <jt-base> 4197 ;; agf %r1, 0(%r1, %rScaledIndex) 4198 ;; br %r1 4199 ;; [jt entries] 4200 ;; 4201 ;; This must be *one* instruction in the vcode because 4202 ;; we cannot allow regalloc to insert any spills/fills 4203 ;; in the middle of the sequence; otherwise, the LARL's 4204 ;; PC-rel offset to the jumptable would be incorrect. 4205 ;; (The alternative is to introduce a relocation pass 4206 ;; for inlined jumptables, which is much worse, IMHO.) 4207 (let ((shifted_idx Reg (lshl_imm $I64 idx 2))) 4208 (emit_side_effect (jt_sequence_default_bool shifted_idx default cond targets))))) 4209 4210 4211;;;; Rules for `brif` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4212 4213;; Two-way conditional branch on nonzero. `targets` contains: 4214;; - element 0: target if the condition is true (i.e. value is nonzero) 4215;; - element 1: target if the condition is false (i.e. value is zero) 4216(rule (lower_branch (brif val_cond _ _) (two_targets then else)) 4217 (emit_side_effect (cond_br_bool (value_nonzero val_cond) then else))) 4218 4219 4220;;;; Rules for `trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4221 4222(rule (lower (trap trap_code)) 4223 (side_effect (trap_impl trap_code))) 4224 4225 4226;;;; Rules for `trapz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4227 4228(rule (lower (trapz val trap_code)) 4229 (side_effect (trap_if_bool (invert_bool (value_nonzero val)) trap_code))) 4230 4231 4232;;;; Rules for `trapnz` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4233 4234(rule (lower (trapnz val trap_code)) 4235 (side_effect (trap_if_bool (value_nonzero val) trap_code))) 4236 4237 4238;;;; Rules for `debugtrap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4239 4240(rule (lower (debugtrap)) 4241 (side_effect (debugtrap_impl))) 4242 4243;;;; Rules for `uadd_overflow_trap` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4244 4245;; UaddOverflowTrap is implemented via a ADD LOGICAL instruction, which sets the 4246;; the condition code as follows: 4247;; 0 Result zero; no carry 4248;; 1 Result not zero; no carry 4249;; 2 Result zero; carry 4250;; 3 Result not zero; carry 4251;; This means "carry" corresponds to condition code 2 or 3, i.e. 4252;; a condition mask of 2 | 1. 4253;; 4254;; As this does not match any of the encodings used with a normal integer 4255;; comparison, this cannot be represented by any IntCC value. We need to 4256;; remap the IntCC::UnsignedGreaterThan value that we have here as result 4257;; of the unsigned_add_overflow_condition call to the correct mask. 4258 4259(rule 0 (lower (has_type (fits_in_64 ty) (uadd_overflow_trap _ x y tc))) 4260 (with_flags 4261 (add_logical_reg_with_flags_paired ty x y) 4262 (trap_if_impl (mask_as_cond 3) tc))) 4263 4264;; Add a register an a zero-extended register. 4265(rule 4 (lower (has_type (fits_in_64 ty) 4266 (uadd_overflow_trap _ x (zext32_value y) tc))) 4267 (with_flags 4268 (add_logical_reg_zext32_with_flags_paired ty x y) 4269 (trap_if_impl (mask_as_cond 3) tc))) 4270(rule 8 (lower (has_type (fits_in_64 ty) 4271 (uadd_overflow_trap _ (zext32_value x) y tc))) 4272 (with_flags 4273 (add_logical_reg_zext32_with_flags_paired ty y x) 4274 (trap_if_impl (mask_as_cond 3) tc))) 4275 4276;; Add a register and an immediate 4277(rule 3 (lower (has_type (fits_in_64 ty) 4278 (uadd_overflow_trap _ x (u32_from_value y) tc))) 4279 (with_flags 4280 (add_logical_zimm32_with_flags_paired ty x y) 4281 (trap_if_impl (mask_as_cond 3) tc))) 4282(rule 7 (lower (has_type (fits_in_64 ty) 4283 (uadd_overflow_trap _ (u32_from_value x) y tc))) 4284 (with_flags 4285 (add_logical_zimm32_with_flags_paired ty y x) 4286 (trap_if_impl (mask_as_cond 3) tc))) 4287 4288;; Add a register and memory (32/64-bit types). 4289(rule 2 (lower (has_type (fits_in_64 ty) 4290 (uadd_overflow_trap _ x (sinkable_load_32_64 y) tc))) 4291 (with_flags 4292 (add_logical_mem_with_flags_paired ty x (sink_load y)) 4293 (trap_if_impl (mask_as_cond 3) tc))) 4294(rule 6 (lower (has_type (fits_in_64 ty) 4295 (uadd_overflow_trap _ (sinkable_load_32_64 x) y tc))) 4296 (with_flags 4297 (add_logical_mem_with_flags_paired ty y (sink_load x)) 4298 (trap_if_impl (mask_as_cond 3) tc))) 4299 4300;; Add a register and zero-extended memory. 4301(rule 1 (lower (has_type (fits_in_64 ty) 4302 (uadd_overflow_trap _ x (sinkable_uload32 y) tc))) 4303 (with_flags 4304 (add_logical_mem_zext32_with_flags_paired ty x (sink_uload32 y)) 4305 (trap_if_impl (mask_as_cond 3) tc))) 4306(rule 5 (lower (has_type (fits_in_64 ty) 4307 (uadd_overflow_trap _ (sinkable_uload32 x) y tc))) 4308 (with_flags 4309 (add_logical_mem_zext32_with_flags_paired ty y (sink_uload32 x)) 4310 (trap_if_impl (mask_as_cond 3) tc))) 4311 4312;;;; Rules for `uadd_overflow` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4313 4314(rule 0 (lower (has_type (ty_32_or_64 ty) (uadd_overflow _ x y))) 4315 (let ((sum Reg (add_reg ty x y)) 4316 (overflow Reg 4317 (lower_bool $I8 4318 (bool (icmpu_reg ty sum x) (intcc_as_cond (IntCC.UnsignedLessThan)))))) 4319 (output_pair sum overflow))) 4320 4321;;;; Rules for `return` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4322 4323(rule (lower (return args)) 4324 (lower_return args)) 4325 4326 4327;;;; Rules for `call` and `call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4328 4329;; Direct call to an in-range function. 4330(rule 1 (lower (call (func_ref_data sig_ref name (RelocDistance.Near) patchable) args)) 4331 (let ((output ValueRegsVec (gen_call_output sig_ref)) 4332 (abi Sig (abi_sig sig_ref)) 4333 (_ Unit (abi_emit_call_adjust_stack abi)) 4334 (uses CallArgList (gen_call_args abi (abi_prepare_args abi args))) 4335 (defs CallRetList (gen_call_rets abi output)) 4336 (info BoxCallInfo (gen_call_info abi name uses defs (try_call_none) patchable)) 4337 (_ Unit (emit_side_effect (call_impl (writable_link_reg) info)))) 4338 output)) 4339 4340;; Direct call to an out-of-range function (implicitly via pointer). 4341(rule (lower (call (func_ref_data sig_ref name _ false) args)) 4342 (let ((output ValueRegsVec (gen_call_output sig_ref)) 4343 (abi Sig (abi_sig sig_ref)) 4344 (_ Unit (abi_emit_call_adjust_stack abi)) 4345 (uses CallArgList (gen_call_args abi (abi_prepare_args abi args))) 4346 (defs CallRetList (gen_call_rets abi output)) 4347 (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0))) 4348 (info BoxCallInfo (gen_call_info abi target uses defs (try_call_none) false)) 4349 (_ Unit (emit_side_effect (call_impl (writable_link_reg) info)))) 4350 output)) 4351 4352;; Indirect call. 4353(rule (lower (call_indirect sig_ref ptr args)) 4354 (let ((output ValueRegsVec (gen_call_output sig_ref)) 4355 (abi Sig (abi_sig sig_ref)) 4356 (target Reg (put_in_reg ptr)) 4357 (_ Unit (abi_emit_call_adjust_stack abi)) 4358 (uses CallArgList (gen_call_args abi (abi_prepare_args abi args))) 4359 (defs CallRetList (gen_call_rets abi output)) 4360 (info BoxCallInfo (gen_call_info abi target uses defs (try_call_none) false)) 4361 (_ Unit (emit_side_effect (call_impl (writable_link_reg) info)))) 4362 output)) 4363 4364;;;; Rules for `return_call` and `return_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;; 4365 4366;; Direct tail call to an in-range function. 4367(rule 1 (lower (return_call (func_ref_data sig_ref name (RelocDistance.Near) false) args)) 4368 (let ((abi Sig (abi_sig sig_ref)) 4369 (_ Unit (abi_emit_return_call_adjust_stack abi)) 4370 (uses CallArgList (gen_return_call_args abi (abi_prepare_args abi args))) 4371 (info BoxReturnCallInfo (gen_return_call_info abi name uses))) 4372 (side_effect (return_call_impl info)))) 4373 4374;; Direct tail call to an out-of-range function (implicitly via pointer). 4375(rule (lower (return_call (func_ref_data sig_ref name _ false) args)) 4376 (let ((abi Sig (abi_sig sig_ref)) 4377 (_ Unit (abi_emit_return_call_adjust_stack abi)) 4378 (uses CallArgList (gen_return_call_args abi (abi_prepare_args abi args))) 4379 (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0))) 4380 (info BoxReturnCallInfo (gen_return_call_info abi target uses))) 4381 (side_effect (return_call_impl info)))) 4382 4383;; Indirect tail call. 4384(rule (lower (return_call_indirect sig_ref ptr args)) 4385 (let ((abi Sig (abi_sig sig_ref)) 4386 (target Reg (put_in_reg ptr)) 4387 (_ Unit (abi_emit_return_call_adjust_stack abi)) 4388 (uses CallArgList (gen_return_call_args abi (abi_prepare_args abi args))) 4389 (info BoxReturnCallInfo (gen_return_call_info abi target uses))) 4390 (side_effect (return_call_impl info)))) 4391 4392 4393;;;; Rules for `try_call` and `try_call_indirect` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4394 4395;; Direct call to an in-range function. 4396(rule 1 (lower_branch (try_call (func_ref_data sig_ref name (RelocDistance.Near) patchable) args et) targets) 4397 (let ((abi Sig (abi_sig sig_ref)) 4398 (trycall OptionTryCallInfo (try_call_info et targets)) 4399 (_ Unit (abi_emit_call_adjust_stack abi)) 4400 (uses CallArgList (gen_call_args abi (abi_prepare_args abi args))) 4401 (defs CallRetList (gen_try_call_rets abi)) 4402 (info BoxCallInfo (gen_call_info abi name uses defs trycall patchable))) 4403 (emit_side_effect (call_impl (writable_link_reg) info)))) 4404 4405;; Direct call to an out-of-range function (implicitly via pointer). 4406(rule (lower_branch (try_call (func_ref_data sig_ref name _ false) args et) targets) 4407 (let ((abi Sig (abi_sig sig_ref)) 4408 (trycall OptionTryCallInfo (try_call_info et targets)) 4409 (_ Unit (abi_emit_call_adjust_stack abi)) 4410 (uses CallArgList (gen_call_args abi (abi_prepare_args abi args))) 4411 (defs CallRetList (gen_try_call_rets abi)) 4412 (target Reg (load_symbol_reloc (SymbolReloc.Absolute name 0))) 4413 (info BoxCallInfo (gen_call_info abi target uses defs trycall false))) 4414 (emit_side_effect (call_impl (writable_link_reg) info)))) 4415 4416;; Indirect call. 4417(rule (lower_branch (try_call_indirect ptr args et) targets) 4418 (if-let (exception_sig sig_ref) et) 4419 (let ((abi Sig (abi_sig sig_ref)) 4420 (trycall OptionTryCallInfo (try_call_info et targets)) 4421 (target Reg (put_in_reg ptr)) 4422 (_ Unit (abi_emit_call_adjust_stack abi)) 4423 (uses CallArgList (gen_call_args abi (abi_prepare_args abi args))) 4424 (defs CallRetList (gen_try_call_rets abi)) 4425 (info BoxCallInfo (gen_call_info abi target uses defs trycall false))) 4426 (emit_side_effect (call_impl (writable_link_reg) info)))) 4427 4428 4429;;;; Rules for `get_{frame,stack}_pointer` and `get_return_address` ;;;;;;;;;;;; 4430 4431(rule (lower (get_stack_pointer _)) 4432 (sp)) 4433 4434(rule (lower (get_frame_pointer _)) 4435 (load64 (memarg_frame_pointer_offset))) 4436 4437(rule (lower (get_return_address _)) 4438 (load64 (memarg_return_address_offset))) 4439 4440;; Rules for `get_exception_handler_address` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4441 4442(rule (lower (get_exception_handler_address _ (u64_from_imm64 idx) block)) 4443 (let ((succ_label MachLabel (block_exn_successor_label block idx))) 4444 (s390x_label_address succ_label))) 4445 4446;; Rules for `sequence_point` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4447 4448(rule (lower (sequence_point)) 4449 (side_effect 4450 (s390x_sequence_point))) 4451