Skip to content

Commit 8ec3ff3

Browse files
authored
Cranelift: ISLE recursion check (#12474)
* add decl rec attribute * implement recursion check * add required `req` attributes * document the `RecursionError` variant * add required `req` attributes to pully ISLE rules * add `rec` to isle example * use dfs for cycle detection * document the `rec` attribute * recursion safety comments * "is permitted to be recursive" * fix documentation of RecursionError variant
1 parent 8510bac commit 8ec3ff3

23 files changed

Lines changed: 310 additions & 40 deletions

cranelift/codegen/src/isa/aarch64/inst.isle

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2474,7 +2474,9 @@
24742474

24752475
;; Helper for emitting `MInst.FpuCSel16` / `MInst.FpuCSel32` / `MInst.FpuCSel64`
24762476
;; instructions.
2477-
(decl fpu_csel (Type Cond Reg Reg) ConsumesFlags)
2477+
;;
2478+
;; Recursion: may recurse once to downgrade from F16 to F32 when FP16 is not enabled.
2479+
(decl rec fpu_csel (Type Cond Reg Reg) ConsumesFlags)
24782480
(rule (fpu_csel $F16 cond if_true if_false)
24792481
(fpu_csel $F32 cond if_true if_false))
24802482

@@ -2524,9 +2526,11 @@
25242526
dst))
25252527

25262528
;; Helper for emitting `MInst.MovToFpu` instructions.
2529+
;;
2530+
;; Recursion: may recurse once to downgrade from F16 to F32 when FP16 is not enabled.
25272531
(spec (mov_to_fpu x s)
25282532
(provide (= result (zero_ext 64 (conv_to s x)))))
2529-
(decl mov_to_fpu (Reg ScalarSize) Reg)
2533+
(decl rec mov_to_fpu (Reg ScalarSize) Reg)
25302534
(rule (mov_to_fpu x size)
25312535
(let ((dst WritableReg (temp_writable_reg $I8X16))
25322536
(_ Unit (emit (MInst.MovToFpu dst x size))))
@@ -4017,7 +4021,9 @@
40174021
;; Note that we must make sure that all bits outside the lowest 16 are set to 0
40184022
;; because this function is also used to load wider constants (that have zeros
40194023
;; in their most significant bits).
4020-
(decl constant_f16 (u16) Reg)
4024+
;;
4025+
;; Recursion: forms cycle with `constant_f32`. Invokes 32-bit case when FP16 is not supported.
4026+
(decl rec constant_f16 (u16) Reg)
40214027
(rule 3 (constant_f16 n)
40224028
(if-let false (use_fp16))
40234029
(constant_f32 n))
@@ -4036,7 +4042,9 @@
40364042
;; Note that we must make sure that all bits outside the lowest 32 are set to 0
40374043
;; because this function is also used to load wider constants (that have zeros
40384044
;; in their most significant bits).
4039-
(decl constant_f32 (u32) Reg)
4045+
;;
4046+
;; Recursion: forms cycle with `constant_f16`. Invokes 16-bit case when FP16 is supported.
4047+
(decl rec constant_f32 (u32) Reg)
40404048
(rule 3 (constant_f32 0)
40414049
(vec_dup_imm (asimd_mov_mod_imm_zero (ScalarSize.Size32))
40424050
false
@@ -4099,7 +4107,9 @@
40994107
;;
41004108
;; The 64-bit input here only uses the low bits for the lane size in
41014109
;; `VectorSize` and all other bits are ignored.
4102-
(decl splat_const (u64 VectorSize) Reg)
4110+
;;
4111+
;; Recursion: bounded since the recursive call always reduces lane size.
4112+
(decl rec splat_const (u64 VectorSize) Reg)
41034113

41044114
;; If the splat'd constant can itself be reduced in size then attempt to do so
41054115
;; as it will make it easier to create the immediates in the instructions below.
@@ -4956,7 +4966,8 @@
49564966
(MInst.CSel dst (Cond.Eq) tmp1 tmp2)
49574967
(value_reg dst))))
49584968

4959-
(decl lower_bmask (Type Type ValueRegs) ValueRegs)
4969+
; Recursion: bounded since recursive calls reduce type width (128-bit to 64-bit).
4970+
(decl rec lower_bmask (Type Type ValueRegs) ValueRegs)
49604971

49614972

49624973
;; For conversions that exactly fit a register, we can use csetm.

cranelift/codegen/src/isa/pulley_shared/lower.isle

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
;; needs to handle situations such as when the `Value` is 64-bits an explicit
1212
;; comparison must be made. Additionally if `Value` is smaller than 32-bits
1313
;; then it must be sign-extended up to at least 32 bits.
14-
(decl lower_cond (Value) Cond)
14+
;;
15+
;; Recursion: peeling away `uextend` operations must be bounded since each
16+
;; extend must be on a strictly smaller type.
17+
(decl rec lower_cond (Value) Cond)
1518
(rule 0 (lower_cond val @ (value_type (fits_in_32 _))) (Cond.If32 (zext32 val)))
1619
(rule 1 (lower_cond val @ (value_type $I64))
1720
(Cond.IfXneq64I32 val 0))
@@ -737,7 +740,9 @@
737740
(rule (lower (icmp cc a b @ (value_type (ty_int ty))))
738741
(lower_icmp ty cc a b))
739742

740-
(decl lower_icmp (Type IntCC Value Value) XReg)
743+
; Recursion: bounded since only recursive rules swap condition code order from
744+
; greater into less, which can only apply once.
745+
(decl rec lower_icmp (Type IntCC Value Value) XReg)
741746

742747
(rule (lower_icmp $I64 (IntCC.Equal) a b)
743748
(pulley_xeq64 a b))
@@ -846,7 +851,9 @@
846851
(rule 1 (lower (icmp cc a @ (value_type (ty_vec128 ty)) b))
847852
(lower_vcmp ty cc a b))
848853

849-
(decl lower_vcmp (Type IntCC Value Value) VReg)
854+
; Recursion: bounded since only recursive rules swap condition code order from
855+
; greater into less, which can only apply once.
856+
(decl rec lower_vcmp (Type IntCC Value Value) VReg)
850857
(rule (lower_vcmp $I8X16 (IntCC.Equal) a b) (pulley_veq8x16 a b))
851858
(rule (lower_vcmp $I8X16 (IntCC.NotEqual) a b) (pulley_vneq8x16 a b))
852859
(rule (lower_vcmp $I8X16 (IntCC.SignedLessThan) a b) (pulley_vslt8x16 a b))
@@ -890,7 +897,9 @@
890897
(rule 1 (lower (fcmp cc a b @ (value_type (ty_vec128 ty))))
891898
(lower_vfcmp ty cc a b))
892899

893-
(decl lower_fcmp (Type FloatCC Value Value) XReg)
900+
; Recursion: bounded since recursive rules only implement certain condition
901+
; codes in terms of a smaller canonical set, to which recursive rules don't apply.
902+
(decl rec lower_fcmp (Type FloatCC Value Value) XReg)
894903

895904
(rule (lower_fcmp $F32 (FloatCC.Equal) a b) (pulley_feq32 a b))
896905
(rule (lower_fcmp $F64 (FloatCC.Equal) a b) (pulley_feq64 a b))
@@ -921,7 +930,9 @@
921930
(if-let true (floatcc_unordered cc))
922931
(pulley_xbxor32_s8 (lower_fcmp ty (floatcc_complement cc) a b) 1))
923932

924-
(decl lower_vfcmp (Type FloatCC Value Value) VReg)
933+
; Recursion: bounded since recursive rules only implement certain condition
934+
; codes in terms of a smaller canonical set, to which recursive rules don't apply.
935+
(decl rec lower_vfcmp (Type FloatCC Value Value) VReg)
925936

926937
(rule (lower_vfcmp $F32X4 (FloatCC.Equal) a b) (pulley_veqf32x4 a b))
927938
(rule (lower_vfcmp $F64X2 (FloatCC.Equal) a b) (pulley_veqf64x2 a b))

cranelift/codegen/src/isa/riscv64/inst.isle

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,7 +1873,10 @@
18731873
;; Immediate Loading rules
18741874
;; TODO: Loading the zero reg directly causes a bunch of regalloc errors, we should look into it.
18751875
;; TODO: Load floats using `fld` instead of `ld`
1876-
(decl imm (Type u64) Reg)
1876+
;;
1877+
;; Recursion: bounded since either float cases are reduced to integers, or the
1878+
;; shift case reduces to a smaller constant.
1879+
(decl rec imm (Type u64) Reg)
18771880

18781881
;; Special-case 0.0 for floats to use the `(zero_reg)` directly.
18791882
;; See #7162 for why this doesn't fall out of the rules below.
@@ -2470,7 +2473,10 @@
24702473
(rule 0 (load_op_reg_type _) $I64)
24712474

24722475
;; Helper constructor to build a load instruction.
2473-
(decl gen_load (AMode LoadOP MemFlags) Reg)
2476+
;;
2477+
;; Recursion: recursive rule can only match once, since it matches on
2478+
;; `LoadOP.Flh` and emits `LoadOP.Lh`.
2479+
(decl rec gen_load (AMode LoadOP MemFlags) Reg)
24742480
(rule (gen_load amode op flags)
24752481
(let ((dst WritableReg (temp_writable_reg (load_op_reg_type op)))
24762482
(_ Unit (emit (MInst.Load dst op flags amode))))
@@ -2661,7 +2667,9 @@
26612667
(decl gen_stack_addr (StackSlot Offset32) Reg)
26622668
(extern constructor gen_stack_addr gen_stack_addr)
26632669

2664-
(decl gen_select_xreg (IntegerCompare XReg XReg) XReg)
2670+
; Recursion: bounded by only matching when one of the inputs is a zero register,
2671+
; but not both.
2672+
(decl rec gen_select_xreg (IntegerCompare XReg XReg) XReg)
26652673

26662674
(rule 6 (gen_select_xreg (int_compare_decompose cc x y) x y)
26672675
(if-let (IntCC.UnsignedLessThan) (intcc_without_eq cc))
@@ -2994,7 +3002,10 @@
29943002

29953003
;; Generates a bitcast instruction.
29963004
;; Args are: src, src_ty, dst_ty
2997-
(decl gen_bitcast (Reg Type Type) Reg)
3005+
;;
3006+
;; Recursion: only recursive rule matches on vec-to-float, and emits vec-to-int
3007+
;; and int-to-float bitcasts, so this can only recurse once.
3008+
(decl rec gen_bitcast (Reg Type Type) Reg)
29983009

29993010
(rule 9 (gen_bitcast r (ty_supported_float_size $F16) (ty_supported_vec _)) (if-let false (has_zvfh)) (rv_vfmv_sf r (vstate_from_type $F32)))
30003011
(rule 8 (gen_bitcast r (ty_supported_vec ty) (ty_supported_float_size $F16)) (if-let false (has_zvfh)) (gen_bitcast (gen_bitcast r ty $I16) $I16 $F16))
@@ -3214,7 +3225,9 @@
32143225
(convert FloatCompare IntegerCompare float_to_int_compare)
32153226

32163227
;; Compare two floating point numbers and return a zero/non-zero result.
3217-
(decl fcmp_to_float_compare (FloatCC Type FReg FReg) FloatCompare)
3228+
;;
3229+
;; Recursion: at most once to convert unordered comparisons into ordered comparisons.
3230+
(decl rec fcmp_to_float_compare (FloatCC Type FReg FReg) FloatCompare)
32183231

32193232
;; Direct codegen for unordered comparisons is not that efficient, so invert
32203233
;; the comparison to get an ordered comparison and generate that. Then invert

cranelift/codegen/src/isa/riscv64/inst_vector.isle

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,9 @@
15011501

15021502
;;;; Multi-Instruction Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15031503

1504-
(decl gen_extractlane (Type VReg u8) Reg)
1504+
; Recursion: recursive rules reduce to the index zero case, which are handled
1505+
; with higher-priority rules.
1506+
(decl rec gen_extractlane (Type VReg u8) Reg)
15051507

15061508
;; When extracting lane 0 for floats, we can use `vfmv.f.s` directly.
15071509
(rule 3 (gen_extractlane (ty_vec_fits_in_register ty) src 0)
@@ -1731,7 +1733,10 @@
17311733

17321734

17331735
;; Builds a vector mask corresponding to the FloatCC operation.
1734-
(decl gen_fcmp_mask (Type FloatCC Value Value) VReg)
1736+
;;
1737+
;; Recursion: recursive rules implement some condition codes in terms of a
1738+
;; smaller set of primtives, which recursive rules would not apply to twice.
1739+
(decl rec gen_fcmp_mask (Type FloatCC Value Value) VReg)
17351740

17361741
;; FloatCC.Equal
17371742

cranelift/codegen/src/isa/riscv64/lower.isle

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,9 @@
10441044

10451045
;; Constructs a sequence of instructions that reverse all bits in `x` up to
10461046
;; the given type width.
1047-
(decl gen_bitrev (Type XReg) XReg)
1047+
;;
1048+
;; Recursion: at most once to implement 16- and 32-bit cases in terms of 64-bit.
1049+
(decl rec gen_bitrev (Type XReg) XReg)
10481050

10491051
(rule 0 (gen_bitrev (ty_16_or_32 (ty_int ty)) x)
10501052
(if-let shift_amt (u64_to_imm12 (u64_wrapping_sub 64 (ty_bits ty))))
@@ -1069,7 +1071,9 @@
10691071

10701072
;; Builds a sequence of instructions that swaps the bytes in `x` up to the given
10711073
;; type width.
1072-
(decl gen_bswap (Type XReg) XReg)
1074+
;;
1075+
;; Recursion: bounded depth since each step halves the type width.
1076+
(decl rec gen_bswap (Type XReg) XReg)
10731077

10741078
;; This is only here to make the rule below work. bswap.i8 isn't valid
10751079
(rule 0 (gen_bswap $I8 x) x)
@@ -2263,7 +2267,8 @@
22632267
(rule 0 (lower (icmp cc x @ (value_type (fits_in_64 ty)) y))
22642268
(lower_icmp cc x y))
22652269

2266-
(decl lower_icmp (IntCC Value Value) XReg)
2270+
; Recursion: at most once to implement >= in terms of <.
2271+
(decl rec lower_icmp (IntCC Value Value) XReg)
22672272
(rule 0 (lower_icmp cc x y)
22682273
(lower_int_compare (icmp_to_int_compare cc x y)))
22692274

@@ -2352,7 +2357,8 @@
23522357
(rule 20 (lower (icmp cc x @ (value_type $I128) y))
23532358
(lower_icmp_i128 cc x y))
23542359

2355-
(decl lower_icmp_i128 (IntCC ValueRegs ValueRegs) XReg)
2360+
; Recursion: at most once to implement some conditions in terms of a smaller primitive set.
2361+
(decl rec lower_icmp_i128 (IntCC ValueRegs ValueRegs) XReg)
23562362
(rule 0 (lower_icmp_i128 (IntCC.Equal) x y)
23572363
(let ((lo XReg (rv_xor (value_regs_get x 0) (value_regs_get y 0)))
23582364
(hi XReg (rv_xor (value_regs_get x 1) (value_regs_get y 1))))

cranelift/codegen/src/isa/s390x/inst.isle

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,7 +2982,7 @@
29822982
;; Helpers for generating immediate values ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29832983

29842984
;; Allocate a temporary register, initialized with an immediate.
2985-
(decl imm (Type u64) Reg)
2985+
(decl rec imm (Type u64) Reg)
29862986

29872987
;; 16-bit (or smaller) result type, any value
29882988
(rule 7 (imm (fits_in_16 (ty_int ty)) n)
@@ -3084,7 +3084,9 @@
30843084
(vec_load ty (memarg_const (emit_u128_be_const n))))
30853085

30863086
;; Variant with replicated immediate.
3087-
(decl vec_imm_splat (Type u64) Reg)
3087+
;;
3088+
;; Recursion: bounded since recursive rules reduce number of lanes.
3089+
(decl rec vec_imm_splat (Type u64) Reg)
30883090
(rule 1 (vec_imm_splat (ty_vec128 ty) 0)
30893091
(vec_imm_byte_mask ty 0))
30903092
(rule 2 (vec_imm_splat ty @ (multi_lane 8 _) n)
@@ -3387,7 +3389,9 @@
33873389
(rule (lower_bool $I8 cond) (select_bool_imm $I8 cond 1 0))
33883390

33893391
;; Lower a boolean condition to the values -1/0.
3390-
(decl lower_bool_to_mask (Type ProducesBool) Reg)
3392+
;;
3393+
;; Recursion: at most once to reduce 128-bit to 64-bit case.
3394+
(decl rec lower_bool_to_mask (Type ProducesBool) Reg)
33913395
(rule 0 (lower_bool_to_mask (fits_in_64 ty) producer)
33923396
(select_bool_imm ty producer -1 0))
33933397

cranelift/codegen/src/isa/x64/inst.isle

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,9 @@
19291929
;;
19301930
;; Note that if `Type` is less than 64-bits then the upper bits of the `imm`
19311931
;; argument will be set to zero and lost.
1932-
(decl imm (Type u64) Reg)
1932+
;;
1933+
;; Recursion: at most once to implement floats with integer bit patterns.
1934+
(decl rec imm (Type u64) Reg)
19331935

19341936
;; Base case: integers of up to at most 32-bits.
19351937
;;
@@ -3346,7 +3348,9 @@
33463348
(ConsumesFlags.ConsumesFlagsSideEffect (MInst.JmpCondOr cc1 cc2 taken not_taken)))
33473349

33483350
;; Conditional jump based on a `CondResult`
3349-
(decl jmp_cond_result (CondResult MachLabel MachLabel) SideEffectNoResult)
3351+
;;
3352+
;; Recursion: at most to convert `And` into `Or`.
3353+
(decl rec jmp_cond_result (CondResult MachLabel MachLabel) SideEffectNoResult)
33503354
(rule (jmp_cond_result (CondResult.CC producer cc) taken not_taken)
33513355
(with_flags_side_effect producer (jmp_cond cc taken not_taken)))
33523356
(rule (jmp_cond_result cond @ (CondResult.And _ _ _) taken not_taken)
@@ -3549,7 +3553,8 @@
35493553
(rule 5 (emit_cmp (IntCC.NotEqual) a (u64_from_iconst 0)) (is_nonzero a))
35503554
(rule 6 (emit_cmp (IntCC.NotEqual) (u64_from_iconst 0) a) (is_nonzero a))
35513555

3552-
(decl emit_cmp_i128 (CC Gpr Gpr Gpr Gpr) CondResult)
3556+
; Recursion: at most one to eliminate "or equal" cases.
3557+
(decl rec emit_cmp_i128 (CC Gpr Gpr Gpr Gpr) CondResult)
35533558
;; Eliminate cases which compare something "or equal" by swapping arguments.
35543559
(rule 2 (emit_cmp_i128 (CC.NLE) a_hi a_lo b_hi b_lo)
35553560
(emit_cmp_i128 (CC.L) b_hi b_lo a_hi a_lo))

cranelift/codegen/src/isa/x64/lower.isle

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,9 @@
628628

629629
;; Get the address of the mask to use when fixing up the lanes that weren't
630630
;; correctly generated by the 16x8 shift.
631-
(decl ishl_i8x16_mask (RegMemImm) SyntheticAmode)
631+
;;
632+
;; Recursion: at most once to convert memory case into register case.
633+
(decl rec ishl_i8x16_mask (RegMemImm) SyntheticAmode)
632634

633635
;; When the shift amount is known, we can statically (i.e. at compile time)
634636
;; determine the mask to use and only emit that.
@@ -732,7 +734,9 @@
732734

733735
;; Get the address of the mask to use when fixing up the lanes that weren't
734736
;; correctly generated by the 16x8 shift.
735-
(decl ushr_i8x16_mask (RegMemImm) SyntheticAmode)
737+
;;
738+
;; Recursion: at most once to convert memory case into register case.
739+
(decl rec ushr_i8x16_mask (RegMemImm) SyntheticAmode)
736740

737741
;; When the shift amount is known, we can statically (i.e. at compile time)
738742
;; determine the mask to use and only emit that.
@@ -1422,7 +1426,8 @@
14221426

14231427
;;;; Rules for `bmask` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14241428

1425-
(decl lower_bmask (Type Type ValueRegs) ValueRegs)
1429+
; Recursion: reduces 128-bit cases to 64-bit.
1430+
(decl rec lower_bmask (Type Type ValueRegs) ValueRegs)
14261431

14271432
;; Values that fit in a register
14281433
;;
@@ -2178,7 +2183,8 @@
21782183

21792184
(rule (lower (select cond x y)) (lower_select (is_nonzero_cmp cond) x y))
21802185

2181-
(decl lower_select (CondResult Value Value) InstOutput)
2186+
; Recursion: at most once to swap the And case for an Or.
2187+
(decl rec lower_select (CondResult Value Value) InstOutput)
21822188
(rule 0 (lower_select cond a @ (value_type (ty_int (fits_in_64 ty))) b)
21832189
(lower_select_gpr ty cond a b))
21842190
(rule 1 (lower_select cond a @ (value_type (is_xmm_type ty)) b)
@@ -4276,7 +4282,9 @@
42764282

42774283
;; Emits either a `round{ss,sd,ps,pd}` instruction, as appropriate, or generates
42784284
;; the appropriate libcall and sequence to call that.
4279-
(decl x64_round (Type RegMem RoundImm) Xmm)
4285+
;;
4286+
;; Recursion: at most once to convert memory case into register case.
4287+
(decl rec x64_round (Type RegMem RoundImm) Xmm)
42804288
(rule 1 (x64_round $F32 a imm)
42814289
(if-let true (has_sse41))
42824290
(x64_roundss a imm))
@@ -4683,7 +4691,9 @@
46834691
;; performant thing in the world so this is primarily here for completeness
46844692
;; of lowerings on all x86 cpus but if rules are ideally gated on the presence
46854693
;; of SSSE3 to use the `pshufb` instruction itself.
4686-
(decl lower_pshufb (Xmm RegMem) Xmm)
4694+
;;
4695+
;; Recursion: at most once to implement the memory load case.
4696+
(decl rec lower_pshufb (Xmm RegMem) Xmm)
46874697
(rule 1 (lower_pshufb src mask)
46884698
(if-let true (has_ssse3))
46894699
(x64_pshufb src mask))

cranelift/codegen/src/prelude_opt.isle

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@
131131
;; so that `iconst.i8 255` will give you a `-1_i64`.
132132
;; When constructing, the rule will fail if the value cannot be represented in
133133
;; the target type. If it fits, it'll be masked accordingly in the constant.
134-
(decl iconst_s (Type i64) Value)
134+
;;
135+
;; Recursion: may recurse at most once to reduce reduce 128-bit to 64-bit.
136+
(decl rec iconst_s (Type i64) Value)
135137
(extractor (iconst_s ty c) (inst_data_value_tupled (iconst_sextend_etor ty c)))
136138
(rule 0 (iconst_s ty c)
137139
(if-let c_masked (u64_and (i64_cast_unsigned c)
@@ -147,7 +149,9 @@
147149
;; so that `iconst.i8 255` will give you a `255_u64`.
148150
;; When constructing, the rule will fail if the value cannot be represented in
149151
;; the target type.
150-
(decl iconst_u (Type u64) Value)
152+
;;
153+
;; Recursion: may recurse at most once to reduce reduce 128-bit to 64-bit.
154+
(decl rec iconst_u (Type u64) Value)
151155
(extractor (iconst_u ty c) (iconst ty (u64_from_imm64 c)))
152156
(rule 0 (iconst_u ty c)
153157
(if-let true (u64_lt_eq c (ty_umax ty)))

0 commit comments

Comments
 (0)