ISLE: Enable the overlap checker (#5011)
This PR turns the overlap checker on by default, requiring the use of priorities to resolve overlap between rules.
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
;; aarch64 instruction selection and CLIF-to-MachInst lowering.
|
;; aarch64 instruction selection and CLIF-to-MachInst lowering.
|
||||||
|
|
||||||
(pragma overlap_errors)
|
|
||||||
|
|
||||||
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
||||||
;; register(s) within which the lowered instruction's result values live.
|
;; register(s) within which the lowered instruction's result values live.
|
||||||
(decl lower (Inst) InstOutput)
|
(decl lower (Inst) InstOutput)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
;; riscv64 instruction selection and CLIF-to-MachInst lowering.
|
;; riscv64 instruction selection and CLIF-to-MachInst lowering.
|
||||||
|
|
||||||
(pragma overlap_errors)
|
|
||||||
|
|
||||||
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
||||||
;; register(s) within which the lowered instruction's result values live.
|
;; register(s) within which the lowered instruction's result values live.
|
||||||
(decl lower (Inst) InstOutput)
|
(decl lower (Inst) InstOutput)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
;; s390x instruction selection and CLIF-to-MachInst lowering.
|
;; s390x instruction selection and CLIF-to-MachInst lowering.
|
||||||
|
|
||||||
(pragma overlap_errors)
|
|
||||||
|
|
||||||
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
||||||
;; register(s) within which the lowered instruction's result values live.
|
;; register(s) within which the lowered instruction's result values live.
|
||||||
(decl lower (Inst) InstOutput)
|
(decl lower (Inst) InstOutput)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
;; x86-64 instruction selection and CLIF-to-MachInst lowering.
|
;; x86-64 instruction selection and CLIF-to-MachInst lowering.
|
||||||
|
|
||||||
;; Enable overlap checking for the x64 backend
|
|
||||||
(pragma overlap_errors)
|
|
||||||
|
|
||||||
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
;; The main lowering constructor term: takes a clif `Inst` and returns the
|
||||||
;; register(s) within which the lowered instruction's result values live.
|
;; register(s) within which the lowered instruction's result values live.
|
||||||
(decl lower (Inst) InstOutput)
|
(decl lower (Inst) InstOutput)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
(decl pure predicate () u32)
|
(decl pure predicate () u32)
|
||||||
(rule (predicate) 1)
|
(rule (predicate) 1)
|
||||||
|
|
||||||
(rule (C a b c (B d e))
|
(rule 2 (C a b c (B d e))
|
||||||
(if-let (B f g) d)
|
(if-let (B f g) d)
|
||||||
(if-let h (A a b))
|
(if-let h (A a b))
|
||||||
(A h a))
|
(A h a))
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
(if (predicate))
|
(if (predicate))
|
||||||
42)
|
42)
|
||||||
|
|
||||||
(rule (C a b a b)
|
(rule 1 (C a b a b)
|
||||||
(if-let x (D a b))
|
(if-let x (D a b))
|
||||||
x)
|
x)
|
||||||
|
|
||||||
(decl pure D (u32 u32) u32)
|
(decl pure D (u32 u32) u32)
|
||||||
(rule (D x 0) x)
|
(rule (D x 0) x)
|
||||||
(rule (D 0 x) x)
|
(rule 1 (D 0 x) x)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
(decl Rule (u32) u32)
|
(decl Rule (u32) u32)
|
||||||
|
|
||||||
(rule (Rule (E1 a idx))
|
(rule 1 (Rule (E1 a idx))
|
||||||
(if-let (A.B) a)
|
(if-let (A.B) a)
|
||||||
idx)
|
idx)
|
||||||
(rule (Rule _)
|
(rule (Rule _)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
(rule
|
(rule
|
||||||
(Lower (Iadd ra rb))
|
(Lower (Iadd ra rb))
|
||||||
(MachInst.Add (UseInput ra) (UseInput rb)))
|
(MachInst.Add (UseInput ra) (UseInput rb)))
|
||||||
(rule
|
(rule 1
|
||||||
(Lower (Iadd (Producer (Iadd ra rb)) rc))
|
(Lower (Iadd (Producer (Iadd ra rb)) rc))
|
||||||
(MachInst.Add3 (UseInput ra) (UseInput rb) (UseInput rc)))
|
(MachInst.Add3 (UseInput ra) (UseInput rb) (UseInput rc)))
|
||||||
(rule
|
(rule
|
||||||
|
|||||||
@@ -51,12 +51,12 @@
|
|||||||
(extern constructor put_in_reg put_in_reg)
|
(extern constructor put_in_reg put_in_reg)
|
||||||
|
|
||||||
;; Simple rule for lowering adds.
|
;; Simple rule for lowering adds.
|
||||||
(rule (lower (HighLevelInst.Add a b))
|
(rule -1 (lower (HighLevelInst.Add a b))
|
||||||
(LowLevelInst.Add
|
(LowLevelInst.Add
|
||||||
(AddrMode.RegReg (put_in_reg a) (put_in_reg b))))
|
(AddrMode.RegReg (put_in_reg a) (put_in_reg b))))
|
||||||
|
|
||||||
;; Simple rule for lowering loads.
|
;; Simple rule for lowering loads.
|
||||||
(rule (lower (HighLevelInst.Load addr))
|
(rule -1 (lower (HighLevelInst.Load addr))
|
||||||
(LowLevelInst.Load 0 (put_in_reg addr)))
|
(LowLevelInst.Load 0 (put_in_reg addr)))
|
||||||
|
|
||||||
;; Declare an external extractor for extracting the instruction that defined a
|
;; Declare an external extractor for extracting the instruction that defined a
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
0)))
|
0)))
|
||||||
|
|
||||||
;; Rule to sink a load of a base address with a static offset into a single add.
|
;; Rule to sink a load of a base address with a static offset into a single add.
|
||||||
(rule (lower (HighLevelInst.Add
|
(rule 1 (lower (HighLevelInst.Add
|
||||||
a
|
a
|
||||||
(inst_result (HighLevelInst.Load
|
(inst_result (HighLevelInst.Load
|
||||||
(inst_result (HighLevelInst.Add
|
(inst_result (HighLevelInst.Add
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
|
|
||||||
(type u32 (primitive u32))
|
|
||||||
|
|
||||||
(decl identity (u32) u32)
|
|
||||||
(extern extractor infallible identity identity)
|
|
||||||
|
|
||||||
(decl is_zero (u32) u32)
|
|
||||||
(extern extractor is_zero is_zero)
|
|
||||||
|
|
||||||
(decl test (u32) u32)
|
|
||||||
|
|
||||||
;; This exposes a bug where infallible extractors were running before fallible
|
|
||||||
;; ones, as the derived ordering for the `Extract` type was ordering them ahead
|
|
||||||
;; of the fallible ones. The result is that the fallible `is_zero` extractor
|
|
||||||
;; never runs, as the `identity` extractor will always succeed before it's
|
|
||||||
;; called.
|
|
||||||
(rule (test (identity x)) x)
|
|
||||||
|
|
||||||
(rule (test (is_zero x)) 2)
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
mod extractor_ordering_bug;
|
|
||||||
|
|
||||||
struct Context;
|
|
||||||
impl extractor_ordering_bug::Context for Context {
|
|
||||||
fn is_zero(&mut self, val: u32) -> Option<u32> {
|
|
||||||
if val == 0 {
|
|
||||||
Some(val)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn identity(&mut self, val: u32) -> u32 {
|
|
||||||
val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut ctx = Context;
|
|
||||||
|
|
||||||
assert_eq!(extractor_ordering_bug::constructor_test(&mut ctx, 0), Some(2));
|
|
||||||
assert_eq!(extractor_ordering_bug::constructor_test(&mut ctx, 1), Some(1));
|
|
||||||
}
|
|
||||||
@@ -33,8 +33,7 @@ pub struct Ident(pub String, pub Pos);
|
|||||||
/// Pragmas parsed with the `(pragma <ident>)` syntax.
|
/// Pragmas parsed with the `(pragma <ident>)` syntax.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Pragma {
|
pub enum Pragma {
|
||||||
/// Enable overlap errors in the source.
|
// currently, no pragmas are defined, but the infrastructure is useful to keep around
|
||||||
OverlapErrors,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A declaration of a type.
|
/// A declaration of a type.
|
||||||
|
|||||||
@@ -11,20 +11,14 @@ use crate::sema::{self, Rule, RuleId, Sym, TermEnv, TermId, TermKind, TypeEnv, V
|
|||||||
/// Check for overlap.
|
/// Check for overlap.
|
||||||
pub fn check(tyenv: &TypeEnv, termenv: &TermEnv) -> Result<()> {
|
pub fn check(tyenv: &TypeEnv, termenv: &TermEnv) -> Result<()> {
|
||||||
let mut errors = check_overlaps(termenv).report(tyenv, termenv);
|
let mut errors = check_overlaps(termenv).report(tyenv, termenv);
|
||||||
if termenv.overlap_errors {
|
errors.sort_by_key(|err| match err {
|
||||||
errors.sort_by_key(|err| match err {
|
Error::OverlapError { rules, .. } => rules.first().unwrap().1.from,
|
||||||
Error::OverlapError { rules, .. } => rules.first().unwrap().1.from,
|
_ => Pos::default(),
|
||||||
_ => Pos::default(),
|
});
|
||||||
});
|
match errors.len() {
|
||||||
match errors.len() {
|
0 => Ok(()),
|
||||||
0 => Ok(()),
|
1 => Err(errors.pop().unwrap()),
|
||||||
1 => Err(errors.pop().unwrap()),
|
_ => Err(Error::Errors(errors)),
|
||||||
_ => Err(Error::Errors(errors)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
use crate::log;
|
|
||||||
log!("found {} overlap errors", errors.len());
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,9 +200,9 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn parse_pragma(&mut self) -> Result<Pragma> {
|
fn parse_pragma(&mut self) -> Result<Pragma> {
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
match ident.0.as_ref() {
|
// currently, no pragmas are defined, but the infrastructure is useful to keep around
|
||||||
"overlap_errors" => Ok(Pragma::OverlapErrors),
|
match ident.0.as_str() {
|
||||||
_ => Err(self.error(ident.1, format!("Unknown pragma '{}'", ident.0))),
|
pragma => Err(self.error(ident.1, format!("Unknown pragma '{}'", pragma))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,9 +200,6 @@ pub struct TermEnv {
|
|||||||
/// defined implicit type-converter terms we can try to use to fit
|
/// defined implicit type-converter terms we can try to use to fit
|
||||||
/// types together.
|
/// types together.
|
||||||
pub converters: StableMap<(TypeId, TypeId), TermId>,
|
pub converters: StableMap<(TypeId, TypeId), TermId>,
|
||||||
|
|
||||||
/// A flag indicating whether or not overlap between rules should be considered an error.
|
|
||||||
pub overlap_errors: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A term.
|
/// A term.
|
||||||
@@ -789,7 +786,6 @@ impl TermEnv {
|
|||||||
term_map: StableMap::new(),
|
term_map: StableMap::new(),
|
||||||
rules: vec![],
|
rules: vec![],
|
||||||
converters: StableMap::new(),
|
converters: StableMap::new(),
|
||||||
overlap_errors: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
env.collect_pragmas(defs);
|
env.collect_pragmas(defs);
|
||||||
@@ -811,13 +807,9 @@ impl TermEnv {
|
|||||||
Ok(env)
|
Ok(env)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_pragmas(&mut self, defs: &ast::Defs) {
|
fn collect_pragmas(&mut self, _: &ast::Defs) {
|
||||||
for def in &defs.defs {
|
// currently, no pragmas are defined, but the infrastructure is useful to keep around
|
||||||
match def {
|
return;
|
||||||
ast::Def::Pragma(ast::Pragma::OverlapErrors) => self.overlap_errors = true,
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) {
|
fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) {
|
||||||
|
|||||||
Reference in New Issue
Block a user