|
208 | 208 | (let ((_ Unit (emit_side_effect (vcmp (FpuSize.F64) (put_in_reg a) (put_in_reg b))))) |
209 | 209 | (csetv (cond_from_floatcc cc)))) |
210 | 210 |
|
| 211 | +;; `one` (ordered and not-equal) and `ueq` (unordered or equal) can't be |
| 212 | +;; expressed as a single ARM condition, so they get a two-condition sequence. |
| 213 | +(rule 1 (lower (fcmp _ (FloatCC.OrderedNotEqual) a @ (value_type $F32) b)) |
| 214 | + (gen_fcmp_one (FpuSize.F32) (put_in_reg a) (put_in_reg b))) |
| 215 | +(rule 1 (lower (fcmp _ (FloatCC.OrderedNotEqual) a @ (value_type $F64) b)) |
| 216 | + (gen_fcmp_one (FpuSize.F64) (put_in_reg a) (put_in_reg b))) |
| 217 | +(rule 1 (lower (fcmp _ (FloatCC.UnorderedOrEqual) a @ (value_type $F32) b)) |
| 218 | + (gen_fcmp_ueq (FpuSize.F32) (put_in_reg a) (put_in_reg b))) |
| 219 | +(rule 1 (lower (fcmp _ (FloatCC.UnorderedOrEqual) a @ (value_type $F64) b)) |
| 220 | + (gen_fcmp_ueq (FpuSize.F64) (put_in_reg a) (put_in_reg b))) |
| 221 | + |
211 | 222 | ;; f32 <-> f64. |
212 | 223 | (rule (lower (fpromote $F64 x)) |
213 | 224 | (vcvt_ff true (put_in_reg x))) |
|
266 | 277 | (mov_to_fpu64 (put_in_regs x))) |
267 | 278 |
|
268 | 279 | ;;;; Divides (only when hardware `sdiv`/`udiv` is available) ;;;;;;;;;;;;;;;;;;; |
269 | | -;; NOTE: trap-on-zero / INT_MIN overflow checks are not yet emitted. |
| 280 | +;; `gen_sdiv`/`gen_udiv` emit the trap-on-zero check (and, for `sdiv`, the |
| 281 | +;; `INT_MIN / -1` overflow check) before the divide. |
270 | 282 |
|
271 | 283 | (rule (lower (sdiv $I32 x y)) |
272 | 284 | (if-let true (use_idiv)) |
273 | | - (sdiv_reg (put_in_reg x) (put_in_reg y))) |
| 285 | + (gen_sdiv (put_in_reg x) (put_in_reg y))) |
274 | 286 | (rule (lower (udiv $I32 x y)) |
275 | 287 | (if-let true (use_idiv)) |
276 | | - (udiv_reg (put_in_reg x) (put_in_reg y))) |
| 288 | + (gen_udiv (put_in_reg x) (put_in_reg y))) |
277 | 289 |
|
278 | 290 | ;;;; Counting / byte-swap / bit-reverse ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
279 | 291 |
|
|
304 | 316 |
|
305 | 317 | ;;;; `icmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
306 | 318 |
|
307 | | -;; 32-bit comparison producing a 0/1 boolean. |
| 319 | +;; 32-bit comparison producing a 0/1 boolean. `emit_icmp_cmp` widens narrow |
| 320 | +;; (i8/i16) operands to 32 bits per the comparison's signedness before the |
| 321 | +;; `cmp`, since Cranelift leaves the high bits of narrow values undefined. |
308 | 322 | (rule (lower (icmp _ cc a @ (value_type (fits_in_32 _)) b)) |
309 | | - (let ((_ Unit (emit_side_effect (cmp_rr (put_in_reg a) (put_in_reg b))))) |
310 | | - (csetv (cond_from_intcc cc)))) |
| 323 | + (csetv (emit_icmp_cmp cc a b))) |
311 | 324 |
|
312 | 325 | ;; 64-bit comparison producing a 0/1 boolean. |
313 | 326 | (rule 4 (lower (icmp _ cc a @ (value_type $I64) b)) |
|
317 | 330 |
|
318 | 331 | ;; Fuse an `icmp` condition into the compare that precedes the select. |
319 | 332 | (rule 1 (lower (select (fits_in_32 _) (icmp _ cc x @ (value_type (fits_in_32 _)) y) a b)) |
320 | | - (let ((_ Unit (emit_side_effect (cmp_rr (put_in_reg x) (put_in_reg y))))) |
321 | | - (csel (cond_from_intcc cc) (put_in_reg a) (put_in_reg b)))) |
| 333 | + (let ((cond Cond (emit_icmp_cmp cc x y))) |
| 334 | + (csel cond (put_in_reg a) (put_in_reg b)))) |
322 | 335 |
|
323 | 336 | ;; Generic select: branch on whether the condition value is non-zero. |
324 | 337 | (rule (lower (select (fits_in_32 _) c a b)) |
325 | 338 | (let ((_ Unit (emit_side_effect (cmp_imm (put_in_reg c) 0)))) |
326 | 339 | (csel (Cond.Ne) (put_in_reg a) (put_in_reg b)))) |
327 | 340 |
|
| 341 | +;; 64-bit select: pick each half of the pair. The operands are materialized |
| 342 | +;; before the compare so nothing clobbers the flags in between. |
| 343 | +(rule 4 (lower (select $I64 c a b)) |
| 344 | + (let ((av ValueRegs (put_in_regs a)) |
| 345 | + (bv ValueRegs (put_in_regs b)) |
| 346 | + (_ Unit (emit_side_effect (cmp_imm (put_in_reg c) 0)))) |
| 347 | + (value_regs (csel (Cond.Ne) (vr_lo av) (vr_lo bv)) |
| 348 | + (csel (Cond.Ne) (vr_hi av) (vr_hi bv))))) |
| 349 | + |
328 | 350 | ;;;; Shifts: `ishl` / `ushr` / `sshr` / `rotr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
329 | 351 |
|
330 | 352 | (rule 1 (lower (ishl $I32 x (iconst _ (u64_from_imm64 n)))) |
|
349 | 371 |
|
350 | 372 | ;;;; Loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
351 | 373 |
|
| 374 | +;; A plain `load` reads exactly `sizeof(ty)` bytes; narrow types zero-extend |
| 375 | +;; into the 32-bit result register. |
| 376 | +(rule 1 (lower (load $I8 flags addr offset)) |
| 377 | + (arm_load (amode addr offset) (LoadKind.UByte))) |
| 378 | +(rule 1 (lower (load $I16 flags addr offset)) |
| 379 | + (arm_load (amode addr offset) (LoadKind.UHalf))) |
352 | 380 | (rule (lower (load (fits_in_32 _) flags addr offset)) |
353 | 381 | (arm_load (amode addr offset) (LoadKind.Word))) |
354 | 382 |
|
|
363 | 391 |
|
364 | 392 | ;;;; Stores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
365 | 393 |
|
| 394 | +;; A plain `store` writes exactly `sizeof(ty)` bytes. |
| 395 | +(rule 1 (lower (store flags val @ (value_type $I8) addr offset)) |
| 396 | + (arm_store (put_in_reg val) (amode addr offset) (StoreKind.Byte))) |
| 397 | +(rule 1 (lower (store flags val @ (value_type $I16) addr offset)) |
| 398 | + (arm_store (put_in_reg val) (amode addr offset) (StoreKind.Half))) |
366 | 399 | (rule (lower (store flags val @ (value_type (fits_in_32 _)) addr offset)) |
367 | 400 | (arm_store (put_in_reg val) (amode addr offset) (StoreKind.Word))) |
368 | 401 |
|
|
431 | 464 |
|
432 | 465 | ;; Fuse a 32-bit `icmp` feeding a `brif` into a compare plus conditional branch. |
433 | 466 | (rule 1 (lower_branch (brif (icmp _ cc a @ (value_type (fits_in_32 _)) b) _ _) (two_targets taken not_taken)) |
434 | | - (emit_side_effect |
435 | | - (side_effect_concat |
436 | | - (cmp_rr (put_in_reg a) (put_in_reg b)) |
437 | | - (cond_br (cond_from_intcc cc) taken not_taken)))) |
| 467 | + (emit_side_effect (cond_br (emit_icmp_cmp cc a b) taken not_taken))) |
438 | 468 |
|
439 | 469 | ;; Fuse a 64-bit `icmp` feeding a `brif`. |
440 | 470 | (rule 2 (lower_branch (brif (icmp _ cc a @ (value_type $I64) b) _ _) (two_targets taken not_taken)) |
441 | 471 | (emit_side_effect |
442 | 472 | (cond_br (lower_icmp_i64 cc (put_in_regs a) (put_in_regs b)) taken not_taken))) |
443 | 473 |
|
| 474 | +;; `one`/`ueq` feeding a `brif`: materialize the two-condition boolean, then |
| 475 | +;; branch on whether it is non-zero (priority 2 beats the generic fused rule, |
| 476 | +;; whose single-condition mapping can't represent these). |
| 477 | +(rule 2 (lower_branch (brif (fcmp _ (FloatCC.OrderedNotEqual) a @ (value_type $F32) b) _ _) (two_targets taken not_taken)) |
| 478 | + (emit_side_effect (side_effect_concat |
| 479 | + (cmp_imm (gen_fcmp_one (FpuSize.F32) (put_in_reg a) (put_in_reg b)) 0) |
| 480 | + (cond_br (Cond.Ne) taken not_taken)))) |
| 481 | +(rule 2 (lower_branch (brif (fcmp _ (FloatCC.OrderedNotEqual) a @ (value_type $F64) b) _ _) (two_targets taken not_taken)) |
| 482 | + (emit_side_effect (side_effect_concat |
| 483 | + (cmp_imm (gen_fcmp_one (FpuSize.F64) (put_in_reg a) (put_in_reg b)) 0) |
| 484 | + (cond_br (Cond.Ne) taken not_taken)))) |
| 485 | +(rule 2 (lower_branch (brif (fcmp _ (FloatCC.UnorderedOrEqual) a @ (value_type $F32) b) _ _) (two_targets taken not_taken)) |
| 486 | + (emit_side_effect (side_effect_concat |
| 487 | + (cmp_imm (gen_fcmp_ueq (FpuSize.F32) (put_in_reg a) (put_in_reg b)) 0) |
| 488 | + (cond_br (Cond.Ne) taken not_taken)))) |
| 489 | +(rule 2 (lower_branch (brif (fcmp _ (FloatCC.UnorderedOrEqual) a @ (value_type $F64) b) _ _) (two_targets taken not_taken)) |
| 490 | + (emit_side_effect (side_effect_concat |
| 491 | + (cmp_imm (gen_fcmp_ueq (FpuSize.F64) (put_in_reg a) (put_in_reg b)) 0) |
| 492 | + (cond_br (Cond.Ne) taken not_taken)))) |
| 493 | + |
444 | 494 | ;; Fuse an `fcmp` feeding a `brif`. |
445 | 495 | (rule 1 (lower_branch (brif (fcmp _ cc a @ (value_type $F32) b) _ _) (two_targets taken not_taken)) |
446 | 496 | (emit_side_effect |
|
0 commit comments