ISLE: remove all uses of argument polarity, and remove it from the language. (#4091)
This PR removes "argument polarity": the feature of ISLE extractors that lets them take inputs aside from the value to be matched. Cases that need this expressivity have been subsumed by #4072 with if-let clauses; we can now finally remove this misfeature of the language, which has caused significant confusion and has always felt like a bit of a hack. This PR (i) removes the feature from the ISLE compiler; (ii) removes it from the reference documentation; and (iii) refactors away all uses of the feature in our three existing backends written in ISLE.
This commit is contained in:
@@ -1290,14 +1290,14 @@
|
|||||||
(decl move_wide_const_from_negated_u64 (MoveWideConst) u64)
|
(decl move_wide_const_from_negated_u64 (MoveWideConst) u64)
|
||||||
(extern extractor move_wide_const_from_negated_u64 move_wide_const_from_negated_u64)
|
(extern extractor move_wide_const_from_negated_u64 move_wide_const_from_negated_u64)
|
||||||
|
|
||||||
(decl imm_logic_from_u64 (Type ImmLogic) u64)
|
(decl pure imm_logic_from_u64 (Type u64) ImmLogic)
|
||||||
(extern extractor imm_logic_from_u64 imm_logic_from_u64 (in out))
|
(extern constructor imm_logic_from_u64 imm_logic_from_u64)
|
||||||
|
|
||||||
(decl imm_logic_from_imm64 (Type ImmLogic) Imm64)
|
(decl pure imm_logic_from_imm64 (Type Imm64) ImmLogic)
|
||||||
(extern extractor imm_logic_from_imm64 imm_logic_from_imm64 (in out))
|
(extern constructor imm_logic_from_imm64 imm_logic_from_imm64)
|
||||||
|
|
||||||
(decl imm_shift_from_imm64 (Type ImmShift) Imm64)
|
(decl pure imm_shift_from_imm64 (Type Imm64) ImmShift)
|
||||||
(extern extractor imm_shift_from_imm64 imm_shift_from_imm64 (in out))
|
(extern constructor imm_shift_from_imm64 imm_shift_from_imm64)
|
||||||
|
|
||||||
(decl imm_shift_from_u8 (u8) ImmShift)
|
(decl imm_shift_from_u8 (u8) ImmShift)
|
||||||
(extern constructor imm_shift_from_u8 imm_shift_from_u8)
|
(extern constructor imm_shift_from_u8 imm_shift_from_u8)
|
||||||
@@ -1317,8 +1317,8 @@
|
|||||||
(decl imm12_from_negated_u64 (Imm12) u64)
|
(decl imm12_from_negated_u64 (Imm12) u64)
|
||||||
(extern extractor imm12_from_negated_u64 imm12_from_negated_u64)
|
(extern extractor imm12_from_negated_u64 imm12_from_negated_u64)
|
||||||
|
|
||||||
(decl lshl_from_imm64 (Type ShiftOpAndAmt) Imm64)
|
(decl pure lshl_from_imm64 (Type Imm64) ShiftOpAndAmt)
|
||||||
(extern extractor lshl_from_imm64 lshl_from_imm64 (in out))
|
(extern constructor lshl_from_imm64 lshl_from_imm64)
|
||||||
|
|
||||||
(decl integral_ty (Type) Type)
|
(decl integral_ty (Type) Type)
|
||||||
(extern extractor integral_ty integral_ty)
|
(extern extractor integral_ty integral_ty)
|
||||||
@@ -1330,13 +1330,13 @@
|
|||||||
(decl imm12_from_value (Imm12) Value)
|
(decl imm12_from_value (Imm12) Value)
|
||||||
(extractor
|
(extractor
|
||||||
(imm12_from_value n)
|
(imm12_from_value n)
|
||||||
(def_inst (iconst (u64_from_imm64 (imm12_from_u64 n)))))
|
(iconst (u64_from_imm64 (imm12_from_u64 n))))
|
||||||
|
|
||||||
;; Same as `imm12_from_value`, but tries negating the constant value.
|
;; Same as `imm12_from_value`, but tries negating the constant value.
|
||||||
(decl imm12_from_negated_value (Imm12) Value)
|
(decl imm12_from_negated_value (Imm12) Value)
|
||||||
(extractor
|
(extractor
|
||||||
(imm12_from_negated_value n)
|
(imm12_from_negated_value n)
|
||||||
(def_inst (iconst (u64_from_imm64 (imm12_from_negated_u64 n)))))
|
(iconst (u64_from_imm64 (imm12_from_negated_u64 n))))
|
||||||
|
|
||||||
;; Helper type to represent a value and an extend operation fused together.
|
;; Helper type to represent a value and an extend operation fused together.
|
||||||
(type ExtendedValue extern (enum))
|
(type ExtendedValue extern (enum))
|
||||||
@@ -1877,7 +1877,8 @@
|
|||||||
(movn n (OperandSize.Size64)))
|
(movn n (OperandSize.Size64)))
|
||||||
|
|
||||||
;; Weird logical-instruction immediate in ORI using zero register
|
;; Weird logical-instruction immediate in ORI using zero register
|
||||||
(rule (imm (integral_ty _ty) (imm_logic_from_u64 <$I64 n))
|
(rule (imm (integral_ty _ty) k)
|
||||||
|
(if-let n (imm_logic_from_u64 $I64 k))
|
||||||
(orr_imm $I64 (zero_reg) n))
|
(orr_imm $I64 (zero_reg) n))
|
||||||
|
|
||||||
(decl load_constant64_full (u64) Reg)
|
(decl load_constant64_full (u64) Reg)
|
||||||
@@ -1978,29 +1979,35 @@
|
|||||||
|
|
||||||
;; Base case of operating on registers.
|
;; Base case of operating on registers.
|
||||||
(rule (alu_rs_imm_logic_commutative op ty x y)
|
(rule (alu_rs_imm_logic_commutative op ty x y)
|
||||||
(alu_rrr op ty (put_in_reg x) (put_in_reg y)))
|
(alu_rrr op ty x y))
|
||||||
|
|
||||||
;; Special cases for when one operand is a constant.
|
;; Special cases for when one operand is a constant.
|
||||||
(rule (alu_rs_imm_logic_commutative op ty x (def_inst (iconst (imm_logic_from_imm64 <ty imm))))
|
(rule (alu_rs_imm_logic_commutative op ty x (iconst k))
|
||||||
(alu_rr_imm_logic op ty (put_in_reg x) imm))
|
(if-let imm (imm_logic_from_imm64 ty k))
|
||||||
(rule (alu_rs_imm_logic_commutative op ty (def_inst (iconst (imm_logic_from_imm64 <ty imm))) x)
|
(alu_rr_imm_logic op ty x imm))
|
||||||
(alu_rr_imm_logic op ty (put_in_reg x) imm))
|
(rule (alu_rs_imm_logic_commutative op ty (iconst k) x)
|
||||||
|
(if-let imm (imm_logic_from_imm64 ty k))
|
||||||
|
(alu_rr_imm_logic op ty x imm))
|
||||||
|
|
||||||
;; Special cases for when one operand is shifted left by a constant.
|
;; Special cases for when one operand is shifted left by a constant.
|
||||||
(rule (alu_rs_imm_logic_commutative op ty x (def_inst (ishl y (def_inst (iconst (lshl_from_imm64 <ty amt))))))
|
(rule (alu_rs_imm_logic_commutative op ty x (ishl y (iconst k)))
|
||||||
(alu_rrr_shift op ty (put_in_reg x) (put_in_reg y) amt))
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
(rule (alu_rs_imm_logic_commutative op ty (def_inst (ishl x (def_inst (iconst (lshl_from_imm64 <ty amt))))) y)
|
(alu_rrr_shift op ty x y amt))
|
||||||
(alu_rrr_shift op ty (put_in_reg y) (put_in_reg x) amt))
|
(rule (alu_rs_imm_logic_commutative op ty (ishl x (iconst k)) y)
|
||||||
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
|
(alu_rrr_shift op ty y x amt))
|
||||||
|
|
||||||
;; Same as `alu_rs_imm_logic_commutative` above, except that it doesn't require
|
;; Same as `alu_rs_imm_logic_commutative` above, except that it doesn't require
|
||||||
;; that the operation is commutative.
|
;; that the operation is commutative.
|
||||||
(decl alu_rs_imm_logic (ALUOp Type Value Value) Reg)
|
(decl alu_rs_imm_logic (ALUOp Type Value Value) Reg)
|
||||||
(rule (alu_rs_imm_logic op ty x y)
|
(rule (alu_rs_imm_logic op ty x y)
|
||||||
(alu_rrr op ty (put_in_reg x) (put_in_reg y)))
|
(alu_rrr op ty x y))
|
||||||
(rule (alu_rs_imm_logic op ty x (def_inst (iconst (imm_logic_from_imm64 <ty imm))))
|
(rule (alu_rs_imm_logic op ty x (iconst k))
|
||||||
(alu_rr_imm_logic op ty (put_in_reg x) imm))
|
(if-let imm (imm_logic_from_imm64 ty k))
|
||||||
(rule (alu_rs_imm_logic op ty x (def_inst (ishl y (def_inst (iconst (lshl_from_imm64 <ty amt))))))
|
(alu_rr_imm_logic op ty x imm))
|
||||||
(alu_rrr_shift op ty (put_in_reg x) (put_in_reg y) amt))
|
(rule (alu_rs_imm_logic op ty x (ishl y (iconst k)))
|
||||||
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
|
(alu_rrr_shift op ty x y amt))
|
||||||
|
|
||||||
;; Helper for generating i128 bitops which simply do the same operation to the
|
;; Helper for generating i128 bitops which simply do the same operation to the
|
||||||
;; hi/lo registers.
|
;; hi/lo registers.
|
||||||
|
|||||||
@@ -56,11 +56,13 @@
|
|||||||
;; Special cases for when we're adding the shift of a different
|
;; Special cases for when we're adding the shift of a different
|
||||||
;; register by a constant amount and the shift can get folded into the add.
|
;; register by a constant amount and the shift can get folded into the add.
|
||||||
(rule (lower (has_type (fits_in_64 ty)
|
(rule (lower (has_type (fits_in_64 ty)
|
||||||
(iadd x (ishl y (iconst (lshl_from_imm64 <ty amt))))))
|
(iadd x (ishl y (iconst k)))))
|
||||||
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
(add_shift ty x y amt))
|
(add_shift ty x y amt))
|
||||||
|
|
||||||
(rule (lower (has_type (fits_in_64 ty)
|
(rule (lower (has_type (fits_in_64 ty)
|
||||||
(iadd (ishl x (iconst (lshl_from_imm64 <ty amt))) y)))
|
(iadd (ishl x (iconst k)) y)))
|
||||||
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
(add_shift ty y x amt))
|
(add_shift ty y x amt))
|
||||||
|
|
||||||
;; Fold an `iadd` and `imul` combination into a `madd` instruction.
|
;; Fold an `iadd` and `imul` combination into a `madd` instruction.
|
||||||
@@ -122,7 +124,8 @@
|
|||||||
;; Finally a special case for when we're subtracting the shift of a different
|
;; Finally a special case for when we're subtracting the shift of a different
|
||||||
;; register by a constant amount and the shift can get folded into the sub.
|
;; register by a constant amount and the shift can get folded into the sub.
|
||||||
(rule (lower (has_type (fits_in_64 ty)
|
(rule (lower (has_type (fits_in_64 ty)
|
||||||
(isub x (ishl y (iconst (lshl_from_imm64 <ty amt))))))
|
(isub x (ishl y (iconst k)))))
|
||||||
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
(sub_shift ty x y amt))
|
(sub_shift ty x y amt))
|
||||||
|
|
||||||
;; vectors
|
;; vectors
|
||||||
@@ -568,7 +571,8 @@
|
|||||||
;; Special case to use `orr_not_shift` if it's a `bnot` of a const-left-shifted
|
;; Special case to use `orr_not_shift` if it's a `bnot` of a const-left-shifted
|
||||||
;; value.
|
;; value.
|
||||||
(rule (lower (has_type (fits_in_64 ty)
|
(rule (lower (has_type (fits_in_64 ty)
|
||||||
(bnot (ishl x (iconst (lshl_from_imm64 <ty amt))))))
|
(bnot (ishl x (iconst k)))))
|
||||||
|
(if-let amt (lshl_from_imm64 ty k))
|
||||||
(orr_not_shift ty (zero_reg) x amt))
|
(orr_not_shift ty (zero_reg) x amt))
|
||||||
|
|
||||||
;; Implementation of `bnot` for `i128`.
|
;; Implementation of `bnot` for `i128`.
|
||||||
@@ -737,7 +741,8 @@
|
|||||||
;; Note that this rule explicitly has a higher priority than the others
|
;; Note that this rule explicitly has a higher priority than the others
|
||||||
;; to ensure it's attempted first, otherwise the type-based filters on the
|
;; to ensure it's attempted first, otherwise the type-based filters on the
|
||||||
;; previous rules seem to take priority over this rule.
|
;; previous rules seem to take priority over this rule.
|
||||||
(rule 1 (do_shift op ty x (iconst (imm_shift_from_imm64 <ty shift)))
|
(rule 1 (do_shift op ty x (iconst k))
|
||||||
|
(if-let shift (imm_shift_from_imm64 ty k))
|
||||||
(alu_rr_imm_shift op ty x shift))
|
(alu_rr_imm_shift op ty x shift))
|
||||||
|
|
||||||
;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Rules for `ushr` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -846,7 +851,8 @@
|
|||||||
(small_rotr ty (put_in_reg_zext32 x) neg_shift)))
|
(small_rotr ty (put_in_reg_zext32 x) neg_shift)))
|
||||||
|
|
||||||
;; Specialization for the 8/16-bit case when the rotation amount is an immediate.
|
;; Specialization for the 8/16-bit case when the rotation amount is an immediate.
|
||||||
(rule (lower (has_type (fits_in_16 ty) (rotl x (iconst (imm_shift_from_imm64 <ty n)))))
|
(rule (lower (has_type (fits_in_16 ty) (rotl x (iconst k))))
|
||||||
|
(if-let n (imm_shift_from_imm64 ty k))
|
||||||
(small_rotr_imm ty (put_in_reg_zext32 x) (negate_imm_shift ty n)))
|
(small_rotr_imm ty (put_in_reg_zext32 x) (negate_imm_shift ty n)))
|
||||||
|
|
||||||
;; aarch64 doesn't have a left-rotate instruction, but a left rotation of K
|
;; aarch64 doesn't have a left-rotate instruction, but a left rotation of K
|
||||||
@@ -868,11 +874,13 @@
|
|||||||
(a64_rotr $I64 x neg_shift)))
|
(a64_rotr $I64 x neg_shift)))
|
||||||
|
|
||||||
;; Specialization for the 32-bit case when the rotation amount is an immediate.
|
;; Specialization for the 32-bit case when the rotation amount is an immediate.
|
||||||
(rule (lower (has_type $I32 (rotl x (iconst (imm_shift_from_imm64 <$I32 n)))))
|
(rule (lower (has_type $I32 (rotl x (iconst k))))
|
||||||
|
(if-let n (imm_shift_from_imm64 $I32 k))
|
||||||
(a64_rotr_imm $I32 x (negate_imm_shift $I32 n)))
|
(a64_rotr_imm $I32 x (negate_imm_shift $I32 n)))
|
||||||
|
|
||||||
;; Specialization for the 64-bit case when the rotation amount is an immediate.
|
;; Specialization for the 64-bit case when the rotation amount is an immediate.
|
||||||
(rule (lower (has_type $I64 (rotl x (iconst (imm_shift_from_imm64 <$I64 n)))))
|
(rule (lower (has_type $I64 (rotl x (iconst k))))
|
||||||
|
(if-let n (imm_shift_from_imm64 $I64 k))
|
||||||
(a64_rotr_imm $I64 x (negate_imm_shift $I64 n)))
|
(a64_rotr_imm $I64 x (negate_imm_shift $I64 n)))
|
||||||
|
|
||||||
(decl negate_imm_shift (Type ImmShift) ImmShift)
|
(decl negate_imm_shift (Type ImmShift) ImmShift)
|
||||||
@@ -906,15 +914,18 @@
|
|||||||
(a64_rotr $I64 x y))
|
(a64_rotr $I64 x y))
|
||||||
|
|
||||||
;; Specialization for the 8/16-bit case when the rotation amount is an immediate.
|
;; Specialization for the 8/16-bit case when the rotation amount is an immediate.
|
||||||
(rule (lower (has_type (fits_in_16 ty) (rotr x (iconst (imm_shift_from_imm64 <ty n)))))
|
(rule (lower (has_type (fits_in_16 ty) (rotr x (iconst k))))
|
||||||
|
(if-let n (imm_shift_from_imm64 ty k))
|
||||||
(small_rotr_imm ty (put_in_reg_zext32 x) n))
|
(small_rotr_imm ty (put_in_reg_zext32 x) n))
|
||||||
|
|
||||||
;; Specialization for the 32-bit case when the rotation amount is an immediate.
|
;; Specialization for the 32-bit case when the rotation amount is an immediate.
|
||||||
(rule (lower (has_type $I32 (rotr x (iconst (imm_shift_from_imm64 <$I32 n)))))
|
(rule (lower (has_type $I32 (rotr x (iconst k))))
|
||||||
|
(if-let n (imm_shift_from_imm64 $I32 k))
|
||||||
(a64_rotr_imm $I32 x n))
|
(a64_rotr_imm $I32 x n))
|
||||||
|
|
||||||
;; Specialization for the 64-bit case when the rotation amount is an immediate.
|
;; Specialization for the 64-bit case when the rotation amount is an immediate.
|
||||||
(rule (lower (has_type $I64 (rotr x (iconst (imm_shift_from_imm64 <$I64 n)))))
|
(rule (lower (has_type $I64 (rotr x (iconst k))))
|
||||||
|
(if-let n (imm_shift_from_imm64 $I64 k))
|
||||||
(a64_rotr_imm $I64 x n))
|
(a64_rotr_imm $I64 x n))
|
||||||
|
|
||||||
;; For a < 32-bit rotate-right, we synthesize this as:
|
;; For a < 32-bit rotate-right, we synthesize this as:
|
||||||
|
|||||||
@@ -83,13 +83,13 @@ where
|
|||||||
MoveWideConst::maybe_from_u64(!n)
|
MoveWideConst::maybe_from_u64(!n)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn imm_logic_from_u64(&mut self, n: u64, ty: Type) -> Option<ImmLogic> {
|
fn imm_logic_from_u64(&mut self, ty: Type, n: u64) -> Option<ImmLogic> {
|
||||||
let ty = if ty.bits() < 32 { I32 } else { ty };
|
let ty = if ty.bits() < 32 { I32 } else { ty };
|
||||||
ImmLogic::maybe_from_u64(n, ty)
|
ImmLogic::maybe_from_u64(n, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn imm_logic_from_imm64(&mut self, n: Imm64, ty: Type) -> Option<ImmLogic> {
|
fn imm_logic_from_imm64(&mut self, ty: Type, n: Imm64) -> Option<ImmLogic> {
|
||||||
self.imm_logic_from_u64(n.bits() as u64, ty)
|
self.imm_logic_from_u64(ty, n.bits() as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn imm12_from_u64(&mut self, n: u64) -> Option<Imm12> {
|
fn imm12_from_u64(&mut self, n: u64) -> Option<Imm12> {
|
||||||
@@ -104,7 +104,7 @@ where
|
|||||||
ImmShift::maybe_from_u64(n.into()).unwrap()
|
ImmShift::maybe_from_u64(n.into()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lshl_from_imm64(&mut self, n: Imm64, ty: Type) -> Option<ShiftOpAndAmt> {
|
fn lshl_from_imm64(&mut self, ty: Type, n: Imm64) -> Option<ShiftOpAndAmt> {
|
||||||
let shiftimm = ShiftOpShiftImm::maybe_from_shift(n.bits() as u64)?;
|
let shiftimm = ShiftOpShiftImm::maybe_from_shift(n.bits() as u64)?;
|
||||||
let shiftee_bits = ty_bits(ty);
|
let shiftee_bits = ty_bits(ty);
|
||||||
if shiftee_bits <= std::u8::MAX as usize {
|
if shiftee_bits <= std::u8::MAX as usize {
|
||||||
@@ -292,7 +292,7 @@ where
|
|||||||
ImmLogic::maybe_from_u64(mask, I32).unwrap()
|
ImmLogic::maybe_from_u64(mask, I32).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn imm_shift_from_imm64(&mut self, val: Imm64, ty: Type) -> Option<ImmShift> {
|
fn imm_shift_from_imm64(&mut self, ty: Type, val: Imm64) -> Option<ImmShift> {
|
||||||
let imm_value = (val.bits() as u64) & ((ty.bits() - 1) as u64);
|
let imm_value = (val.bits() as u64) & ((ty.bits() - 1) as u64);
|
||||||
ImmShift::maybe_from_u64(imm_value)
|
ImmShift::maybe_from_u64(imm_value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle 443b34b797fc8ace
|
src/clif.isle 443b34b797fc8ace
|
||||||
src/prelude.isle a7915a6b88310eb5
|
src/prelude.isle a7915a6b88310eb5
|
||||||
src/isa/aarch64/inst.isle a2c0ae729bfa24a8
|
src/isa/aarch64/inst.isle 21a43af20be377d2
|
||||||
src/isa/aarch64/lower.isle 15641ca7f0ac061a
|
src/isa/aarch64/lower.isle 75ad8450963e3829
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -937,14 +937,18 @@
|
|||||||
|
|
||||||
;; Detect specific integer values
|
;; Detect specific integer values
|
||||||
|
|
||||||
(decl i64_nonequal (i64 i64) i64)
|
(decl pure i64_nonequal (i64 i64) i64)
|
||||||
(extern extractor i64_nonequal i64_nonequal (out in))
|
(extern constructor i64_nonequal i64_nonequal)
|
||||||
|
|
||||||
(decl i64_nonzero (i64) i64)
|
(decl pure i64_nonzero (i64) i64)
|
||||||
(extractor (i64_nonzero val) (i64_nonequal val <0))
|
(rule (i64_nonzero x)
|
||||||
|
(if (i64_nonequal x 0))
|
||||||
|
x)
|
||||||
|
|
||||||
(decl i64_not_neg1 (i64) i64)
|
(decl pure i64_not_neg1 (i64) i64)
|
||||||
(extractor (i64_not_neg1 val) (i64_nonequal val <-1))
|
(rule (i64_not_neg1 x)
|
||||||
|
(if (i64_nonequal x -1))
|
||||||
|
x)
|
||||||
|
|
||||||
;; Integer type casts (with the rust `as` semantics).
|
;; Integer type casts (with the rust `as` semantics).
|
||||||
|
|
||||||
@@ -1116,12 +1120,13 @@
|
|||||||
|
|
||||||
;; Form the sum of two offset values, and check that the result is
|
;; 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).
|
;; a valid `MemArg::Symbol` offset (i.e. is even and fits into i32).
|
||||||
(decl memarg_symbol_offset_sum (i64 i32) i64)
|
(decl pure memarg_symbol_offset_sum (i64 i64) i32)
|
||||||
(extern extractor memarg_symbol_offset_sum memarg_symbol_offset_sum (in out))
|
(extern constructor memarg_symbol_offset_sum memarg_symbol_offset_sum)
|
||||||
|
|
||||||
;; Likewise, but just check a single offset value.
|
;; Likewise, but just check a single offset value.
|
||||||
(decl memarg_symbol_offset (i32) i64)
|
(decl pure memarg_symbol_offset (i64) i32)
|
||||||
(extractor (memarg_symbol_offset offset) (memarg_symbol_offset_sum <0 offset))
|
(rule (memarg_symbol_offset x)
|
||||||
|
(memarg_symbol_offset_sum x 0))
|
||||||
|
|
||||||
;; Lower an address into a `MemArg`.
|
;; Lower an address into a `MemArg`.
|
||||||
|
|
||||||
@@ -1130,29 +1135,33 @@
|
|||||||
(rule (lower_address flags addr (i64_from_offset offset))
|
(rule (lower_address flags addr (i64_from_offset offset))
|
||||||
(memarg_reg_plus_off addr offset flags))
|
(memarg_reg_plus_off addr offset flags))
|
||||||
|
|
||||||
(rule (lower_address flags (def_inst (iadd x y)) (i64_from_offset 0))
|
(rule (lower_address flags (iadd x y) (i64_from_offset 0))
|
||||||
(memarg_reg_plus_reg x y flags))
|
(memarg_reg_plus_reg x y flags))
|
||||||
|
|
||||||
(rule (lower_address flags
|
(rule (lower_address flags
|
||||||
(def_inst (symbol_value (symbol_value_data name (reloc_distance_near) offset)))
|
(symbol_value (symbol_value_data name (reloc_distance_near) sym_offset))
|
||||||
(i64_from_offset (memarg_symbol_offset_sum <offset final_offset)))
|
(i64_from_offset offset))
|
||||||
|
(if-let final_offset (memarg_symbol_offset_sum offset sym_offset))
|
||||||
(memarg_symbol name final_offset flags))
|
(memarg_symbol name final_offset flags))
|
||||||
|
|
||||||
|
|
||||||
;; Test whether a `load` address will be lowered to a `MemArg::Symbol`.
|
;; Test whether a `load` address will be lowered to a `MemArg::Symbol`.
|
||||||
|
|
||||||
(decl load_sym (Inst) Inst)
|
(decl pure load_sym (Inst) Inst)
|
||||||
(extractor (load_sym inst)
|
(rule (load_sym inst)
|
||||||
(and inst
|
(if-let (load _ (symbol_value (symbol_value_data _ (reloc_distance_near) sym_offset))
|
||||||
(load _ (def_inst (symbol_value (symbol_value_data _ (reloc_distance_near) offset)))
|
(i64_from_offset load_offset))
|
||||||
(i64_from_offset (memarg_symbol_offset_sum <offset _)))))
|
inst)
|
||||||
|
(if (memarg_symbol_offset_sum sym_offset load_offset))
|
||||||
(decl uload16_sym (Inst) Inst)
|
inst)
|
||||||
(extractor (uload16_sym inst)
|
|
||||||
(and inst
|
|
||||||
(uload16 _ (def_inst (symbol_value (symbol_value_data _ (reloc_distance_near) offset)))
|
|
||||||
(i64_from_offset (memarg_symbol_offset_sum <offset _)))))
|
|
||||||
|
|
||||||
|
(decl pure 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))
|
||||||
|
inst)
|
||||||
|
(if (memarg_symbol_offset_sum sym_offset load_offset))
|
||||||
|
inst)
|
||||||
|
|
||||||
;; Helpers for stack-slot addresses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Helpers for stack-slot addresses ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
@@ -1170,11 +1179,11 @@
|
|||||||
|
|
||||||
;; A value that is the result of a sign-extend from a 32-bit value.
|
;; A value that is the result of a sign-extend from a 32-bit value.
|
||||||
(decl sext32_value (Value) Value)
|
(decl sext32_value (Value) Value)
|
||||||
(extractor (sext32_value x) (def_inst (sextend (and x (value_type $I32)))))
|
(extractor (sext32_value x) (sextend (and x (value_type $I32))))
|
||||||
|
|
||||||
;; A value that is the result of a zero-extend from a 32-bit value.
|
;; A value that is the result of a zero-extend from a 32-bit value.
|
||||||
(decl zext32_value (Value) Value)
|
(decl zext32_value (Value) Value)
|
||||||
(extractor (zext32_value x) (def_inst (uextend (and x (value_type $I32)))))
|
(extractor (zext32_value x) (uextend (and x (value_type $I32))))
|
||||||
|
|
||||||
|
|
||||||
;; Helpers for sinkable loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Helpers for sinkable loads ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1777,8 +1786,8 @@
|
|||||||
;; Similarly, because we cannot allocate temp registers, if an instruction
|
;; Similarly, because we cannot allocate temp registers, if an instruction
|
||||||
;; requires matching source and destination registers, this needs to be handled
|
;; requires matching source and destination registers, this needs to be handled
|
||||||
;; by the user. Another helper to verify that constraint.
|
;; by the user. Another helper to verify that constraint.
|
||||||
(decl same_reg (WritableReg) Reg)
|
(decl pure same_reg (WritableReg Reg) Reg)
|
||||||
(extern extractor same_reg same_reg (in))
|
(extern constructor same_reg same_reg)
|
||||||
|
|
||||||
;; Push a `MInst.AluRRR` instruction to a sequence.
|
;; Push a `MInst.AluRRR` instruction to a sequence.
|
||||||
(decl push_alu_reg (VecMInstBuilder ALUOp WritableReg Reg Reg) Reg)
|
(decl push_alu_reg (VecMInstBuilder ALUOp WritableReg Reg Reg) Reg)
|
||||||
@@ -1788,7 +1797,8 @@
|
|||||||
|
|
||||||
;; Push a `MInst.AluRUImm32Shifted` instruction to a sequence.
|
;; Push a `MInst.AluRUImm32Shifted` instruction to a sequence.
|
||||||
(decl push_alu_uimm32shifted (VecMInstBuilder ALUOp WritableReg Reg UImm32Shifted) Reg)
|
(decl push_alu_uimm32shifted (VecMInstBuilder ALUOp WritableReg Reg UImm32Shifted) Reg)
|
||||||
(rule (push_alu_uimm32shifted ib op (real_reg dst) (same_reg <dst) imm)
|
(rule (push_alu_uimm32shifted ib op (real_reg dst) r imm)
|
||||||
|
(if (same_reg dst r))
|
||||||
(let ((_ Unit (inst_builder_push ib (MInst.AluRUImm32Shifted op dst imm))))
|
(let ((_ Unit (inst_builder_push ib (MInst.AluRUImm32Shifted op dst imm))))
|
||||||
dst))
|
dst))
|
||||||
|
|
||||||
@@ -1801,7 +1811,8 @@
|
|||||||
|
|
||||||
;; Push a `MInst.RxSBG` instruction to a sequence.
|
;; Push a `MInst.RxSBG` instruction to a sequence.
|
||||||
(decl push_rxsbg (VecMInstBuilder RxSBGOp WritableReg Reg Reg u8 u8 i8) Reg)
|
(decl push_rxsbg (VecMInstBuilder RxSBGOp WritableReg Reg Reg u8 u8 i8) Reg)
|
||||||
(rule (push_rxsbg ib op (real_reg dst) (same_reg <dst) src start_bit end_bit rotate_amt)
|
(rule (push_rxsbg ib op (real_reg dst) r src start_bit end_bit rotate_amt)
|
||||||
|
(if (same_reg dst r))
|
||||||
(let ((_ Unit (inst_builder_push ib
|
(let ((_ Unit (inst_builder_push ib
|
||||||
(MInst.RxSBG op dst src start_bit end_bit rotate_amt))))
|
(MInst.RxSBG op dst src start_bit end_bit rotate_amt))))
|
||||||
dst))
|
dst))
|
||||||
@@ -2088,9 +2099,9 @@
|
|||||||
(rule (emit_put_in_reg_zext32 dst (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
(rule (emit_put_in_reg_zext32 dst (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
||||||
(emit_zext32_mem dst ty (sink_load load)))
|
(emit_zext32_mem dst ty (sink_load load)))
|
||||||
(rule (emit_put_in_reg_zext32 dst val @ (value_type (fits_in_16 ty)))
|
(rule (emit_put_in_reg_zext32 dst val @ (value_type (fits_in_16 ty)))
|
||||||
(emit_zext32_reg dst ty (put_in_reg val)))
|
(emit_zext32_reg dst ty val))
|
||||||
(rule (emit_put_in_reg_zext32 dst val @ (value_type (ty_32_or_64 ty)))
|
(rule (emit_put_in_reg_zext32 dst val @ (value_type (ty_32_or_64 ty)))
|
||||||
(emit_mov ty dst (put_in_reg val)))
|
(emit_mov ty dst val))
|
||||||
|
|
||||||
;; Place `Value` into destination, sign-extending to 32 bits if smaller. (Non-SSA form.)
|
;; Place `Value` into destination, sign-extending to 32 bits if smaller. (Non-SSA form.)
|
||||||
(decl emit_put_in_reg_sext32 (WritableReg Value) Unit)
|
(decl emit_put_in_reg_sext32 (WritableReg Value) Unit)
|
||||||
@@ -2099,9 +2110,9 @@
|
|||||||
(rule (emit_put_in_reg_sext32 dst (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
(rule (emit_put_in_reg_sext32 dst (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
||||||
(emit_sext32_mem dst ty (sink_load load)))
|
(emit_sext32_mem dst ty (sink_load load)))
|
||||||
(rule (emit_put_in_reg_sext32 dst val @ (value_type (fits_in_16 ty)))
|
(rule (emit_put_in_reg_sext32 dst val @ (value_type (fits_in_16 ty)))
|
||||||
(emit_sext32_reg dst ty (put_in_reg val)))
|
(emit_sext32_reg dst ty val))
|
||||||
(rule (emit_put_in_reg_sext32 dst val @ (value_type (ty_32_or_64 ty)))
|
(rule (emit_put_in_reg_sext32 dst val @ (value_type (ty_32_or_64 ty)))
|
||||||
(emit_mov ty dst (put_in_reg val)))
|
(emit_mov ty dst val))
|
||||||
|
|
||||||
;; Place `Value` into destination, zero-extending to 64 bits if smaller. (Non-SSA form.)
|
;; Place `Value` into destination, zero-extending to 64 bits if smaller. (Non-SSA form.)
|
||||||
(decl emit_put_in_reg_zext64 (WritableReg Value) Unit)
|
(decl emit_put_in_reg_zext64 (WritableReg Value) Unit)
|
||||||
@@ -2110,9 +2121,9 @@
|
|||||||
(rule (emit_put_in_reg_zext64 dst (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
(rule (emit_put_in_reg_zext64 dst (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
||||||
(emit_zext64_mem dst ty (sink_load load)))
|
(emit_zext64_mem dst ty (sink_load load)))
|
||||||
(rule (emit_put_in_reg_zext64 dst val @ (value_type (gpr32_ty ty)))
|
(rule (emit_put_in_reg_zext64 dst val @ (value_type (gpr32_ty ty)))
|
||||||
(emit_zext64_reg dst ty (put_in_reg val)))
|
(emit_zext64_reg dst ty val))
|
||||||
(rule (emit_put_in_reg_zext64 dst val @ (value_type (gpr64_ty ty)))
|
(rule (emit_put_in_reg_zext64 dst val @ (value_type (gpr64_ty ty)))
|
||||||
(emit_mov ty dst (put_in_reg val)))
|
(emit_mov ty dst val))
|
||||||
|
|
||||||
;; Place `Value` into destination, sign-extending to 64 bits if smaller. (Non-SSA form.)
|
;; Place `Value` into destination, sign-extending to 64 bits if smaller. (Non-SSA form.)
|
||||||
(decl emit_put_in_reg_sext64 (WritableReg Value) Unit)
|
(decl emit_put_in_reg_sext64 (WritableReg Value) Unit)
|
||||||
@@ -2121,9 +2132,9 @@
|
|||||||
(rule (emit_put_in_reg_sext64 dst (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
(rule (emit_put_in_reg_sext64 dst (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
||||||
(emit_sext64_mem dst ty (sink_load load)))
|
(emit_sext64_mem dst ty (sink_load load)))
|
||||||
(rule (emit_put_in_reg_sext64 dst val @ (value_type (gpr32_ty ty)))
|
(rule (emit_put_in_reg_sext64 dst val @ (value_type (gpr32_ty ty)))
|
||||||
(emit_sext64_reg dst ty (put_in_reg val)))
|
(emit_sext64_reg dst ty val))
|
||||||
(rule (emit_put_in_reg_sext64 dst val @ (value_type (gpr64_ty ty)))
|
(rule (emit_put_in_reg_sext64 dst val @ (value_type (gpr64_ty ty)))
|
||||||
(emit_mov ty dst (put_in_reg val)))
|
(emit_mov ty dst val))
|
||||||
|
|
||||||
;; Place `Value` into a register, zero-extending to 32 bits if smaller.
|
;; Place `Value` into a register, zero-extending to 32 bits if smaller.
|
||||||
(decl put_in_reg_zext32 (Value) Reg)
|
(decl put_in_reg_zext32 (Value) Reg)
|
||||||
@@ -2132,9 +2143,9 @@
|
|||||||
(rule (put_in_reg_zext32 (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
(rule (put_in_reg_zext32 (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
||||||
(zext32_mem ty (sink_load load)))
|
(zext32_mem ty (sink_load load)))
|
||||||
(rule (put_in_reg_zext32 val @ (value_type (fits_in_16 ty)))
|
(rule (put_in_reg_zext32 val @ (value_type (fits_in_16 ty)))
|
||||||
(zext32_reg ty (put_in_reg val)))
|
(zext32_reg ty val))
|
||||||
(rule (put_in_reg_zext32 val @ (value_type (ty_32_or_64 _ty)))
|
(rule (put_in_reg_zext32 val @ (value_type (ty_32_or_64 _ty)))
|
||||||
(put_in_reg val))
|
val)
|
||||||
|
|
||||||
;; Place `Value` into a register, sign-extending to 32 bits if smaller.
|
;; Place `Value` into a register, sign-extending to 32 bits if smaller.
|
||||||
(decl put_in_reg_sext32 (Value) Reg)
|
(decl put_in_reg_sext32 (Value) Reg)
|
||||||
@@ -2143,9 +2154,9 @@
|
|||||||
(rule (put_in_reg_sext32 (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
(rule (put_in_reg_sext32 (and (value_type (fits_in_16 ty)) (sinkable_load load)))
|
||||||
(sext32_mem ty (sink_load load)))
|
(sext32_mem ty (sink_load load)))
|
||||||
(rule (put_in_reg_sext32 val @ (value_type (fits_in_16 ty)))
|
(rule (put_in_reg_sext32 val @ (value_type (fits_in_16 ty)))
|
||||||
(sext32_reg ty (put_in_reg val)))
|
(sext32_reg ty val))
|
||||||
(rule (put_in_reg_sext32 val @ (value_type (ty_32_or_64 _ty)))
|
(rule (put_in_reg_sext32 val @ (value_type (ty_32_or_64 _ty)))
|
||||||
(put_in_reg val))
|
val)
|
||||||
|
|
||||||
;; Place `Value` into a register, zero-extending to 64 bits if smaller.
|
;; Place `Value` into a register, zero-extending to 64 bits if smaller.
|
||||||
(decl put_in_reg_zext64 (Value) Reg)
|
(decl put_in_reg_zext64 (Value) Reg)
|
||||||
@@ -2154,9 +2165,9 @@
|
|||||||
(rule (put_in_reg_zext64 (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
(rule (put_in_reg_zext64 (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
||||||
(zext64_mem ty (sink_load load)))
|
(zext64_mem ty (sink_load load)))
|
||||||
(rule (put_in_reg_zext64 val @ (value_type (gpr32_ty ty)))
|
(rule (put_in_reg_zext64 val @ (value_type (gpr32_ty ty)))
|
||||||
(zext64_reg ty (put_in_reg val)))
|
(zext64_reg ty val))
|
||||||
(rule (put_in_reg_zext64 val @ (value_type (gpr64_ty ty)))
|
(rule (put_in_reg_zext64 val @ (value_type (gpr64_ty ty)))
|
||||||
(put_in_reg val))
|
val)
|
||||||
|
|
||||||
;; Place `Value` into a register, sign-extending to 64 bits if smaller.
|
;; Place `Value` into a register, sign-extending to 64 bits if smaller.
|
||||||
(decl put_in_reg_sext64 (Value) Reg)
|
(decl put_in_reg_sext64 (Value) Reg)
|
||||||
@@ -2165,9 +2176,9 @@
|
|||||||
(rule (put_in_reg_sext64 (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
(rule (put_in_reg_sext64 (and (value_type (gpr32_ty ty)) (sinkable_load load)))
|
||||||
(sext64_mem ty (sink_load load)))
|
(sext64_mem ty (sink_load load)))
|
||||||
(rule (put_in_reg_sext64 val @ (value_type (gpr32_ty ty)))
|
(rule (put_in_reg_sext64 val @ (value_type (gpr32_ty ty)))
|
||||||
(sext64_reg ty (put_in_reg val)))
|
(sext64_reg ty val))
|
||||||
(rule (put_in_reg_sext64 val @ (value_type (gpr64_ty ty)))
|
(rule (put_in_reg_sext64 val @ (value_type (gpr64_ty ty)))
|
||||||
(put_in_reg val))
|
val)
|
||||||
|
|
||||||
;; Place `Value` into the low half of a register pair, zero-extending
|
;; Place `Value` into the low half of a register pair, zero-extending
|
||||||
;; to 32 bits if smaller. The high half is taken from the input.
|
;; to 32 bits if smaller. The high half is taken from the input.
|
||||||
|
|||||||
@@ -341,7 +341,9 @@
|
|||||||
;; If the `avoid_div_traps` flag is true, we perform the check explicitly.
|
;; If the `avoid_div_traps` flag is true, we perform the check explicitly.
|
||||||
;; This still can be omittted if the divisor is a non-zero immediate.
|
;; This still can be omittted if the divisor is a non-zero immediate.
|
||||||
(decl zero_divisor_check_needed (Value) bool)
|
(decl zero_divisor_check_needed (Value) bool)
|
||||||
(rule (zero_divisor_check_needed (i64_from_value (i64_nonzero _))) $false)
|
(rule (zero_divisor_check_needed (i64_from_value x))
|
||||||
|
(if (i64_nonzero x))
|
||||||
|
$false)
|
||||||
(rule (zero_divisor_check_needed (value_type (allow_div_traps))) $false)
|
(rule (zero_divisor_check_needed (value_type (allow_div_traps))) $false)
|
||||||
(rule (zero_divisor_check_needed _) $true)
|
(rule (zero_divisor_check_needed _) $true)
|
||||||
|
|
||||||
@@ -422,7 +424,9 @@
|
|||||||
;; minimum (signed) integer value is divided by -1, so if the divisor
|
;; minimum (signed) integer value is divided by -1, so if the divisor
|
||||||
;; is any immediate different from -1, the check can be omitted.
|
;; is any immediate different from -1, the check can be omitted.
|
||||||
(decl div_overflow_check_needed (Value) bool)
|
(decl div_overflow_check_needed (Value) bool)
|
||||||
(rule (div_overflow_check_needed (i64_from_value (i64_not_neg1 _))) $false)
|
(rule (div_overflow_check_needed (i64_from_value x))
|
||||||
|
(if (i64_not_neg1 x))
|
||||||
|
$false)
|
||||||
(rule (div_overflow_check_needed _) $true)
|
(rule (div_overflow_check_needed _) $true)
|
||||||
|
|
||||||
;; Perform the integer-overflow check if necessary. This implements:
|
;; Perform the integer-overflow check if necessary. This implements:
|
||||||
@@ -1168,7 +1172,8 @@
|
|||||||
|
|
||||||
;; Load the address of a symbol, target reachable via PC-relative instruction.
|
;; Load the address of a symbol, target reachable via PC-relative instruction.
|
||||||
(rule (lower (symbol_value (symbol_value_data name (reloc_distance_near)
|
(rule (lower (symbol_value (symbol_value_data name (reloc_distance_near)
|
||||||
(memarg_symbol_offset offset))))
|
off)))
|
||||||
|
(if-let offset (memarg_symbol_offset off))
|
||||||
(load_addr (memarg_symbol name offset (memflags_trusted))))
|
(load_addr (memarg_symbol name offset (memflags_trusted))))
|
||||||
|
|
||||||
;; Load the address of a symbol, general case.
|
;; Load the address of a symbol, general case.
|
||||||
@@ -1984,14 +1989,16 @@
|
|||||||
;; Note that the ISA only provides instructions with a PC-relative memory
|
;; Note that the ISA only provides instructions with a PC-relative memory
|
||||||
;; address here, so we need to check whether the sinkable load matches this.
|
;; address here, so we need to check whether the sinkable load matches this.
|
||||||
(rule (icmpu_val $true x @ (value_type (fits_in_64 ty))
|
(rule (icmpu_val $true x @ (value_type (fits_in_64 ty))
|
||||||
(sinkable_load_16 (load_sym y)))
|
(sinkable_load_16 ld))
|
||||||
|
(if-let y (load_sym ld))
|
||||||
(icmpu_mem_zext16 (ty_ext32 ty) (put_in_reg_zext32 x) (sink_load y)))
|
(icmpu_mem_zext16 (ty_ext32 ty) (put_in_reg_zext32 x) (sink_load y)))
|
||||||
|
|
||||||
;; Compare (unsigned) a register and zero-extended memory.
|
;; Compare (unsigned) a register and zero-extended memory.
|
||||||
;; Note that the ISA only provides instructions with a PC-relative memory
|
;; Note that the ISA only provides instructions with a PC-relative memory
|
||||||
;; address here, so we need to check whether the sinkable load matches this.
|
;; address here, so we need to check whether the sinkable load matches this.
|
||||||
(rule (icmpu_val $true x @ (value_type (fits_in_64 ty))
|
(rule (icmpu_val $true x @ (value_type (fits_in_64 ty))
|
||||||
(sinkable_uload16 (uload16_sym y)))
|
(sinkable_uload16 ld))
|
||||||
|
(if-let y (uload16_sym ld))
|
||||||
(icmpu_mem_zext16 ty x (sink_uload16 y)))
|
(icmpu_mem_zext16 ty x (sink_uload16 y)))
|
||||||
(rule (icmpu_val $true x @ (value_type (fits_in_64 ty)) (sinkable_uload32 y))
|
(rule (icmpu_val $true x @ (value_type (fits_in_64 ty)) (sinkable_uload32 y))
|
||||||
(icmpu_mem_zext32 ty x (sink_uload32 y)))
|
(icmpu_mem_zext32 ty x (sink_uload32 y)))
|
||||||
|
|||||||
@@ -486,9 +486,9 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn same_reg(&mut self, src: Reg, dst: WritableReg) -> Option<()> {
|
fn same_reg(&mut self, dst: WritableReg, src: Reg) -> Option<Reg> {
|
||||||
if dst.to_reg() == src {
|
if dst.to_reg() == src {
|
||||||
Some(())
|
Some(src)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle 443b34b797fc8ace
|
src/clif.isle 443b34b797fc8ace
|
||||||
src/prelude.isle a7915a6b88310eb5
|
src/prelude.isle a7915a6b88310eb5
|
||||||
src/isa/s390x/inst.isle 8218bd9e8556446b
|
src/isa/s390x/inst.isle 36c2500563cdd4e6
|
||||||
src/isa/s390x/lower.isle 6a8de81f8dc4e568
|
src/isa/s390x/lower.isle e5c946ab8a265b77
|
||||||
|
|||||||
2199
cranelift/codegen/src/isa/s390x/lower/isle/generated_code.rs
generated
2199
cranelift/codegen/src/isa/s390x/lower/isle/generated_code.rs
generated
File diff suppressed because it is too large
Load Diff
@@ -793,8 +793,8 @@
|
|||||||
;; A helper to both check that the `Imm64` and `Offset32` values sum to less
|
;; 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
|
;; 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`.
|
;; zero-extended from `Type` up to 64 bits. This is useful for `to_amode`.
|
||||||
(decl sum_extend_fits_in_32_bits (Type Imm64 u32) Offset32)
|
(decl pure sum_extend_fits_in_32_bits (Type Imm64 Offset32) u32)
|
||||||
(extern extractor sum_extend_fits_in_32_bits sum_extend_fits_in_32_bits (in in out))
|
(extern constructor sum_extend_fits_in_32_bits sum_extend_fits_in_32_bits)
|
||||||
|
|
||||||
;; To generate an address for a memory access, we can pattern-match various CLIF
|
;; To generate an address for a memory access, we can pattern-match various CLIF
|
||||||
;; sub-trees to x64's complex addressing modes (`Amode`). In pseudo-code:
|
;; sub-trees to x64's complex addressing modes (`Amode`). In pseudo-code:
|
||||||
@@ -828,14 +828,18 @@
|
|||||||
;; extractor to check that the offset and constant value (`c`, the in
|
;; extractor to check that the offset and constant value (`c`, the in
|
||||||
;; parameter), when summed will fit into x64's 32-bit displacement, returned as
|
;; parameter), when summed will fit into x64's 32-bit displacement, returned as
|
||||||
;; `sum` (the out parameter). The syntax for this could be improved (TODO).
|
;; `sum` (the out parameter). The syntax for this could be improved (TODO).
|
||||||
(rule (to_amode flags (iadd (iconst c) base) _offset @ (sum_extend_fits_in_32_bits <$I64 <c sum))
|
(rule (to_amode flags (iadd (iconst c) base) offset)
|
||||||
|
(if-let sum (sum_extend_fits_in_32_bits $I64 c offset))
|
||||||
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
||||||
(rule (to_amode flags (iadd base (iconst c)) _offset @ (sum_extend_fits_in_32_bits <$I64 <c sum))
|
(rule (to_amode flags (iadd base (iconst c)) offset)
|
||||||
|
(if-let sum (sum_extend_fits_in_32_bits $I64 c offset))
|
||||||
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
||||||
;; ...matches (uextend(iconst c) ...); see notes above.
|
;; ...matches (uextend(iconst c) ...); see notes above.
|
||||||
(rule (to_amode flags (iadd (has_type ty (uextend (iconst c))) base) _offset @ (sum_extend_fits_in_32_bits <ty <c sum))
|
(rule (to_amode flags (iadd (has_type ty (uextend (iconst c))) base) offset)
|
||||||
|
(if-let sum (sum_extend_fits_in_32_bits $I64 c offset))
|
||||||
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
||||||
(rule (to_amode flags (iadd base (has_type ty (uextend (iconst c)))) _offset @ (sum_extend_fits_in_32_bits <ty <c sum))
|
(rule (to_amode flags (iadd base (has_type ty (uextend (iconst c)))) offset)
|
||||||
|
(if-let sum (sum_extend_fits_in_32_bits $I64 c offset))
|
||||||
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
(amode_imm_reg_flags sum (put_in_gpr base) flags))
|
||||||
;; ...else only matches (iadd(a b))
|
;; ...else only matches (iadd(a b))
|
||||||
(rule (to_amode flags (iadd base index) offset)
|
(rule (to_amode flags (iadd base index) offset)
|
||||||
|
|||||||
@@ -526,9 +526,9 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn sum_extend_fits_in_32_bits(
|
fn sum_extend_fits_in_32_bits(
|
||||||
&mut self,
|
&mut self,
|
||||||
offset: Offset32,
|
|
||||||
extend_from_ty: Type,
|
extend_from_ty: Type,
|
||||||
constant_value: Imm64,
|
constant_value: Imm64,
|
||||||
|
offset: Offset32,
|
||||||
) -> Option<u32> {
|
) -> Option<u32> {
|
||||||
let offset: i64 = offset.into();
|
let offset: i64 = offset.into();
|
||||||
let constant_value: u64 = constant_value.bits() as u64;
|
let constant_value: u64 = constant_value.bits() as u64;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
src/clif.isle 443b34b797fc8ace
|
src/clif.isle 443b34b797fc8ace
|
||||||
src/prelude.isle a7915a6b88310eb5
|
src/prelude.isle a7915a6b88310eb5
|
||||||
src/isa/x64/inst.isle a63b8ede292f2e20
|
src/isa/x64/inst.isle 65f15f51eefe0ce3
|
||||||
src/isa/x64/lower.isle 4c567e9157f84afb
|
src/isa/x64/lower.isle 4c567e9157f84afb
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1202,59 +1202,6 @@ If an extractor returns `None`, then the generated matching code
|
|||||||
proceeds just as if an enum variant match had failed: it moves on to
|
proceeds just as if an enum variant match had failed: it moves on to
|
||||||
try the next rule in turn.
|
try the next rule in turn.
|
||||||
|
|
||||||
#### Advanced Extractors: Arg-Polarity
|
|
||||||
|
|
||||||
There is one shortcoming in the extractor mechanism as defined so far:
|
|
||||||
there is no mechanism to provide additional context or "parameterize"
|
|
||||||
an external extractor; it only receives the term to deconstruct, with
|
|
||||||
no other parameters. For example, one might wish to write a
|
|
||||||
`(GetNthArg n arg_pattern)` extractor that matches on an instruction,
|
|
||||||
fetches the `n`th "arg" from it, and then returns that as the
|
|
||||||
extracted match result, allowing `arg_pattern` to match against it.
|
|
||||||
|
|
||||||
Inspired by Prolog, where argument data can flow in both directions
|
|
||||||
during "unification", we implement a limited form of bidirectionality
|
|
||||||
in ISLE for extractor arguments. Specifically, we can declare the
|
|
||||||
"polarity" of the arguments to an extractor so that some of the
|
|
||||||
arguments flow "in" rather than "out". This lets us provide data to
|
|
||||||
the extractor via expressions embedded in the pattern.
|
|
||||||
|
|
||||||
An example might make this more clear: we can define a term
|
|
||||||
|
|
||||||
```lisp
|
|
||||||
(decl GetNthArg (u32 Arg) Inst)
|
|
||||||
```
|
|
||||||
|
|
||||||
that we wish to use as in the example given above, and then we can define
|
|
||||||
an external extractor
|
|
||||||
|
|
||||||
```lisp
|
|
||||||
(extern extractor GetNthArg get_nth_arg (in out))
|
|
||||||
```
|
|
||||||
|
|
||||||
which indicates that `get_nth_arg()` will take parameters of `&Inst`
|
|
||||||
(the value being extracted) *and* `u32` (the in-arg), and return
|
|
||||||
`Option<(Arg,)>`, i.e., *just* the out-args.
|
|
||||||
|
|
||||||
In order to use this extractor, to avoid parse ambiguity (i.e., to
|
|
||||||
avoid the need for the parser to know argument polarity while it is
|
|
||||||
still parsing), we require special syntax for the in-argument so that
|
|
||||||
it is parsed as an expression: it must be prepended by `<`. So one
|
|
||||||
might use `GetNthArg` as follows:
|
|
||||||
|
|
||||||
```lisp
|
|
||||||
(rule (Lower (and
|
|
||||||
(Inst ...)
|
|
||||||
(GetNthArg <2 second_arg)))
|
|
||||||
...)
|
|
||||||
```
|
|
||||||
|
|
||||||
This functionality is meant to improve the expressive power of the
|
|
||||||
DSL, but is not intended to be commonly used outside of "binding" or
|
|
||||||
"library" ISLE code. In other words, because it is somewhat
|
|
||||||
non-intuitive, it is best to wrap it within friendlier internal
|
|
||||||
extractors.
|
|
||||||
|
|
||||||
### Mapping Type Declarations to Rust
|
### Mapping Type Declarations to Rust
|
||||||
|
|
||||||
When we declare a type like
|
When we declare a type like
|
||||||
@@ -1528,9 +1475,5 @@ newline). The grammar accepted by the parser is as follows:
|
|||||||
|
|
||||||
<extern> ::= "constructor" <ident> <ident>
|
<extern> ::= "constructor" <ident> <ident>
|
||||||
| "extractor" [ "infallible" ] <ident> <ident>
|
| "extractor" [ "infallible" ] <ident> <ident>
|
||||||
[ "(" <polarity>* ")" ]
|
|
||||||
| "const" <const-ident> <ident> <ty>
|
| "const" <const-ident> <ident> <ty>
|
||||||
|
|
||||||
<polarity> ::= "in" | "out"
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
(decl Op (Opcode) Inst)
|
(decl Op (Opcode) Inst)
|
||||||
(extern extractor infallible Op get_opcode)
|
(extern extractor infallible Op get_opcode)
|
||||||
|
|
||||||
(decl InstInput (InstInput u32) Inst)
|
(decl InstInputs2 (InstInput InstInput) Inst)
|
||||||
(extern extractor infallible InstInput get_inst_input (out in))
|
(extern extractor infallible InstInputs2 get_inst_inputs_2)
|
||||||
|
|
||||||
(decl Producer (Inst) InstInput)
|
(decl Producer (Inst) InstInput)
|
||||||
(extern extractor Producer get_input_producer)
|
(extern extractor Producer get_input_producer)
|
||||||
@@ -44,15 +44,13 @@
|
|||||||
(extractor
|
(extractor
|
||||||
(Iadd a b)
|
(Iadd a b)
|
||||||
(and
|
(and
|
||||||
(Op (Opcode.Iadd))
|
(Op (Opcode.Iadd))
|
||||||
(InstInput a <0)
|
(InstInputs2 a b)))
|
||||||
(InstInput b <1)))
|
|
||||||
(extractor
|
(extractor
|
||||||
(Isub a b)
|
(Isub a b)
|
||||||
(and
|
(and
|
||||||
(Op (Opcode.Isub))
|
(Op (Opcode.Isub))
|
||||||
(InstInput a <0)
|
(InstInputs2 a b)))
|
||||||
(InstInput b <1)))
|
|
||||||
|
|
||||||
;; Now the nice syntax-sugar that "end-user" backend authors can write:
|
;; Now the nice syntax-sugar that "end-user" backend authors can write:
|
||||||
(rule
|
(rule
|
||||||
@@ -63,4 +61,4 @@
|
|||||||
(MachInst.Add3 (UseInput ra) (UseInput rb) (UseInput rc)))
|
(MachInst.Add3 (UseInput ra) (UseInput rb) (UseInput rc)))
|
||||||
(rule
|
(rule
|
||||||
(Lower (Isub ra rb))
|
(Lower (Isub ra rb))
|
||||||
(MachInst.Sub (UseInput ra) (UseInput rb)))
|
(MachInst.Sub (UseInput ra) (UseInput rb)))
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ pub enum Pattern {
|
|||||||
/// An application of a type variant or term.
|
/// An application of a type variant or term.
|
||||||
Term {
|
Term {
|
||||||
sym: Ident,
|
sym: Ident,
|
||||||
args: Vec<TermArgPattern>,
|
args: Vec<Pattern>,
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
},
|
},
|
||||||
/// An operator that matches anything.
|
/// An operator that matches anything.
|
||||||
@@ -152,9 +152,7 @@ impl Pattern {
|
|||||||
Pattern::Term { sym, args, pos } => {
|
Pattern::Term { sym, args, pos } => {
|
||||||
f(*pos, sym);
|
f(*pos, sym);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let TermArgPattern::Pattern(p) = arg {
|
arg.terms(f);
|
||||||
p.terms(f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pattern::And { subpats, .. } => {
|
Pattern::And { subpats, .. } => {
|
||||||
@@ -291,41 +289,6 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A pattern in a term argument. Adds "evaluated expression" to kinds
|
|
||||||
/// of patterns in addition to all options in `Pattern`.
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub enum TermArgPattern {
|
|
||||||
/// A regular pattern that must match the existing value in the term's argument.
|
|
||||||
Pattern(Pattern),
|
|
||||||
/// An expression that is evaluated during the match phase and can
|
|
||||||
/// be given into an extractor. This is essentially a limited form
|
|
||||||
/// of unification or bidirectional argument flow (a la Prolog):
|
|
||||||
/// we can pass an arg *into* an extractor rather than getting the
|
|
||||||
/// arg *out of* it.
|
|
||||||
Expr(Expr),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TermArgPattern {
|
|
||||||
fn make_macro_template(&self, args: &[Ident]) -> TermArgPattern {
|
|
||||||
log::trace!("repplace_macro_args: {:?} with {:?}", self, args);
|
|
||||||
match self {
|
|
||||||
&TermArgPattern::Pattern(ref pat) => {
|
|
||||||
TermArgPattern::Pattern(pat.make_macro_template(args))
|
|
||||||
}
|
|
||||||
&TermArgPattern::Expr(_) => self.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subst_macro_args(&self, args: &[Pattern]) -> Option<TermArgPattern> {
|
|
||||||
match self {
|
|
||||||
&TermArgPattern::Pattern(ref pat) => {
|
|
||||||
Some(TermArgPattern::Pattern(pat.subst_macro_args(args)?))
|
|
||||||
}
|
|
||||||
&TermArgPattern::Expr(_) => Some(self.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An expression: the right-hand side of a rule.
|
/// An expression: the right-hand side of a rule.
|
||||||
///
|
///
|
||||||
/// Note that this *almost* looks like a core Lisp or lambda calculus,
|
/// Note that this *almost* looks like a core Lisp or lambda calculus,
|
||||||
@@ -405,15 +368,6 @@ pub enum Extern {
|
|||||||
func: Ident,
|
func: Ident,
|
||||||
/// The position of this decl.
|
/// The position of this decl.
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
/// Poliarity of args: whether values are inputs or outputs to
|
|
||||||
/// the external extractor function. This is a sort of
|
|
||||||
/// statically-defined approximation to Prolog-style
|
|
||||||
/// unification; we allow for the same flexible directionality
|
|
||||||
/// but fix it at DSL-definition time. By default, every arg
|
|
||||||
/// is an *output* from the extractor (and the 'retval", or
|
|
||||||
/// more precisely the term value that we are extracting, is
|
|
||||||
/// an "input").
|
|
||||||
arg_polarity: Option<Vec<ArgPolarity>>,
|
|
||||||
/// Infallibility: if an external extractor returns `(T1, T2,
|
/// Infallibility: if an external extractor returns `(T1, T2,
|
||||||
/// ...)` rather than `Option<(T1, T2, ...)>`, and hence can
|
/// ...)` rather than `Option<(T1, T2, ...)>`, and hence can
|
||||||
/// never fail, it is declared as such and allows for slightly
|
/// never fail, it is declared as such and allows for slightly
|
||||||
@@ -433,17 +387,6 @@ pub enum Extern {
|
|||||||
Const { name: Ident, ty: Ident, pos: Pos },
|
Const { name: Ident, ty: Ident, pos: Pos },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether an argument is an input or an output.
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
||||||
pub enum ArgPolarity {
|
|
||||||
/// An arg that must be given an Expr in the pattern and passes data *to*
|
|
||||||
/// the extractor op.
|
|
||||||
Input,
|
|
||||||
/// An arg that must be given a regular pattern (not Expr) and receives data
|
|
||||||
/// *from* the extractor op.
|
|
||||||
Output,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An implicit converter: the given term, which must have type
|
/// An implicit converter: the given term, which must have type
|
||||||
/// (inner_ty) -> outer_ty, is used either in extractor or constructor
|
/// (inner_ty) -> outer_ty, is used either in extractor or constructor
|
||||||
/// position as appropriate when a type mismatch with the given pair
|
/// position as appropriate when a type mismatch with the given pair
|
||||||
|
|||||||
@@ -387,12 +387,6 @@ impl PatternSequence {
|
|||||||
let arg_tys = &termdata.arg_tys[..];
|
let arg_tys = &termdata.arg_tys[..];
|
||||||
for (i, subpat) in args.iter().enumerate() {
|
for (i, subpat) in args.iter().enumerate() {
|
||||||
let value = self.add_arg(i, arg_tys[i]);
|
let value = self.add_arg(i, arg_tys[i]);
|
||||||
let subpat = match subpat {
|
|
||||||
&TermArgPattern::Expr(..) => {
|
|
||||||
panic!("Should have been caught in typechecking")
|
|
||||||
}
|
|
||||||
&TermArgPattern::Pattern(ref pat) => pat,
|
|
||||||
};
|
|
||||||
self.gen_pattern(
|
self.gen_pattern(
|
||||||
ValueOrArgs::Value(value),
|
ValueOrArgs::Value(value),
|
||||||
typeenv,
|
typeenv,
|
||||||
@@ -411,10 +405,6 @@ impl PatternSequence {
|
|||||||
let arg_values =
|
let arg_values =
|
||||||
self.add_match_variant(input, ty, arg_tys, *variant);
|
self.add_match_variant(input, ty, arg_tys, *variant);
|
||||||
for (subpat, value) in args.iter().zip(arg_values.into_iter()) {
|
for (subpat, value) in args.iter().zip(arg_values.into_iter()) {
|
||||||
let subpat = match subpat {
|
|
||||||
&TermArgPattern::Pattern(ref pat) => pat,
|
|
||||||
_ => unreachable!("Should have been caught by sema"),
|
|
||||||
};
|
|
||||||
self.gen_pattern(
|
self.gen_pattern(
|
||||||
ValueOrArgs::Value(value),
|
ValueOrArgs::Value(value),
|
||||||
typeenv,
|
typeenv,
|
||||||
@@ -438,11 +428,7 @@ impl PatternSequence {
|
|||||||
}
|
}
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
extractor_kind:
|
extractor_kind:
|
||||||
Some(ExtractorKind::ExternalExtractor {
|
Some(ExtractorKind::ExternalExtractor { infallible, .. }),
|
||||||
ref arg_polarity,
|
|
||||||
infallible,
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// Evaluate all `input` args.
|
// Evaluate all `input` args.
|
||||||
@@ -452,33 +438,9 @@ impl PatternSequence {
|
|||||||
let mut output_pats = vec![];
|
let mut output_pats = vec![];
|
||||||
inputs.push(input);
|
inputs.push(input);
|
||||||
input_tys.push(termdata.ret_ty);
|
input_tys.push(termdata.ret_ty);
|
||||||
for (arg, pol) in args.iter().zip(arg_polarity.iter()) {
|
for arg in args {
|
||||||
match pol {
|
output_tys.push(arg.ty());
|
||||||
&ArgPolarity::Input => {
|
output_pats.push(arg);
|
||||||
let expr = match arg {
|
|
||||||
&TermArgPattern::Expr(ref expr) => expr,
|
|
||||||
_ => panic!(
|
|
||||||
"Should have been caught by typechecking"
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let mut seq = ExprSequence::default();
|
|
||||||
let value = seq.gen_expr(typeenv, termenv, expr, vars);
|
|
||||||
seq.add_return(expr.ty(), value);
|
|
||||||
let value = self.add_expr_seq(seq, value, expr.ty());
|
|
||||||
inputs.push(value);
|
|
||||||
input_tys.push(expr.ty());
|
|
||||||
}
|
|
||||||
&ArgPolarity::Output => {
|
|
||||||
let pat = match arg {
|
|
||||||
&TermArgPattern::Pattern(ref pat) => pat,
|
|
||||||
_ => panic!(
|
|
||||||
"Should have been caught by typechecking"
|
|
||||||
),
|
|
||||||
};
|
|
||||||
output_tys.push(pat.ty());
|
|
||||||
output_pats.push(pat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the extractor.
|
// Invoke the extractor.
|
||||||
|
|||||||
@@ -66,8 +66,6 @@ pub enum Token {
|
|||||||
Int(i64),
|
Int(i64),
|
||||||
/// `@`
|
/// `@`
|
||||||
At,
|
At,
|
||||||
/// `<`
|
|
||||||
Lt,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lexer<'a> {
|
impl<'a> Lexer<'a> {
|
||||||
@@ -176,7 +174,7 @@ impl<'a> Lexer<'a> {
|
|||||||
fn next_token(&mut self) -> Result<Option<(Pos, Token)>> {
|
fn next_token(&mut self) -> Result<Option<(Pos, Token)>> {
|
||||||
fn is_sym_first_char(c: u8) -> bool {
|
fn is_sym_first_char(c: u8) -> bool {
|
||||||
match c {
|
match c {
|
||||||
b'-' | b'0'..=b'9' | b'(' | b')' | b';' => false,
|
b'-' | b'0'..=b'9' | b'(' | b')' | b';' | b'<' | b'>' => false,
|
||||||
c if c.is_ascii_whitespace() => false,
|
c if c.is_ascii_whitespace() => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
@@ -222,10 +220,6 @@ impl<'a> Lexer<'a> {
|
|||||||
self.advance_pos();
|
self.advance_pos();
|
||||||
Ok(Some((char_pos, Token::At)))
|
Ok(Some((char_pos, Token::At)))
|
||||||
}
|
}
|
||||||
b'<' => {
|
|
||||||
self.advance_pos();
|
|
||||||
Ok(Some((char_pos, Token::Lt)))
|
|
||||||
}
|
|
||||||
c if is_sym_first_char(c) => {
|
c if is_sym_first_char(c) => {
|
||||||
let start = self.pos.offset;
|
let start = self.pos.offset;
|
||||||
let start_pos = self.pos();
|
let start_pos = self.pos();
|
||||||
@@ -295,7 +289,7 @@ impl<'a> Lexer<'a> {
|
|||||||
};
|
};
|
||||||
Ok(Some((start_pos, tok)))
|
Ok(Some((start_pos, tok)))
|
||||||
}
|
}
|
||||||
c => panic!("Unexpected character '{}' at offset {}", c, self.pos.offset),
|
c => Err(self.error(self.pos, format!("Unexpected character '{}'", c))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,9 +77,6 @@ impl<'a> Parser<'a> {
|
|||||||
fn is_at(&self) -> bool {
|
fn is_at(&self) -> bool {
|
||||||
self.is(|tok| *tok == Token::At)
|
self.is(|tok| *tok == Token::At)
|
||||||
}
|
}
|
||||||
fn is_lt(&self) -> bool {
|
|
||||||
self.is(|tok| *tok == Token::Lt)
|
|
||||||
}
|
|
||||||
fn is_sym(&self) -> bool {
|
fn is_sym(&self) -> bool {
|
||||||
self.is(|tok| tok.is_sym())
|
self.is(|tok| tok.is_sym())
|
||||||
}
|
}
|
||||||
@@ -109,9 +106,6 @@ impl<'a> Parser<'a> {
|
|||||||
fn at(&mut self) -> Result<()> {
|
fn at(&mut self) -> Result<()> {
|
||||||
self.take(|tok| *tok == Token::At).map(|_| ())
|
self.take(|tok| *tok == Token::At).map(|_| ())
|
||||||
}
|
}
|
||||||
fn lt(&mut self) -> Result<()> {
|
|
||||||
self.take(|tok| *tok == Token::Lt).map(|_| ())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn symbol(&mut self) -> Result<String> {
|
fn symbol(&mut self) -> Result<String> {
|
||||||
match self.take(|tok| tok.is_sym())? {
|
match self.take(|tok| tok.is_sym())? {
|
||||||
@@ -338,30 +332,10 @@ impl<'a> Parser<'a> {
|
|||||||
let term = self.parse_ident()?;
|
let term = self.parse_ident()?;
|
||||||
let func = self.parse_ident()?;
|
let func = self.parse_ident()?;
|
||||||
|
|
||||||
let arg_polarity = if self.is_lparen() {
|
|
||||||
let mut pol = vec![];
|
|
||||||
self.lparen()?;
|
|
||||||
while !self.is_rparen() {
|
|
||||||
if self.is_sym_str("in") {
|
|
||||||
self.symbol()?;
|
|
||||||
pol.push(ArgPolarity::Input);
|
|
||||||
} else if self.is_sym_str("out") {
|
|
||||||
self.symbol()?;
|
|
||||||
pol.push(ArgPolarity::Output);
|
|
||||||
} else {
|
|
||||||
return Err(self.error(pos, "Invalid argument polarity".to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.rparen()?;
|
|
||||||
Some(pol)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok(Extern::Extractor {
|
Ok(Extern::Extractor {
|
||||||
term,
|
term,
|
||||||
func,
|
func,
|
||||||
pos,
|
pos,
|
||||||
arg_polarity,
|
|
||||||
infallible,
|
infallible,
|
||||||
})
|
})
|
||||||
} else if self.is_sym_str("const") {
|
} else if self.is_sym_str("const") {
|
||||||
@@ -461,7 +435,7 @@ impl<'a> Parser<'a> {
|
|||||||
let sym = self.parse_ident()?;
|
let sym = self.parse_ident()?;
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
while !self.is_rparen() {
|
while !self.is_rparen() {
|
||||||
args.push(self.parse_pattern_term_arg()?);
|
args.push(self.parse_pattern()?);
|
||||||
}
|
}
|
||||||
self.rparen()?;
|
self.rparen()?;
|
||||||
Ok(Pattern::Term { sym, args, pos })
|
Ok(Pattern::Term { sym, args, pos })
|
||||||
@@ -471,15 +445,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pattern_term_arg(&mut self) -> Result<TermArgPattern> {
|
|
||||||
if self.is_lt() {
|
|
||||||
self.lt()?;
|
|
||||||
Ok(TermArgPattern::Expr(self.parse_expr()?))
|
|
||||||
} else {
|
|
||||||
Ok(TermArgPattern::Pattern(self.parse_pattern()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_iflet_or_expr(&mut self) -> Result<IfLetOrExpr> {
|
fn parse_iflet_or_expr(&mut self) -> Result<IfLetOrExpr> {
|
||||||
let pos = self.pos();
|
let pos = self.pos();
|
||||||
if self.is_lparen() {
|
if self.is_lparen() {
|
||||||
|
|||||||
@@ -268,8 +268,6 @@ pub enum ExtractorKind {
|
|||||||
ExternalExtractor {
|
ExternalExtractor {
|
||||||
/// The external name of the extractor function.
|
/// The external name of the extractor function.
|
||||||
name: Sym,
|
name: Sym,
|
||||||
/// Which arguments of the extractor are inputs and which are outputs?
|
|
||||||
arg_polarity: Vec<ArgPolarity>,
|
|
||||||
/// Is the external extractor infallible?
|
/// Is the external extractor infallible?
|
||||||
infallible: bool,
|
infallible: bool,
|
||||||
/// The position where this external extractor was declared.
|
/// The position where this external extractor was declared.
|
||||||
@@ -277,8 +275,6 @@ pub enum ExtractorKind {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::ast::ArgPolarity;
|
|
||||||
|
|
||||||
/// An external function signature.
|
/// An external function signature.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ExternalSig {
|
pub struct ExternalSig {
|
||||||
@@ -357,34 +353,16 @@ impl Term {
|
|||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
extractor_kind:
|
extractor_kind:
|
||||||
Some(ExtractorKind::ExternalExtractor {
|
Some(ExtractorKind::ExternalExtractor {
|
||||||
name,
|
name, infallible, ..
|
||||||
ref arg_polarity,
|
|
||||||
infallible,
|
|
||||||
..
|
|
||||||
}),
|
}),
|
||||||
..
|
..
|
||||||
} => {
|
} => Some(ExternalSig {
|
||||||
let mut arg_tys = vec![];
|
func_name: tyenv.syms[name.index()].clone(),
|
||||||
let mut ret_tys = vec![];
|
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
||||||
arg_tys.push(self.ret_ty);
|
param_tys: vec![self.ret_ty],
|
||||||
for (&arg, polarity) in self.arg_tys.iter().zip(arg_polarity.iter()) {
|
ret_tys: self.arg_tys.clone(),
|
||||||
match polarity {
|
infallible: *infallible,
|
||||||
&ArgPolarity::Input => {
|
}),
|
||||||
arg_tys.push(arg);
|
|
||||||
}
|
|
||||||
&ArgPolarity::Output => {
|
|
||||||
ret_tys.push(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(ExternalSig {
|
|
||||||
func_name: tyenv.syms[name.index()].clone(),
|
|
||||||
full_name: format!("C::{}", tyenv.syms[name.index()]),
|
|
||||||
param_tys: arg_tys,
|
|
||||||
ret_tys,
|
|
||||||
infallible: *infallible,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -477,7 +455,7 @@ pub enum Pattern {
|
|||||||
|
|
||||||
/// Match the current value against the given extractor term with the given
|
/// Match the current value against the given extractor term with the given
|
||||||
/// arguments.
|
/// arguments.
|
||||||
Term(TypeId, TermId, Vec<TermArgPattern>),
|
Term(TypeId, TermId, Vec<Pattern>),
|
||||||
|
|
||||||
/// Match anything of the given type successfully.
|
/// Match anything of the given type successfully.
|
||||||
Wildcard(TypeId),
|
Wildcard(TypeId),
|
||||||
@@ -486,15 +464,6 @@ pub enum Pattern {
|
|||||||
And(TypeId, Vec<Pattern>),
|
And(TypeId, Vec<Pattern>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arguments to a term inside a pattern (i.e. an extractor).
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum TermArgPattern {
|
|
||||||
/// A pattern to match sub-values (i.e. the extractor's results) against.
|
|
||||||
Pattern(Pattern),
|
|
||||||
/// An expression to generate a value that is passed into the extractor.
|
|
||||||
Expr(Expr),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A right-hand side expression of some rule.
|
/// A right-hand side expression of some rule.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
@@ -1248,7 +1217,6 @@ impl TermEnv {
|
|||||||
ref term,
|
ref term,
|
||||||
ref func,
|
ref func,
|
||||||
pos,
|
pos,
|
||||||
ref arg_polarity,
|
|
||||||
infallible,
|
infallible,
|
||||||
}) => {
|
}) => {
|
||||||
let term_sym = tyenv.intern_mut(term);
|
let term_sym = tyenv.intern_mut(term);
|
||||||
@@ -1266,22 +1234,11 @@ impl TermEnv {
|
|||||||
|
|
||||||
let termdata = &mut self.terms[term_id.index()];
|
let termdata = &mut self.terms[term_id.index()];
|
||||||
|
|
||||||
let arg_polarity = if let Some(pol) = arg_polarity.as_ref() {
|
|
||||||
if pol.len() != termdata.arg_tys.len() {
|
|
||||||
tyenv.report_error(pos, "Incorrect number of argument-polarity directions in extractor definition".to_string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pol.clone()
|
|
||||||
} else {
|
|
||||||
vec![ArgPolarity::Output; termdata.arg_tys.len()]
|
|
||||||
};
|
|
||||||
|
|
||||||
match &mut termdata.kind {
|
match &mut termdata.kind {
|
||||||
TermKind::Decl { extractor_kind, .. } => match extractor_kind {
|
TermKind::Decl { extractor_kind, .. } => match extractor_kind {
|
||||||
None => {
|
None => {
|
||||||
*extractor_kind = Some(ExtractorKind::ExternalExtractor {
|
*extractor_kind = Some(ExtractorKind::ExternalExtractor {
|
||||||
name: func_sym,
|
name: func_sym,
|
||||||
arg_polarity,
|
|
||||||
infallible,
|
infallible,
|
||||||
pos,
|
pos,
|
||||||
});
|
});
|
||||||
@@ -1476,7 +1433,7 @@ impl TermEnv {
|
|||||||
let expanded_pattern = ast::Pattern::Term {
|
let expanded_pattern = ast::Pattern::Term {
|
||||||
sym: converter_term_ident,
|
sym: converter_term_ident,
|
||||||
pos: pattern.pos(),
|
pos: pattern.pos(),
|
||||||
args: vec![ast::TermArgPattern::Pattern(pattern.clone())],
|
args: vec![pattern.clone()],
|
||||||
};
|
};
|
||||||
|
|
||||||
return Some(expanded_pattern);
|
return Some(expanded_pattern);
|
||||||
@@ -1712,63 +1669,12 @@ impl TermEnv {
|
|||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
constructor_kind: Some(ConstructorKind::InternalConstructor),
|
constructor_kind: Some(ConstructorKind::InternalConstructor),
|
||||||
..
|
..
|
||||||
} if is_root && *tid == rule_term => {
|
} if is_root && *tid == rule_term => {}
|
||||||
// This is just the `(foo ...)` pseudo-pattern inside a
|
TermKind::EnumVariant { .. } => {}
|
||||||
// `(rule (foo ...) ...)` form. Just keep checking the
|
|
||||||
// sub-patterns.
|
|
||||||
for arg in args {
|
|
||||||
if let ast::TermArgPattern::Expr(e) = arg {
|
|
||||||
tyenv.report_error(
|
|
||||||
e.pos(),
|
|
||||||
"cannot use output-polarity expression with top-level rules"
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TermKind::EnumVariant { .. } => {
|
|
||||||
for arg in args {
|
|
||||||
if let &ast::TermArgPattern::Expr(_) = arg {
|
|
||||||
tyenv.report_error(
|
|
||||||
pos,
|
|
||||||
format!(
|
|
||||||
"Term in pattern '{}' cannot have an injected expr, because \
|
|
||||||
it is an enum variant",
|
|
||||||
sym.0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
extractor_kind:
|
extractor_kind: Some(ExtractorKind::ExternalExtractor { .. }),
|
||||||
Some(ExtractorKind::ExternalExtractor {
|
|
||||||
ref arg_polarity, ..
|
|
||||||
}),
|
|
||||||
..
|
..
|
||||||
} => {
|
} => {}
|
||||||
for (arg, pol) in args.iter().zip(arg_polarity.iter()) {
|
|
||||||
match (arg, pol) {
|
|
||||||
(&ast::TermArgPattern::Expr(..), &ArgPolarity::Input) => {}
|
|
||||||
(&ast::TermArgPattern::Expr(ref e), &ArgPolarity::Output) => {
|
|
||||||
tyenv.report_error(
|
|
||||||
e.pos(),
|
|
||||||
"Expression used for output-polarity extractor arg"
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(_, &ArgPolarity::Output) => {}
|
|
||||||
(&ast::TermArgPattern::Pattern(ref p), &ArgPolarity::Input) => {
|
|
||||||
tyenv.report_error(
|
|
||||||
p.pos(),
|
|
||||||
"Non-expression used in pattern but expression required for \
|
|
||||||
input-polarity extractor arg"
|
|
||||||
.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TermKind::Decl {
|
TermKind::Decl {
|
||||||
extractor_kind: Some(ExtractorKind::InternalExtractor { ref template }),
|
extractor_kind: Some(ExtractorKind::InternalExtractor { ref template }),
|
||||||
..
|
..
|
||||||
@@ -1779,19 +1685,7 @@ impl TermEnv {
|
|||||||
// substitutions.
|
// substitutions.
|
||||||
let mut macro_args: Vec<ast::Pattern> = vec![];
|
let mut macro_args: Vec<ast::Pattern> = vec![];
|
||||||
for template_arg in args {
|
for template_arg in args {
|
||||||
let sub_ast = match template_arg {
|
macro_args.push(template_arg.clone());
|
||||||
&ast::TermArgPattern::Pattern(ref pat) => pat.clone(),
|
|
||||||
&ast::TermArgPattern::Expr(_) => {
|
|
||||||
tyenv.report_error(
|
|
||||||
pos,
|
|
||||||
"Cannot expand an extractor macro with an expression in a \
|
|
||||||
macro argument"
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
macro_args.push(sub_ast.clone());
|
|
||||||
}
|
}
|
||||||
log::trace!("internal extractor macro args = {:?}", args);
|
log::trace!("internal extractor macro args = {:?}", args);
|
||||||
let pat = template.subst_macro_args(¯o_args[..])?;
|
let pat = template.subst_macro_args(¯o_args[..])?;
|
||||||
@@ -1824,13 +1718,13 @@ impl TermEnv {
|
|||||||
for (i, arg) in args.iter().enumerate() {
|
for (i, arg) in args.iter().enumerate() {
|
||||||
let term = unwrap_or_continue!(self.terms.get(tid.index()));
|
let term = unwrap_or_continue!(self.terms.get(tid.index()));
|
||||||
let arg_ty = unwrap_or_continue!(term.arg_tys.get(i).copied());
|
let arg_ty = unwrap_or_continue!(term.arg_tys.get(i).copied());
|
||||||
let (subpat, _) = unwrap_or_continue!(self.translate_pattern_term_arg(
|
let (subpat, _) = unwrap_or_continue!(self.translate_pattern(
|
||||||
tyenv,
|
tyenv,
|
||||||
rule_term,
|
rule_term,
|
||||||
pos,
|
|
||||||
arg,
|
arg,
|
||||||
Some(arg_ty),
|
Some(arg_ty),
|
||||||
bindings,
|
bindings,
|
||||||
|
/* is_root = */ false,
|
||||||
));
|
));
|
||||||
subpats.push(subpat);
|
subpats.push(subpat);
|
||||||
}
|
}
|
||||||
@@ -1841,48 +1735,6 @@ impl TermEnv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_pattern_term_arg(
|
|
||||||
&self,
|
|
||||||
tyenv: &mut TypeEnv,
|
|
||||||
rule_term: TermId,
|
|
||||||
pos: Pos,
|
|
||||||
pat: &ast::TermArgPattern,
|
|
||||||
expected_ty: Option<TypeId>,
|
|
||||||
bindings: &mut Bindings,
|
|
||||||
) -> Option<(TermArgPattern, TypeId)> {
|
|
||||||
match pat {
|
|
||||||
&ast::TermArgPattern::Pattern(ref pat) => {
|
|
||||||
let (subpat, ty) = self.translate_pattern(
|
|
||||||
tyenv,
|
|
||||||
rule_term,
|
|
||||||
pat,
|
|
||||||
expected_ty,
|
|
||||||
bindings,
|
|
||||||
/* is_root = */ false,
|
|
||||||
)?;
|
|
||||||
Some((TermArgPattern::Pattern(subpat), ty))
|
|
||||||
}
|
|
||||||
&ast::TermArgPattern::Expr(ref expr) => {
|
|
||||||
if expected_ty.is_none() {
|
|
||||||
tyenv.report_error(
|
|
||||||
pos,
|
|
||||||
"Expression in pattern must have expected type".to_string(),
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let ty = expected_ty.unwrap();
|
|
||||||
let expr = self.translate_expr(
|
|
||||||
tyenv,
|
|
||||||
expr,
|
|
||||||
expected_ty,
|
|
||||||
bindings,
|
|
||||||
/* pure = */ true,
|
|
||||||
)?;
|
|
||||||
Some((TermArgPattern::Expr(expr), ty))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maybe_implicit_convert_expr(
|
fn maybe_implicit_convert_expr(
|
||||||
&self,
|
&self,
|
||||||
tyenv: &mut TypeEnv,
|
tyenv: &mut TypeEnv,
|
||||||
|
|||||||
Reference in New Issue
Block a user