diff --git a/cranelift/codegen/src/egraph.rs b/cranelift/codegen/src/egraph.rs index 69870d556e..121155008b 100644 --- a/cranelift/codegen/src/egraph.rs +++ b/cranelift/codegen/src/egraph.rs @@ -229,48 +229,46 @@ where // values produced as equivalents to this value. trace!("Calling into ISLE with original value {}", orig_value); isle_ctx.ctx.stats.rewrite_rule_invoked += 1; - let optimized_values = + let mut optimized_values = crate::opts::generated_code::constructor_simplify(&mut isle_ctx, orig_value); // Create a union of all new values with the original (or // maybe just one new value marked as "subsuming" the // original, if present.) let mut union_value = orig_value; - if let Some(mut optimized_values) = optimized_values { - while let Some(optimized_value) = optimized_values.next(&mut isle_ctx) { - trace!( - "Returned from ISLE for {}, got {:?}", - orig_value, - optimized_value - ); - if optimized_value == orig_value { - trace!(" -> same as orig value; skipping"); - continue; - } - if isle_ctx.ctx.subsume_values.contains(&optimized_value) { - // Merge in the unionfind so canonicalization - // still works, but take *only* the subsuming - // value, and break now. - isle_ctx.ctx.eclasses.union(optimized_value, union_value); - union_value = optimized_value; - break; - } - - let old_union_value = union_value; - union_value = isle_ctx - .ctx - .func - .dfg - .union(old_union_value, optimized_value); - isle_ctx.ctx.stats.union += 1; - trace!(" -> union: now {}", union_value); - isle_ctx.ctx.eclasses.add(union_value); - isle_ctx - .ctx - .eclasses - .union(old_union_value, optimized_value); - isle_ctx.ctx.eclasses.union(old_union_value, union_value); + while let Some(optimized_value) = optimized_values.next(&mut isle_ctx) { + trace!( + "Returned from ISLE for {}, got {:?}", + orig_value, + optimized_value + ); + if optimized_value == orig_value { + trace!(" -> same as orig value; skipping"); + continue; } + if isle_ctx.ctx.subsume_values.contains(&optimized_value) { + // Merge in the unionfind so canonicalization + // still works, but take *only* the subsuming + // value, and break now. + isle_ctx.ctx.eclasses.union(optimized_value, union_value); + union_value = optimized_value; + break; + } + + let old_union_value = union_value; + union_value = isle_ctx + .ctx + .func + .dfg + .union(old_union_value, optimized_value); + isle_ctx.ctx.stats.union += 1; + trace!(" -> union: now {}", union_value); + isle_ctx.ctx.eclasses.add(union_value); + isle_ctx + .ctx + .eclasses + .union(old_union_value, optimized_value); + isle_ctx.ctx.eclasses.union(old_union_value, union_value); } isle_ctx.ctx.rewrite_depth -= 1; diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index b61ca529c9..4e281a9b09 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -1599,7 +1599,7 @@ )) ;; Extractors for target features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(decl pure sign_return_address_disabled () Unit) +(decl pure partial sign_return_address_disabled () Unit) (extern constructor sign_return_address_disabled sign_return_address_disabled) (decl use_lse () Inst) @@ -1607,13 +1607,13 @@ ;; Extractor helpers for various immmediate constants ;;;;;;;;;;;;;;;;;;;;;;;;;; -(decl pure imm_logic_from_u64 (Type u64) ImmLogic) +(decl pure partial imm_logic_from_u64 (Type u64) ImmLogic) (extern constructor imm_logic_from_u64 imm_logic_from_u64) -(decl pure imm_logic_from_imm64 (Type Imm64) ImmLogic) +(decl pure partial imm_logic_from_imm64 (Type Imm64) ImmLogic) (extern constructor imm_logic_from_imm64 imm_logic_from_imm64) -(decl pure imm_shift_from_imm64 (Type Imm64) ImmShift) +(decl pure partial imm_shift_from_imm64 (Type Imm64) ImmShift) (extern constructor imm_shift_from_imm64 imm_shift_from_imm64) (decl imm_shift_from_u8 (u8) ImmShift) @@ -1672,13 +1672,13 @@ (decl imm12_from_negated_u64 (Imm12) u64) (extern extractor imm12_from_negated_u64 imm12_from_negated_u64) -(decl pure lshr_from_u64 (Type u64) ShiftOpAndAmt) +(decl pure partial lshr_from_u64 (Type u64) ShiftOpAndAmt) (extern constructor lshr_from_u64 lshr_from_u64) -(decl pure lshl_from_imm64 (Type Imm64) ShiftOpAndAmt) +(decl pure partial lshl_from_imm64 (Type Imm64) ShiftOpAndAmt) (extern constructor lshl_from_imm64 lshl_from_imm64) -(decl pure lshl_from_u64 (Type u64) ShiftOpAndAmt) +(decl pure partial lshl_from_u64 (Type u64) ShiftOpAndAmt) (extern constructor lshl_from_u64 lshl_from_u64) (decl integral_ty (Type) Type) @@ -1687,10 +1687,10 @@ (decl valid_atomic_transaction (Type) Type) (extern extractor valid_atomic_transaction valid_atomic_transaction) -(decl pure is_zero_simm9 (SImm9) Unit) +(decl pure partial is_zero_simm9 (SImm9) Unit) (extern constructor is_zero_simm9 is_zero_simm9) -(decl pure is_zero_uimm12 (UImm12Scaled) Unit) +(decl pure partial is_zero_uimm12 (UImm12Scaled) Unit) (extern constructor is_zero_uimm12 is_zero_uimm12) ;; Helper to go directly from a `Value`, when it's an `iconst`, to an `Imm12`. @@ -3614,8 +3614,9 @@ ;; csetm res, ne (rule 3 (lower_bmask out_ty (fits_in_16 in_ty) val) - (let ((mask_bits ImmLogic (imm_logic_from_u64 $I32 (ty_mask in_ty))) - (masked Reg (and_imm $I32 (value_regs_get val 0) mask_bits))) + ; This if-let can't fail due to ty_mask always producing 8/16 consecutive 1s. + (if-let mask_bits (imm_logic_from_u64 $I32 (ty_mask in_ty))) + (let ((masked Reg (and_imm $I32 (value_regs_get val 0) mask_bits))) (lower_bmask out_ty $I32 masked))) ;; Exceptional `lower_icmp_into_flags` rules. diff --git a/cranelift/codegen/src/isa/aarch64/lower.isle b/cranelift/codegen/src/isa/aarch64/lower.isle index 572a2f1352..2bb40d1694 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.isle +++ b/cranelift/codegen/src/isa/aarch64/lower.isle @@ -2,7 +2,7 @@ ;; The main lowering constructor term: takes a clif `Inst` and returns the ;; register(s) within which the lowered instruction's result values live. -(decl lower (Inst) InstOutput) +(decl partial lower (Inst) InstOutput) ;; Variant of the main lowering constructor term, which receives an ;; additional argument (a vector of branch targets to be used) for @@ -12,7 +12,7 @@ ;; blocks while we lower, the fallthrough in the new order is not (necessarily) ;; the same as the fallthrough in CLIF. So, we use the explicitly-provided ;; target. -(decl lower_branch (Inst VecMachLabel) InstOutput) +(decl partial lower_branch (Inst VecMachLabel) InstOutput) ;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/codegen/src/isa/riscv64/inst.isle b/cranelift/codegen/src/isa/riscv64/inst.isle index 83e4e7c7d4..20461db7c3 100644 --- a/cranelift/codegen/src/isa/riscv64/inst.isle +++ b/cranelift/codegen/src/isa/riscv64/inst.isle @@ -839,9 +839,9 @@ ;; extend int if need. (decl ext_int_if_need (bool ValueRegs Type) ValueRegs) -;;; for I8 and I16 ... +;;; for I8, I16, and I32 ... (rule -1 - (ext_int_if_need signed val (fits_in_32 ty)) + (ext_int_if_need signed val ty) (gen_extend val signed (ty_bits ty) 64)) ;;; otherwise this is a I64 or I128 ;;; no need to extend. @@ -1870,7 +1870,7 @@ (decl vec_label_get (VecMachLabel u8) MachLabel ) (extern constructor vec_label_get vec_label_get) -(decl lower_branch (Inst VecMachLabel) InstOutput) +(decl partial lower_branch (Inst VecMachLabel) InstOutput) (rule (lower_branch (jump _ _) targets ) (side_effect (SideEffectNoResult.Inst (gen_jump (vec_label_get targets 0))))) diff --git a/cranelift/codegen/src/isa/riscv64/lower.isle b/cranelift/codegen/src/isa/riscv64/lower.isle index c30087525f..af89d9bbe3 100644 --- a/cranelift/codegen/src/isa/riscv64/lower.isle +++ b/cranelift/codegen/src/isa/riscv64/lower.isle @@ -2,7 +2,7 @@ ;; The main lowering constructor term: takes a clif `Inst` and returns the ;; register(s) within which the lowered instruction's result values live. -(decl lower (Inst) InstOutput) +(decl partial lower (Inst) InstOutput) ;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/codegen/src/isa/riscv64/lower/isle.rs b/cranelift/codegen/src/isa/riscv64/lower/isle.rs index c559b98ae4..2b3df718da 100644 --- a/cranelift/codegen/src/isa/riscv64/lower/isle.rs +++ b/cranelift/codegen/src/isa/riscv64/lower/isle.rs @@ -121,7 +121,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> targets: &VecMachLabel, ty: Type, ) -> InstOutput { - let test = generated_code::constructor_lower_icmp(self, cc, a, b, ty).unwrap(); + let test = generated_code::constructor_lower_icmp(self, cc, a, b, ty); self.emit(&MInst::CondBr { taken: BranchTarget::Label(targets[0]), not_taken: BranchTarget::Label(targets[1]), @@ -308,11 +308,11 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> ValueRegs::two(shamt, len_sub_shamt) } - fn has_b(&mut self) -> Option { - Some(self.isa_flags.has_b()) + fn has_b(&mut self) -> bool { + self.isa_flags.has_b() } - fn has_zbkb(&mut self) -> Option { - Some(self.isa_flags.has_zbkb()) + fn has_zbkb(&mut self) -> bool { + self.isa_flags.has_zbkb() } fn valueregs_2_reg(&mut self, val: Value) -> Reg { diff --git a/cranelift/codegen/src/isa/s390x/inst.isle b/cranelift/codegen/src/isa/s390x/inst.isle index db76ff60ab..f218a1610c 100644 --- a/cranelift/codegen/src/isa/s390x/inst.isle +++ b/cranelift/codegen/src/isa/s390x/inst.isle @@ -1537,15 +1537,15 @@ ;; Detect specific integer values -(decl pure i64_nonequal (i64 i64) i64) +(decl pure partial i64_nonequal (i64 i64) i64) (extern constructor i64_nonequal i64_nonequal) -(decl pure i64_nonzero (i64) i64) +(decl pure partial i64_nonzero (i64) i64) (rule (i64_nonzero x) (if (i64_nonequal x 0)) x) -(decl pure i64_not_neg1 (i64) i64) +(decl pure partial i64_not_neg1 (i64) i64) (rule (i64_not_neg1 x) (if (i64_nonequal x -1)) x) @@ -1799,11 +1799,11 @@ ;; Form the sum of two offset values, and check that the result is ;; a valid `MemArg::Symbol` offset (i.e. is even and fits into i32). -(decl pure memarg_symbol_offset_sum (i64 i64) i32) +(decl pure partial memarg_symbol_offset_sum (i64 i64) i32) (extern constructor memarg_symbol_offset_sum memarg_symbol_offset_sum) ;; Likewise, but just check a single offset value. -(decl pure memarg_symbol_offset (i64) i32) +(decl pure partial memarg_symbol_offset (i64) i32) (rule (memarg_symbol_offset x) (memarg_symbol_offset_sum x 0)) @@ -1837,7 +1837,7 @@ ;; Test whether a `load` address will be lowered to a `MemArg::Symbol`. -(decl pure load_sym (Inst) Inst) +(decl pure partial load_sym (Inst) Inst) (rule (load_sym inst) (if-let (load _ (symbol_value (symbol_value_data _ (reloc_distance_near) sym_offset)) (i64_from_offset load_offset)) @@ -1845,7 +1845,7 @@ (if (memarg_symbol_offset_sum sym_offset load_offset)) inst) -(decl pure uload16_sym (Inst) Inst) +(decl pure partial uload16_sym (Inst) Inst) (rule (uload16_sym inst) (if-let (uload16 _ (symbol_value (symbol_value_data _ (reloc_distance_near) sym_offset)) (i64_from_offset load_offset)) @@ -2752,7 +2752,7 @@ ;; Similarly, because we cannot allocate temp registers, if an instruction ;; requires matching source and destination registers, this needs to be handled ;; by the user. Another helper to verify that constraint. -(decl pure same_reg (WritableReg Reg) Reg) +(decl pure partial same_reg (WritableReg Reg) Reg) (extern constructor same_reg same_reg) ;; Push a `MInst.AluRRR` instruction to a sequence. diff --git a/cranelift/codegen/src/isa/s390x/lower.isle b/cranelift/codegen/src/isa/s390x/lower.isle index 0e4ec27dec..a3bb10701b 100644 --- a/cranelift/codegen/src/isa/s390x/lower.isle +++ b/cranelift/codegen/src/isa/s390x/lower.isle @@ -2,12 +2,12 @@ ;; The main lowering constructor term: takes a clif `Inst` and returns the ;; register(s) within which the lowered instruction's result values live. -(decl lower (Inst) InstOutput) +(decl partial lower (Inst) InstOutput) ;; A variant of the main lowering constructor term, used for branches. ;; The only difference is that it gets an extra argument holding a vector ;; of branch targets to be used. -(decl lower_branch (Inst VecMachLabel) InstOutput) +(decl partial lower_branch (Inst VecMachLabel) InstOutput) ;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/codegen/src/isa/s390x/lower/isle.rs b/cranelift/codegen/src/isa/s390x/lower/isle.rs index 3f142aa0a1..2c263b7dca 100644 --- a/cranelift/codegen/src/isa/s390x/lower/isle.rs +++ b/cranelift/codegen/src/isa/s390x/lower/isle.rs @@ -526,15 +526,13 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> } #[inline] - fn lane_order(&mut self) -> Option { - Some(lane_order_for_call_conv( - self.lower_ctx.abi().call_conv(self.lower_ctx.sigs()), - )) + fn lane_order(&mut self) -> LaneOrder { + lane_order_for_call_conv(self.lower_ctx.abi().call_conv(self.lower_ctx.sigs())) } #[inline] fn be_lane_idx(&mut self, ty: Type, idx: u8) -> u8 { - match self.lane_order().unwrap() { + match self.lane_order() { LaneOrder::LittleEndian => ty.lane_count() as u8 - 1 - idx, LaneOrder::BigEndian => idx, } @@ -542,7 +540,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> #[inline] fn be_vec_const(&mut self, ty: Type, n: u128) -> u128 { - match self.lane_order().unwrap() { + match self.lane_order() { LaneOrder::LittleEndian => n, LaneOrder::BigEndian => { let lane_count = ty.lane_count(); @@ -568,7 +566,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> #[inline] fn shuffle_mask_from_u128(&mut self, idx: u128) -> (u128, u16) { - let bytes = match self.lane_order().unwrap() { + let bytes = match self.lane_order() { LaneOrder::LittleEndian => idx.to_be_bytes().map(|x| { if x < 16 { 15 - x @@ -590,7 +588,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> let inst = self.lower_ctx.dfg().value_def(val).inst()?; let constant = self.lower_ctx.get_constant(inst)?; let ty = self.lower_ctx.output_ty(inst, 0); - Some(zero_extend_to_u64(constant, self.ty_bits(ty).unwrap())) + Some(zero_extend_to_u64(constant, self.ty_bits(ty))) } #[inline] @@ -598,7 +596,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> let inst = self.lower_ctx.dfg().value_def(val).inst()?; let constant = self.lower_ctx.get_constant(inst)?; let ty = self.lower_ctx.output_ty(inst, 0); - Some(zero_extend_to_u64(!constant, self.ty_bits(ty).unwrap())) + Some(zero_extend_to_u64(!constant, self.ty_bits(ty))) } #[inline] @@ -620,7 +618,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> let inst = self.lower_ctx.dfg().value_def(val).inst()?; let constant = self.lower_ctx.get_constant(inst)?; let ty = self.lower_ctx.output_ty(inst, 0); - Some(sign_extend_to_u64(constant, self.ty_bits(ty).unwrap())) + Some(sign_extend_to_u64(constant, self.ty_bits(ty))) } #[inline] diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle index 5217d9b51b..fdf15a147c 100644 --- a/cranelift/codegen/src/isa/x64/inst.isle +++ b/cranelift/codegen/src/isa/x64/inst.isle @@ -865,7 +865,7 @@ ;; A helper to both check that the `Imm64` and `Offset32` values sum to less ;; than 32-bits AND return this summed `u32` value. Also, the `Imm64` will be ;; zero-extended from `Type` up to 64 bits. This is useful for `to_amode`. -(decl pure sum_extend_fits_in_32_bits (Type Imm64 Offset32) u32) +(decl pure partial sum_extend_fits_in_32_bits (Type Imm64 Offset32) u32) (extern constructor sum_extend_fits_in_32_bits sum_extend_fits_in_32_bits) ;;;; Amode lowering ;;;; diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle index 93da49d6fd..3954ec5fbf 100644 --- a/cranelift/codegen/src/isa/x64/lower.isle +++ b/cranelift/codegen/src/isa/x64/lower.isle @@ -2,12 +2,12 @@ ;; The main lowering constructor term: takes a clif `Inst` and returns the ;; register(s) within which the lowered instruction's result values live. -(decl lower (Inst) InstOutput) +(decl partial lower (Inst) InstOutput) ;; A variant of the main lowering constructor term, used for branches. ;; The only difference is that it gets an extra argument holding a vector ;; of branch targets to be used. -(decl lower_branch (Inst MachLabelSlice) InstOutput) +(decl partial lower_branch (Inst MachLabelSlice) InstOutput) ;;;; Rules for `iconst` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1309,7 +1309,7 @@ if_true if_false)) -(decl pure all_ones_or_all_zeros (Value) bool) +(decl pure partial all_ones_or_all_zeros (Value) bool) (rule (all_ones_or_all_zeros (and (icmp _ _ _) (value_type (multi_lane _ _)))) $true) (rule (all_ones_or_all_zeros (and (fcmp _ _ _) (value_type (multi_lane _ _)))) $true) (rule (all_ones_or_all_zeros (vconst (vconst_all_ones_or_all_zeros))) $true) diff --git a/cranelift/codegen/src/isle_prelude.rs b/cranelift/codegen/src/isle_prelude.rs index 3e3c34c575..23270f0c49 100644 --- a/cranelift/codegen/src/isle_prelude.rs +++ b/cranelift/codegen/src/isle_prelude.rs @@ -14,43 +14,43 @@ macro_rules! isle_common_prelude_methods { } #[inline] - fn u8_as_u32(&mut self, x: u8) -> Option { - Some(x.into()) + fn u8_as_u32(&mut self, x: u8) -> u32 { + x.into() } #[inline] - fn u8_as_u64(&mut self, x: u8) -> Option { - Some(x.into()) + fn u8_as_u64(&mut self, x: u8) -> u64 { + x.into() } #[inline] - fn u16_as_u64(&mut self, x: u16) -> Option { - Some(x.into()) + fn u16_as_u64(&mut self, x: u16) -> u64 { + x.into() } #[inline] - fn u32_as_u64(&mut self, x: u32) -> Option { - Some(x.into()) + fn u32_as_u64(&mut self, x: u32) -> u64 { + x.into() } #[inline] - fn i64_as_u64(&mut self, x: i64) -> Option { - Some(x as u64) + fn i64_as_u64(&mut self, x: i64) -> u64 { + x as u64 } #[inline] - fn u64_add(&mut self, x: u64, y: u64) -> Option { - Some(x.wrapping_add(y)) + fn u64_add(&mut self, x: u64, y: u64) -> u64 { + x.wrapping_add(y) } #[inline] - fn u64_sub(&mut self, x: u64, y: u64) -> Option { - Some(x.wrapping_sub(y)) + fn u64_sub(&mut self, x: u64, y: u64) -> u64 { + x.wrapping_sub(y) } #[inline] - fn u64_mul(&mut self, x: u64, y: u64) -> Option { - Some(x.wrapping_mul(y)) + fn u64_mul(&mut self, x: u64, y: u64) -> u64 { + x.wrapping_mul(y) } #[inline] @@ -66,23 +66,23 @@ macro_rules! isle_common_prelude_methods { } #[inline] - fn u64_and(&mut self, x: u64, y: u64) -> Option { - Some(x & y) + fn u64_and(&mut self, x: u64, y: u64) -> u64 { + x & y } #[inline] - fn u64_or(&mut self, x: u64, y: u64) -> Option { - Some(x | y) + fn u64_or(&mut self, x: u64, y: u64) -> u64 { + x | y } #[inline] - fn u64_xor(&mut self, x: u64, y: u64) -> Option { - Some(x ^ y) + fn u64_xor(&mut self, x: u64, y: u64) -> u64 { + x ^ y } #[inline] - fn u64_not(&mut self, x: u64) -> Option { - Some(!x) + fn u64_not(&mut self, x: u64) -> u64 { + !x } #[inline] @@ -91,24 +91,24 @@ macro_rules! isle_common_prelude_methods { } #[inline] - fn u64_is_odd(&mut self, x: u64) -> Option { - Some(x & 1 == 1) + fn u64_is_odd(&mut self, x: u64) -> bool { + x & 1 == 1 } #[inline] - fn u64_sextend_u32(&mut self, x: u64) -> Option { - Some(x as u32 as i32 as i64 as u64) + fn u64_sextend_u32(&mut self, x: u64) -> u64 { + x as u32 as i32 as i64 as u64 } #[inline] - fn u64_uextend_u32(&mut self, x: u64) -> Option { - Some(x & 0xffff_ffff) + fn u64_uextend_u32(&mut self, x: u64) -> u64 { + x & 0xffff_ffff } #[inline] - fn ty_bits(&mut self, ty: Type) -> Option { + fn ty_bits(&mut self, ty: Type) -> u8 { use std::convert::TryInto; - Some(ty.bits().try_into().unwrap()) + ty.bits().try_into().unwrap() } #[inline] @@ -505,8 +505,8 @@ macro_rules! isle_common_prelude_methods { } #[inline] - fn imm64(&mut self, x: u64) -> Option { - Some(Imm64::new(x as i64)) + fn imm64(&mut self, x: u64) -> Imm64 { + Imm64::new(x as i64) } #[inline] diff --git a/cranelift/codegen/src/opts.rs b/cranelift/codegen/src/opts.rs index 8f0ca0c9ee..17da7aff57 100644 --- a/cranelift/codegen/src/opts.rs +++ b/cranelift/codegen/src/opts.rs @@ -90,8 +90,8 @@ impl<'a, 'b, 'c> generated_code::Context for IsleContext<'a, 'b, 'c> { type inst_data_etor_iter = InstDataEtorIter<'a, 'b, 'c>; - fn inst_data_etor(&mut self, eclass: Value) -> Option> { - Some(InstDataEtorIter::new(eclass)) + fn inst_data_etor(&mut self, eclass: Value) -> InstDataEtorIter<'a, 'b, 'c> { + InstDataEtorIter::new(eclass) } fn make_inst_ctor(&mut self, ty: Type, op: &InstructionData) -> Value { diff --git a/cranelift/codegen/src/prelude.isle b/cranelift/codegen/src/prelude.isle index fef9a3ab94..0f17b6b442 100644 --- a/cranelift/codegen/src/prelude.isle +++ b/cranelift/codegen/src/prelude.isle @@ -9,7 +9,7 @@ ;; `()` (type Unit (primitive Unit)) -(decl unit () Unit) +(decl pure unit () Unit) (extern constructor unit unit) (type bool (primitive bool)) @@ -42,12 +42,12 @@ (decl value_type (Type) Value) (extern extractor infallible value_type value_type) -(decl u32_add (u32 u32) u32) +(decl pure u32_add (u32 u32) u32) (extern constructor u32_add u32_add) ;; Pure/fallible constructor that tries to add two `u32`s, interpreted ;; as signed values, and fails to match on overflow. -(decl pure s32_add_fallible (u32 u32) u32) +(decl pure partial s32_add_fallible (u32 u32) u32) (extern constructor s32_add_fallible s32_add_fallible) ;; Extractor that matches a `u32` only if non-negative. @@ -61,17 +61,17 @@ ;; Pure/fallible constructor that tests if one u32 is less than or ;; equal to another. -(decl pure u32_lteq (u32 u32) Unit) +(decl pure partial u32_lteq (u32 u32) Unit) (extern constructor u32_lteq u32_lteq) ;; Pure/fallible constructor that tests if one u8 is less than or ;; equal to another. -(decl pure u8_lteq (u8 u8) Unit) +(decl pure partial u8_lteq (u8 u8) Unit) (extern constructor u8_lteq u8_lteq) ;; Pure/fallible constructor that tests if one u8 is strictly less ;; than another. -(decl pure u8_lt (u8 u8) Unit) +(decl pure partial u8_lt (u8 u8) Unit) (extern constructor u8_lt u8_lt) ;; Get a signed 32-bit immediate in an u32 from an Imm64, if possible. @@ -82,7 +82,7 @@ (decl uimm8 (u8) Imm64) (extern extractor uimm8 uimm8) -(decl u8_and (u8 u8) u8) +(decl pure u8_and (u8 u8) u8) (extern constructor u8_and u8_and) ;;;; Primitive Type Conversions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -113,10 +113,10 @@ (decl pure u64_mul (u64 u64) u64) (extern constructor u64_mul u64_mul) -(decl pure u64_sdiv (u64 u64) u64) +(decl pure partial u64_sdiv (u64 u64) u64) (extern constructor u64_sdiv u64_sdiv) -(decl pure u64_udiv (u64 u64) u64) +(decl pure partial u64_udiv (u64 u64) u64) (extern constructor u64_udiv u64_udiv) (decl pure u64_and (u64 u64) u64) @@ -181,29 +181,29 @@ (extern constructor ty_bits ty_bits) ;; Get the bit width of a given type. -(decl ty_bits_u16 (Type) u16) +(decl pure ty_bits_u16 (Type) u16) (extern constructor ty_bits_u16 ty_bits_u16) ;; Get the bit width of a given type. -(decl ty_bits_u64 (Type) u64) +(decl pure ty_bits_u64 (Type) u64) (extern constructor ty_bits_u64 ty_bits_u64) ;; Get a mask for the width of a given type. -(decl ty_mask (Type) u64) +(decl pure ty_mask (Type) u64) (extern constructor ty_mask ty_mask) ;; Get the byte width of a given type. -(decl ty_bytes (Type) u16) +(decl pure ty_bytes (Type) u16) (extern constructor ty_bytes ty_bytes) ;; Get the type of each lane in the given type. -(decl lane_type (Type) Type) +(decl pure lane_type (Type) Type) (extern constructor lane_type lane_type) ;;;; `cranelift_codegen::ir::MemFlags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; `MemFlags::trusted` -(decl mem_flags_trusted () MemFlags) +(decl pure mem_flags_trusted () MemFlags) (extern constructor mem_flags_trusted mem_flags_trusted) ;;;; Helpers for Working with Flags ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -252,7 +252,7 @@ ;; A pure constructor that only matches scalar integers, and references that can ;; fit in 64 bits. -(decl pure ty_int_ref_scalar_64 (Type) Type) +(decl pure partial ty_int_ref_scalar_64 (Type) Type) (extern constructor ty_int_ref_scalar_64 ty_int_ref_scalar_64) ;; An extractor that matches 32- and 64-bit types only. @@ -284,16 +284,16 @@ (extern extractor ty_float_or_vec ty_float_or_vec) ;; A pure constructor that only matches vector floating-point types. -(decl pure ty_vector_float (Type) Type) +(decl pure partial ty_vector_float (Type) Type) (extern constructor ty_vector_float ty_vector_float) ;; A pure constructor that only matches vector types with lanes which ;; are not floating-point. -(decl pure ty_vector_not_float (Type) Type) +(decl pure partial ty_vector_not_float (Type) Type) (extern constructor ty_vector_not_float ty_vector_not_float) ;; A pure constructor/extractor that only matches 64-bit vector types. -(decl pure ty_vec64 (Type) Type) +(decl pure partial ty_vec64 (Type) Type) (extern constructor ty_vec64 ty_vec64_ctor) (extern extractor ty_vec64 ty_vec64) @@ -322,7 +322,7 @@ (extern extractor ty_vec128_int ty_vec128_int) ;; A pure constructor that matches everything except vectors with size 32X2. -(decl pure not_vec32x2 (Type) Type) +(decl pure partial not_vec32x2 (Type) Type) (extern constructor not_vec32x2 not_vec32x2) ;; An extractor that matches everything except I64X2 @@ -388,28 +388,28 @@ (extern extractor ty_dyn128_int ty_dyn128_int) ;; Convert an `Offset32` to a primitive number. -(decl offset32_to_u32 (Offset32) u32) +(decl pure offset32_to_u32 (Offset32) u32) (extern constructor offset32_to_u32 offset32_to_u32) ;; This is a direct import of `IntCC::unsigned`. ;; Get the corresponding IntCC with the signed component removed. ;; For conditions without a signed component, this is a no-op. -(decl intcc_unsigned (IntCC) IntCC) +(decl pure intcc_unsigned (IntCC) IntCC) (extern constructor intcc_unsigned intcc_unsigned) ;; Pure constructor that only matches signed integer cond codes. -(decl pure signed_cond_code (IntCC) IntCC) +(decl pure partial signed_cond_code (IntCC) IntCC) (extern constructor signed_cond_code signed_cond_code) ;;;; Helpers for Working with TrapCode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(decl trap_code_division_by_zero () TrapCode) +(decl pure trap_code_division_by_zero () TrapCode) (extern constructor trap_code_division_by_zero trap_code_division_by_zero) -(decl trap_code_integer_overflow () TrapCode) +(decl pure trap_code_integer_overflow () TrapCode) (extern constructor trap_code_integer_overflow trap_code_integer_overflow) -(decl trap_code_bad_conversion_to_integer () TrapCode) +(decl pure trap_code_bad_conversion_to_integer () TrapCode) (extern constructor trap_code_bad_conversion_to_integer trap_code_bad_conversion_to_integer) ;;;; Helpers for tail recursion loops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -418,7 +418,7 @@ (type Range (primitive Range)) ;; Create a new range from `start` through `end` (exclusive). -(decl range (usize usize) Range) +(decl pure range (usize usize) Range) (extern constructor range range) ;; A view on the current state of the range. diff --git a/cranelift/codegen/src/prelude_lower.isle b/cranelift/codegen/src/prelude_lower.isle index ca89554a66..49e56f19b0 100644 --- a/cranelift/codegen/src/prelude_lower.isle +++ b/cranelift/codegen/src/prelude_lower.isle @@ -227,11 +227,11 @@ (def_inst (iconst (u64_from_imm64 x)))) ;; Match any zero value for iconst, fconst32, fconst64, vconst and splat. -(decl pure zero_value (Value) Value) +(decl pure partial zero_value (Value) Value) (extern constructor zero_value zero_value) ;; Match a sinkable instruction from a value operand. -(decl pure is_sinkable_inst (Value) Inst) +(decl pure partial is_sinkable_inst (Value) Inst) (extern constructor is_sinkable_inst is_sinkable_inst) ;; Instruction creation helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -531,16 +531,16 @@ (decl tls_model (TlsModel) Type) (extern extractor infallible tls_model tls_model) -(decl pure tls_model_is_elf_gd () Unit) +(decl pure partial tls_model_is_elf_gd () Unit) (extern constructor tls_model_is_elf_gd tls_model_is_elf_gd) -(decl pure tls_model_is_macho () Unit) +(decl pure partial tls_model_is_macho () Unit) (extern constructor tls_model_is_macho tls_model_is_macho) -(decl pure tls_model_is_coff () Unit) +(decl pure partial tls_model_is_coff () Unit) (extern constructor tls_model_is_coff tls_model_is_coff) -(decl pure preserve_frame_pointers () Unit) +(decl pure partial preserve_frame_pointers () Unit) (extern constructor preserve_frame_pointers preserve_frame_pointers) ;;;; Helpers for accessing instruction data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/isle/isle/isle_examples/link/borrows.isle b/cranelift/isle/isle/isle_examples/link/borrows.isle index bfae320d68..526c21ede9 100644 --- a/cranelift/isle/isle/isle_examples/link/borrows.isle +++ b/cranelift/isle/isle/isle_examples/link/borrows.isle @@ -4,7 +4,7 @@ (decl get_a (A) u32) (extern extractor get_a get_a) -(decl pure u32_pure (u32) u32) +(decl pure partial u32_pure (u32) u32) (extern constructor u32_pure u32_pure) (decl entry (u32) u32) diff --git a/cranelift/isle/isle/isle_examples/link/iflets.isle b/cranelift/isle/isle/isle_examples/link/iflets.isle index 8bc6b65439..bd768b4ece 100644 --- a/cranelift/isle/isle/isle_examples/link/iflets.isle +++ b/cranelift/isle/isle/isle_examples/link/iflets.isle @@ -1,12 +1,12 @@ (type u32 (primitive u32)) -(decl pure A (u32 u32) u32) +(decl pure partial A (u32 u32) u32) (extern constructor A A) (decl B (u32 u32) u32) (extern extractor B B) -(decl C (u32 u32 u32 u32) u32) +(decl partial C (u32 u32 u32 u32) u32) (decl pure predicate () u32) (rule (predicate) 1) diff --git a/cranelift/isle/isle/isle_examples/link/multi_constructor_main.rs b/cranelift/isle/isle/isle_examples/link/multi_constructor_main.rs index 8a92a0beb1..16725e36ce 100644 --- a/cranelift/isle/isle/isle_examples/link/multi_constructor_main.rs +++ b/cranelift/isle/isle/isle_examples/link/multi_constructor_main.rs @@ -25,22 +25,28 @@ impl multi_constructor::ContextIter for It { impl multi_constructor::Context for Context { type etor_C_iter = It; - fn etor_C(&mut self, value: u32) -> Option { - Some(It { i: 0, limit: value }) + fn etor_C(&mut self, value: u32) -> It { + It { i: 0, limit: value } } type ctor_B_iter = multi_constructor::ContextIterWrapper, Context>; - fn ctor_B(&mut self, value: u32) -> Option { - Some((0..value).rev().collect::>().into_iter().into()) + fn ctor_B(&mut self, value: u32) -> Self::ctor_B_iter { + (0..value).rev().collect::>().into_iter().into() } } -struct IterWithContext<'a, Item, I: multi_constructor::ContextIter> { +struct IterWithContext< + 'a, + Item, + I: multi_constructor::ContextIter, +> { ctx: &'a mut Context, it: I, } -impl<'a, Item, I: multi_constructor::ContextIter> Iterator for IterWithContext<'a, Item, I> { +impl<'a, Item, I: multi_constructor::ContextIter> Iterator + for IterWithContext<'a, Item, I> +{ type Item = Item; fn next(&mut self) -> Option { self.it.next(self.ctx) @@ -49,9 +55,17 @@ impl<'a, Item, I: multi_constructor::ContextIter>(); - let l2 = IterWithContext { ctx: &mut ctx, it: l2 }.collect::>(); + let l1 = multi_constructor::constructor_A(&mut ctx, 10); + let l2 = multi_constructor::constructor_D(&mut ctx, 5); + let l1 = IterWithContext { + ctx: &mut ctx, + it: l1, + } + .collect::>(); + let l2 = IterWithContext { + ctx: &mut ctx, + it: l2, + } + .collect::>(); println!("l1 = {:?} l2 = {:?}", l1, l2); } diff --git a/cranelift/isle/isle/isle_examples/link/multi_extractor_main.rs b/cranelift/isle/isle/isle_examples/link/multi_extractor_main.rs index 0e774e7680..92d5d1c63f 100644 --- a/cranelift/isle/isle/isle_examples/link/multi_extractor_main.rs +++ b/cranelift/isle/isle/isle_examples/link/multi_extractor_main.rs @@ -33,8 +33,8 @@ impl multi_extractor::ContextIter for It { struct Context; impl multi_extractor::Context for Context { type e1_etor_iter = It; - fn e1_etor(&mut self, arg0: u32) -> Option { - Some(It { i: 0, arg: arg0 }) + fn e1_etor(&mut self, arg0: u32) -> It { + It { i: 0, arg: arg0 } } } diff --git a/cranelift/isle/isle/isle_examples/run/iconst.isle b/cranelift/isle/isle/isle_examples/run/iconst.isle index ba407b9883..13e8c1e68c 100644 --- a/cranelift/isle/isle/isle_examples/run/iconst.isle +++ b/cranelift/isle/isle/isle_examples/run/iconst.isle @@ -1,6 +1,6 @@ (type i64 (primitive i64)) -(decl X (i64) i64) +(decl partial X (i64) i64) (rule (X -1) -2) (rule (X -2) -3) (rule (X 0x7fff_ffff_ffff_ffff) 0x8000_0000_0000_0000) @@ -8,7 +8,7 @@ (type i128 (primitive i128)) -(decl Y (i128) i128) +(decl partial Y (i128) i128) (rule (Y 0x1000_0000_0000_0000_1234_5678_9abc_def0) -1) (rule (Y 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff) 3) diff --git a/cranelift/isle/isle/isle_examples/run/let_shadowing_main.rs b/cranelift/isle/isle/isle_examples/run/let_shadowing_main.rs index bb1b33ca46..37ddb0bcc5 100644 --- a/cranelift/isle/isle/isle_examples/run/let_shadowing_main.rs +++ b/cranelift/isle/isle/isle_examples/run/let_shadowing_main.rs @@ -7,21 +7,21 @@ impl let_shadowing::Context for Context {} fn main() { let mut ctx = Context; - assert_eq!(Some(20), let_shadowing::constructor_test1(&mut ctx, 20)); - assert_eq!(Some(97), let_shadowing::constructor_test1(&mut ctx, 97)); + assert_eq!(20, let_shadowing::constructor_test1(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test1(&mut ctx, 97)); - assert_eq!(Some(20), let_shadowing::constructor_test2(&mut ctx, 20)); - assert_eq!(Some(97), let_shadowing::constructor_test2(&mut ctx, 97)); + assert_eq!(20, let_shadowing::constructor_test2(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test2(&mut ctx, 97)); - assert_eq!(Some(20), let_shadowing::constructor_test3(&mut ctx, 20)); - assert_eq!(Some(97), let_shadowing::constructor_test3(&mut ctx, 97)); + assert_eq!(20, let_shadowing::constructor_test3(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test3(&mut ctx, 97)); - assert_eq!(Some(23), let_shadowing::constructor_test4(&mut ctx, 20)); - assert_eq!(Some(23), let_shadowing::constructor_test4(&mut ctx, 97)); + assert_eq!(23, let_shadowing::constructor_test4(&mut ctx, 20)); + assert_eq!(23, let_shadowing::constructor_test4(&mut ctx, 97)); - assert_eq!(Some(20), let_shadowing::constructor_test5(&mut ctx, 20)); - assert_eq!(Some(97), let_shadowing::constructor_test5(&mut ctx, 97)); + assert_eq!(20, let_shadowing::constructor_test5(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test5(&mut ctx, 97)); - assert_eq!(Some(20), let_shadowing::constructor_test6(&mut ctx, 20)); - assert_eq!(Some(97), let_shadowing::constructor_test6(&mut ctx, 97)); + assert_eq!(20, let_shadowing::constructor_test6(&mut ctx, 20)); + assert_eq!(97, let_shadowing::constructor_test6(&mut ctx, 97)); } diff --git a/cranelift/isle/isle/src/ast.rs b/cranelift/isle/isle/src/ast.rs index bd967d6198..a94c85659a 100644 --- a/cranelift/isle/isle/src/ast.rs +++ b/cranelift/isle/isle/src/ast.rs @@ -83,6 +83,8 @@ pub struct Decl { /// extractor or a constructor that matches multiple times, or /// produces multiple values. pub multi: bool, + /// Whether this term's constructor can fail to match. + pub partial: bool, pub pos: Pos, } diff --git a/cranelift/isle/isle/src/codegen.rs b/cranelift/isle/isle/src/codegen.rs index 284afcdb7a..85896d999d 100644 --- a/cranelift/isle/isle/src/codegen.rs +++ b/cranelift/isle/isle/src/codegen.rs @@ -2,10 +2,10 @@ use crate::ir::{ExprInst, InstId, PatternInst, Value}; use crate::log; -use crate::sema::ExternalSig; -use crate::sema::{TermEnv, TermId, Type, TypeEnv, TypeId, Variant}; +use crate::sema::{ExternalSig, ReturnKind, TermEnv, TermId, Type, TypeEnv, TypeId, Variant}; use crate::trie::{TrieEdge, TrieNode, TrieSymbol}; use crate::{StableMap, StableSet}; +use std::borrow::Cow; use std::collections::BTreeMap; use std::fmt::Write; @@ -111,14 +111,21 @@ impl<'a> Codegen<'a> { close_paren = if sig.ret_tys.len() != 1 { ")" } else { "" }, ); - let ret_ty = match (sig.multi, sig.infallible) { - (false, false) => format!("Option<{}>", ret_tuple), - (false, true) => format!("{}", ret_tuple), - (true, false) => format!("Option", sig.func_name), - _ => panic!( - "Unsupported multiplicity/infallible combo: {:?}, {}", - sig.multi, sig.infallible - ), + if sig.ret_kind == ReturnKind::Iterator { + writeln!( + code, + "{indent}type {name}_iter: ContextIter;", + indent = indent, + name = sig.func_name, + output = ret_tuple, + ) + .unwrap(); + } + + let ret_ty = match sig.ret_kind { + ReturnKind::Plain => ret_tuple, + ReturnKind::Option => format!("Option<{}>", ret_tuple), + ReturnKind::Iterator => format!("Self::{}_iter", sig.func_name), }; writeln!( @@ -136,17 +143,6 @@ impl<'a> Codegen<'a> { ret_ty = ret_ty, ) .unwrap(); - - if sig.multi { - writeln!( - code, - "{indent}type {name}_iter: ContextIter;", - indent = indent, - name = sig.func_name, - output = ret_tuple, - ) - .unwrap(); - } } fn generate_ctx_trait(&self, code: &mut String) { @@ -357,27 +353,29 @@ impl<'a> Codegen<'a> { .collect::>() .join(", "); assert_eq!(sig.ret_tys.len(), 1); + let ret = self.type_name(sig.ret_tys[0], false); - let ret = if sig.multi { - format!("impl ContextIter", ret) - } else { - ret + let ret = match sig.ret_kind { + ReturnKind::Iterator => format!("impl ContextIter", ret), + ReturnKind::Option => format!("Option<{}>", ret), + ReturnKind::Plain => ret, }; + let term_name = &self.typeenv.syms[termdata.name.index()]; writeln!( code, "\n// Generated as internal constructor for term {}.", - self.typeenv.syms[termdata.name.index()], + term_name, ) .unwrap(); writeln!( code, - "pub fn {}(ctx: &mut C, {}) -> Option<{}> {{", + "pub fn {}(ctx: &mut C, {}) -> {} {{", sig.func_name, args, ret, ) .unwrap(); - if sig.multi { + if sig.ret_kind == ReturnKind::Iterator { writeln!(code, "let mut returns = ConstructorVec::new();").unwrap(); } @@ -388,18 +386,23 @@ impl<'a> Codegen<'a> { trie, " ", &mut body_ctx, - sig.multi, + sig.ret_kind, ); if !returned { - if sig.multi { - writeln!( - code, - " return Some(ContextIterWrapper::from(returns.into_iter()));" - ) - .unwrap(); - } else { - writeln!(code, " return None;").unwrap(); - } + let ret_expr = match sig.ret_kind { + ReturnKind::Plain => Cow::from(format!( + "unreachable!(\"no rule matched for term {{}} at {{}}; should it be partial?\", {:?}, {:?})", + term_name, + termdata + .decl_pos + .pretty_print_line(&self.typeenv.filenames[..]) + )), + ReturnKind::Option => Cow::from("None"), + ReturnKind::Iterator => { + Cow::from("ContextIterWrapper::from(returns.into_iter())") + } + }; + write!(code, " return {};", ret_expr).unwrap(); } writeln!(code, "}}").unwrap(); @@ -542,7 +545,7 @@ impl<'a> Codegen<'a> { } else { writeln!( code, - "{}let mut it = {}(ctx, {})?;", + "{}let mut iter = {}(ctx, {});", indent, sig.full_name, input_exprs.join(", "), @@ -550,7 +553,7 @@ impl<'a> Codegen<'a> { .unwrap(); writeln!( code, - "{}while let Some({}) = it.next(ctx) {{", + "{}while let Some({}) = iter.next(ctx) {{", indent, outputname, ) .unwrap(); @@ -717,49 +720,20 @@ impl<'a> Codegen<'a> { args = input_values.join(", ") ); - match (infallible, multi) { - (_, true) => { - writeln!( - code, - "{indent}if let Some(mut iter) = {etor_call} {{", - indent = indent, - etor_call = etor_call, - ) - .unwrap(); - writeln!( - code, - "{indent} while let Some({bind_pattern}) = iter.next(ctx) {{", - indent = indent, - bind_pattern = bind_pattern, - ) - .unwrap(); - - (false, 2) - } - (false, false) => { - writeln!( - code, - "{indent}if let Some({bind_pattern}) = {etor_call} {{", - indent = indent, - bind_pattern = bind_pattern, - etor_call = etor_call, - ) - .unwrap(); - - (false, 1) - } - (true, false) => { - writeln!( - code, - "{indent}let {bind_pattern} = {etor_call};", - indent = indent, - bind_pattern = bind_pattern, - etor_call = etor_call, - ) - .unwrap(); - - (true, 0) - } + if multi { + writeln!(code, "{indent}let mut iter = {etor_call};").unwrap(); + writeln!( + code, + "{indent}while let Some({bind_pattern}) = iter.next(ctx) {{", + ) + .unwrap(); + (false, 1) + } else if infallible { + writeln!(code, "{indent}let {bind_pattern} = {etor_call};").unwrap(); + (true, 0) + } else { + writeln!(code, "{indent}if let Some({bind_pattern}) = {etor_call} {{").unwrap(); + (false, 1) } } &PatternInst::Expr { @@ -833,7 +807,7 @@ impl<'a> Codegen<'a> { trie: &TrieNode, indent: &str, ctx: &mut BodyContext, - is_multi: bool, + ret_kind: ReturnKind, ) -> bool { log!("generate_body:\n{}", trie.pretty()); let mut returned = false; @@ -865,17 +839,18 @@ impl<'a> Codegen<'a> { } assert_eq!(returns.len(), 1); - if is_multi { - writeln!(code, "{}returns.push({});", indent, returns[0].1).unwrap(); - } else { - writeln!(code, "{}return Some({});", indent, returns[0].1).unwrap(); - } + let (before, after) = match ret_kind { + ReturnKind::Plain => ("return ", ""), + ReturnKind::Option => ("return Some(", ")"), + ReturnKind::Iterator => ("returns.push(", ")"), + }; + writeln!(code, "{}{}{}{};", indent, before, returns[0].1, after).unwrap(); for _ in 0..scopes { writeln!(code, "{}}}", orig_indent).unwrap(); } - returned = !is_multi; + returned = ret_kind != ReturnKind::Iterator; } &TrieNode::Decision { ref edges } => { @@ -930,7 +905,7 @@ impl<'a> Codegen<'a> { &edges[i..last], indent, ctx, - is_multi, + ret_kind, ); i = last; continue; @@ -950,7 +925,7 @@ impl<'a> Codegen<'a> { node, indent, ctx, - is_multi, + ret_kind, ); } &TrieSymbol::Match { ref op } => { @@ -967,7 +942,7 @@ impl<'a> Codegen<'a> { node, &subindent[..], ctx, - is_multi, + ret_kind, ); for _ in 0..new_scopes { writeln!(code, "{}}}", indent).unwrap(); @@ -993,7 +968,7 @@ impl<'a> Codegen<'a> { edges: &[TrieEdge], indent: &str, ctx: &mut BodyContext, - is_multi: bool, + ret_kind: ReturnKind, ) { let (input, input_ty) = match &edges[0].symbol { &TrieSymbol::Match { @@ -1058,7 +1033,7 @@ impl<'a> Codegen<'a> { ) .unwrap(); let subindent = format!("{} ", indent); - self.generate_body(code, depth + 1, node, &subindent, ctx, is_multi); + self.generate_body(code, depth + 1, node, &subindent, ctx, ret_kind); writeln!(code, "{} }}", indent).unwrap(); } diff --git a/cranelift/isle/isle/src/overlap.rs b/cranelift/isle/isle/src/overlap.rs index d127fc7f97..799c675701 100644 --- a/cranelift/isle/isle/src/overlap.rs +++ b/cranelift/isle/isle/src/overlap.rs @@ -112,7 +112,7 @@ fn check_overlaps(terms: Vec<(TermId, trie_again::RuleSet)>, env: &TermEnv) -> E let mut errs = Errors::default(); for (tid, ruleset) in terms { let is_multi_ctor = match &env.terms[tid.index()].kind { - &TermKind::Decl { multi, .. } => multi, + TermKind::Decl { flags, .. } => flags.multi, _ => false, }; if is_multi_ctor { diff --git a/cranelift/isle/isle/src/parser.rs b/cranelift/isle/isle/src/parser.rs index 03b9d09033..a305d6ce99 100644 --- a/cranelift/isle/isle/src/parser.rs +++ b/cranelift/isle/isle/src/parser.rs @@ -307,6 +307,12 @@ impl<'a> Parser<'a> { } else { false }; + let partial = if self.is_sym_str("partial") { + self.symbol()?; + true + } else { + false + }; let term = self.parse_ident()?; @@ -325,6 +331,7 @@ impl<'a> Parser<'a> { ret_ty, pure, multi, + partial, pos, }) } diff --git a/cranelift/isle/isle/src/sema.rs b/cranelift/isle/isle/src/sema.rs index d45ae68900..b0467c3f51 100644 --- a/cranelift/isle/isle/src/sema.rs +++ b/cranelift/isle/isle/src/sema.rs @@ -223,6 +223,17 @@ pub struct Term { pub kind: TermKind, } +/// Flags from a term's declaration with `(decl ...)`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TermFlags { + /// Whether the term is marked as `pure`. + pub pure: bool, + /// Whether the term is marked as `multi`. + pub multi: bool, + /// Whether the term is marked as `partial`. + pub partial: bool, +} + /// The kind of a term. #[derive(Clone, Debug, PartialEq, Eq)] pub enum TermKind { @@ -234,10 +245,8 @@ pub enum TermKind { }, /// A term declared via a `(decl ...)` form. Decl { - /// Whether the term is marked as `pure`. - pure: bool, - /// Whether the term is marked as `multi`. - multi: bool, + /// Flags from the term's declaration. + flags: TermFlags, /// The kind of this term's constructor, if any. constructor_kind: Option, /// The kind of this term's extractor, if any. @@ -279,6 +288,17 @@ pub enum ExtractorKind { }, } +/// How many values a function can return. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ReturnKind { + /// Exactly one return value. + Plain, + /// Zero or one return values. + Option, + /// Zero or more return values. + Iterator, +} + /// An external function signature. #[derive(Clone, Debug)] pub struct ExternalSig { @@ -290,11 +310,8 @@ pub struct ExternalSig { pub param_tys: Vec, /// The types of this function signature's results. pub ret_tys: Vec, - /// Whether this signature is infallible or not. - pub infallible: bool, - /// "Multiplicity": does the function return multiple values (via - /// an iterator)? - pub multi: bool, + /// How many values can this function return? + pub ret_kind: ReturnKind, } impl Term { @@ -372,20 +389,28 @@ impl Term { pub fn extractor_sig(&self, tyenv: &TypeEnv) -> Option { match &self.kind { TermKind::Decl { - multi, + flags, extractor_kind: Some(ExtractorKind::ExternalExtractor { name, infallible, .. }), .. - } => Some(ExternalSig { - func_name: tyenv.syms[name.index()].clone(), - full_name: format!("C::{}", tyenv.syms[name.index()]), - param_tys: vec![self.ret_ty], - ret_tys: self.arg_tys.clone(), - infallible: *infallible && !*multi, - multi: *multi, - }), + } => { + let ret_kind = if flags.multi { + ReturnKind::Iterator + } else if *infallible { + ReturnKind::Plain + } else { + ReturnKind::Option + }; + Some(ExternalSig { + func_name: tyenv.syms[name.index()].clone(), + full_name: format!("C::{}", tyenv.syms[name.index()]), + param_tys: vec![self.ret_ty], + ret_tys: self.arg_tys.clone(), + ret_kind, + }) + } _ => None, } } @@ -394,35 +419,33 @@ impl Term { pub fn constructor_sig(&self, tyenv: &TypeEnv) -> Option { match &self.kind { TermKind::Decl { - constructor_kind: Some(ConstructorKind::ExternalConstructor { name }), - multi, - pure, - .. - } => Some(ExternalSig { - func_name: tyenv.syms[name.index()].clone(), - full_name: format!("C::{}", tyenv.syms[name.index()]), - param_tys: self.arg_tys.clone(), - ret_tys: vec![self.ret_ty], - infallible: !pure && !*multi, - multi: *multi, - }), - TermKind::Decl { - constructor_kind: Some(ConstructorKind::InternalConstructor { .. }), - multi, + constructor_kind: Some(kind), + flags, .. } => { - let name = format!("constructor_{}", tyenv.syms[self.name.index()]); + let (func_name, full_name) = match kind { + ConstructorKind::InternalConstructor => { + let name = format!("constructor_{}", tyenv.syms[self.name.index()]); + (name.clone(), name) + } + ConstructorKind::ExternalConstructor { name } => ( + tyenv.syms[name.index()].clone(), + format!("C::{}", tyenv.syms[name.index()]), + ), + }; + let ret_kind = if flags.multi { + ReturnKind::Iterator + } else if flags.partial { + ReturnKind::Option + } else { + ReturnKind::Plain + }; Some(ExternalSig { - func_name: name.clone(), - full_name: name, + func_name, + full_name, param_tys: self.arg_tys.clone(), ret_tys: vec![self.ret_ty], - // Internal constructors are always fallible, even - // if not pure, because ISLE allows partial - // matching at the toplevel (an entry point can - // fail to rewrite). - infallible: false, - multi: *multi, + ret_kind, }) } _ => None, @@ -625,7 +648,7 @@ impl Pattern { panic!("Should have been expanded away") } TermKind::Decl { - multi, + flags, extractor_kind: Some(ExtractorKind::ExternalExtractor { infallible, .. }), .. } => { @@ -638,8 +661,8 @@ impl Pattern { termdata.ret_ty, output_tys, term, - *infallible && !*multi, - *multi, + *infallible && !flags.multi, + flags.multi, ) } }; @@ -737,30 +760,16 @@ impl Expr { visitor.add_create_variant(arg_values_tys, ty, *variant) } TermKind::Decl { - constructor_kind: Some(ConstructorKind::InternalConstructor), - multi, + constructor_kind: Some(_), + flags, .. } => { visitor.add_construct( arg_values_tys, ty, term, - /* infallible = */ false, - *multi, - ) - } - TermKind::Decl { - constructor_kind: Some(ConstructorKind::ExternalConstructor { .. }), - pure, - multi, - .. - } => { - visitor.add_construct( - arg_values_tys, - ty, - term, - /* infallible = */ !pure, - *multi, + /* infallible = */ !flags.partial, + flags.multi, ) } TermKind::Decl { @@ -1167,6 +1176,13 @@ impl TermEnv { ); } + if decl.multi && decl.partial { + tyenv.report_error( + decl.pos, + format!("Term '{}' can't be both multi and partial", decl.term.0), + ); + } + let arg_tys = decl .arg_tys .iter() @@ -1196,6 +1212,11 @@ impl TermEnv { let tid = TermId(self.terms.len()); self.term_map.insert(name, tid); + let flags = TermFlags { + pure: decl.pure, + multi: decl.multi, + partial: decl.partial, + }; self.terms.push(Term { id: tid, decl_pos: decl.pos, @@ -1203,10 +1224,9 @@ impl TermEnv { arg_tys, ret_ty, kind: TermKind::Decl { + flags, constructor_kind: None, extractor_kind: None, - pure: decl.pure, - multi: decl.multi, }, }); } @@ -1364,12 +1384,12 @@ impl TermEnv { continue; } TermKind::Decl { - multi, + flags, extractor_kind, .. } => match extractor_kind { None => { - if *multi { + if flags.multi { tyenv.report_error( ext.pos, "A term declared with `multi` cannot have an internal extractor.".to_string()); @@ -1658,8 +1678,8 @@ impl TermEnv { let termdata = &self.terms[root_term.index()]; - let pure = match &termdata.kind { - &TermKind::Decl { pure, .. } => pure, + let flags = match &termdata.kind { + TermKind::Decl { flags, .. } => flags, _ => { tyenv.report_error( pos, @@ -1676,14 +1696,17 @@ impl TermEnv { let iflets = rule .iflets .iter() - .filter_map(|iflet| self.translate_iflet(tyenv, iflet, &mut bindings)) + .filter_map(|iflet| { + self.translate_iflet(tyenv, iflet, &mut bindings, flags) + }) .collect(); let rhs = unwrap_or_continue!(self.translate_expr( tyenv, &rule.expr, Some(termdata.ret_ty), &mut bindings, - pure, + flags, + /* on_lhs */ false, )); let rid = RuleId(self.rules.len()); @@ -2058,7 +2081,8 @@ impl TermEnv { expr: &ast::Expr, ty: Option, bindings: &mut Bindings, - pure: bool, + root_flags: &TermFlags, + on_lhs: bool, ) -> Option { log!("translate_expr: {:?}", expr); match expr { @@ -2101,7 +2125,14 @@ impl TermEnv { if let Some(expanded_expr) = self.maybe_implicit_convert_expr(tyenv, expr, ret_ty, ty.unwrap()) { - return self.translate_expr(tyenv, &expanded_expr, ty, bindings, pure); + return self.translate_expr( + tyenv, + &expanded_expr, + ty, + bindings, + root_flags, + on_lhs, + ); } tyenv.report_error( @@ -2116,9 +2147,11 @@ impl TermEnv { ret_ty }; - // Check that the term's constructor is pure. - if pure { - if let TermKind::Decl { pure: false, .. } = &termdata.kind { + if let TermKind::Decl { flags, .. } = &termdata.kind { + // On the left-hand side of a rule or in a pure term, only pure terms may be + // used. + let pure_required = on_lhs || root_flags.pure; + if pure_required && !flags.pure { tyenv.report_error( pos, format!( @@ -2127,6 +2160,36 @@ impl TermEnv { ), ); } + + // Multi-terms may only be used inside other multi-terms. + if !root_flags.multi && flags.multi { + tyenv.report_error( + pos, + format!( + "Used multi-term '{}' but this rule is not in a multi-term", + sym.0 + ), + ); + } + + // Partial terms may always be used on the left-hand side of a rule. On the + // right-hand side they may only be used inside other partial terms. + let partial_allowed = on_lhs || root_flags.partial; + if !partial_allowed && flags.partial { + tyenv.report_error( + pos, + format!( + "Rule can't use partial constructor '{}' on RHS; \ + try moving it to if-let{}", + sym.0, + if root_flags.multi { + "" + } else { + " or make this rule's term partial too" + } + ), + ); + } } termdata.check_args_count(args, tyenv, pos, sym); @@ -2136,7 +2199,7 @@ impl TermEnv { .iter() .zip(termdata.arg_tys.iter()) .filter_map(|(arg, &arg_ty)| { - self.translate_expr(tyenv, arg, Some(arg_ty), bindings, pure) + self.translate_expr(tyenv, arg, Some(arg_ty), bindings, root_flags, on_lhs) }) .collect(); @@ -2159,7 +2222,14 @@ impl TermEnv { if let Some(expanded_expr) = self.maybe_implicit_convert_expr(tyenv, expr, bv.ty, ty.unwrap()) { - return self.translate_expr(tyenv, &expanded_expr, ty, bindings, pure); + return self.translate_expr( + tyenv, + &expanded_expr, + ty, + bindings, + root_flags, + on_lhs, + ); } tyenv.report_error( @@ -2251,7 +2321,8 @@ impl TermEnv { &def.val, Some(tid), bindings, - pure + root_flags, + on_lhs, ))); // Bind the var with the given type. @@ -2260,7 +2331,8 @@ impl TermEnv { } // Evaluate the body, expecting the type of the overall let-expr. - let body = Box::new(self.translate_expr(tyenv, body, ty, bindings, pure)?); + let body = + Box::new(self.translate_expr(tyenv, body, ty, bindings, root_flags, on_lhs)?); let body_ty = body.ty(); // Pop the bindings. @@ -2280,10 +2352,18 @@ impl TermEnv { tyenv: &mut TypeEnv, iflet: &ast::IfLet, bindings: &mut Bindings, + root_flags: &TermFlags, ) -> Option { - // Translate the expr first. Ensure it's pure. - let rhs = - self.translate_expr(tyenv, &iflet.expr, None, bindings, /* pure = */ true)?; + // Translate the expr first. The `if-let` and `if` forms are part of the left-hand side of + // the rule. + let rhs = self.translate_expr( + tyenv, + &iflet.expr, + None, + bindings, + root_flags, + /* on_lhs */ true, + )?; let ty = rhs.ty(); let (lhs, _lhs_ty) = self.translate_pattern(tyenv, &iflet.pattern, Some(ty), bindings)?;