From 9b8738de63959f6daa20f8d54e7eefdf121102e4 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 09:35:04 -0600 Subject: [PATCH 01/16] Expand concat example, breaks type-checking --- juno_samples/concat/src/concat.jn | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/juno_samples/concat/src/concat.jn b/juno_samples/concat/src/concat.jn index 2471671e..70c741b6 100644 --- a/juno_samples/concat/src/concat.jn +++ b/juno_samples/concat/src/concat.jn @@ -30,3 +30,22 @@ fn concat_entry(a : i32) -> i32 { let arr3 = concat::<i32, 3, 6>(arr1, arr2); return sum::<i32, 9>(arr3); } + +#[entry] +fn concat_switch<n: usize>(b: i32, m: i32[n]) -> i32[n + 2] { + let ex : i32[2]; + ex[0] = 0; + ex[1] = 1; + + let x = concat::<_, 2, n>(ex, m); + let y = concat::<_, n, 2>(m, ex); + + let s = 0; + + s += sum::<i32, n + 2>(x); + s += sum::<i32, 2 + n>(x); + s += sum::<i32, n + 2>(y); + s += sum::<i32, 2 + n>(y); + + return if s < b then x else y; +} -- GitLab From 2a18b1cb0c0b427363d1fed9e17d1ef0ff88cca8 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 15:28:35 -0600 Subject: [PATCH 02/16] Define normalization process --- hercules_ir/src/dc_normalization.rs | 198 ++++++++++++++++++++++++++++ hercules_ir/src/ir.rs | 105 ++++++++------- hercules_ir/src/lib.rs | 2 + 3 files changed, 255 insertions(+), 50 deletions(-) create mode 100644 hercules_ir/src/dc_normalization.rs diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs new file mode 100644 index 00000000..cfeaf744 --- /dev/null +++ b/hercules_ir/src/dc_normalization.rs @@ -0,0 +1,198 @@ +use crate::*; + +use std::collections::HashMap; +use std::cmp::{min, max}; + +fn insert_dc( + dc: DynamicConstant, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + if let Some(id) = reverse_map.get(&dc) { + *id + } else { + let id = DynamicConstantID::new(dynamic_constants.len()); + dynamic_constants.push(dc.clone()); + reverse_map.insert(dc, id); + id + } +} + +pub fn dc_add( + dcs: Vec<DynamicConstantID>, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + let mut constant_val = 0; + let mut fields = vec![]; + + for dc in dcs { + match &dynamic_constants[dc.idx()] { + DynamicConstant::Constant(x) => constant_val += x, + DynamicConstant::Add(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), + } + } + + let new_dc = + if fields.len() == 0 { + // If there are no non-constants, our result is a constant + DynamicConstant::Constant(constant_val) + } else if constant_val == 0 { + // If there are non-constants and our constant value is zero, omit it + fields.sort(); + DynamicConstant::Add(fields) + } else { + // Both non-constant and constant pieces + fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); + fields.sort(); + DynamicConstant::Add(fields) + }; + + insert_dc(new_dc, dynamic_constants, reverse_map) +} + +pub fn dc_mul( + dcs: Vec<DynamicConstantID>, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + let mut constant_val = 1; + let mut fields = vec![]; + + for dc in dcs { + match &dynamic_constants[dc.idx()] { + DynamicConstant::Constant(x) => constant_val *= x, + DynamicConstant::Mul(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), + } + } + + let new_dc = + if fields.len() == 0 { + // If there are no non-constants, our result is a constant + DynamicConstant::Constant(constant_val) + } else if constant_val == 1 { + // If there are non-constants and our constant value is one, omit it + fields.sort(); + DynamicConstant::Mul(fields) + } else { + // Both non-constant and constant pieces + fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); + fields.sort(); + DynamicConstant::Mul(fields) + }; + + insert_dc(new_dc, dynamic_constants, reverse_map) +} + +pub fn dc_min( + dcs: Vec<DynamicConstantID>, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + let mut constant_val : Option<usize> = None; + let mut fields = vec![]; + + for dc in dcs { + match &dynamic_constants[dc.idx()] { + DynamicConstant::Constant(x) => { + if let Some(cur_min) = constant_val { + constant_val = Some(min(cur_min, *x)); + } else { + constant_val = Some(*x); + } + } + DynamicConstant::Min(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), + } + } + + let new_dc = + if let Some(const_val) = constant_val { + fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); + fields.sort(); + DynamicConstant::Min(fields) + } else { + fields.sort(); + DynamicConstant::Min(fields) + }; + + insert_dc(new_dc, dynamic_constants, reverse_map) +} + +pub fn dc_max( + dcs: Vec<DynamicConstantID>, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + let mut constant_val : Option<usize> = None; + let mut fields = vec![]; + + for dc in dcs { + match &dynamic_constants[dc.idx()] { + DynamicConstant::Constant(x) => { + if let Some(cur_max) = constant_val { + constant_val = Some(max(cur_max, *x)); + } else { + constant_val = Some(*x); + } + } + DynamicConstant::Max(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), + } + } + + let new_dc = + if let Some(const_val) = constant_val { + fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); + fields.sort(); + DynamicConstant::Max(fields) + } else { + fields.sort(); + DynamicConstant::Max(fields) + }; + + insert_dc(new_dc, dynamic_constants, reverse_map) +} + +pub fn dc_sub( + x: DynamicConstantID, + y: DynamicConstantID, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + match (&dynamic_constants[x.idx()], &dynamic_constants[y.idx()]) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => + insert_dc(DynamicConstant::Constant(x - y), dynamic_constants, reverse_map), + (_, DynamicConstant::Constant(0)) => x, + _ => insert_dc(DynamicConstant::Sub(x, y), dynamic_constants, reverse_map), + } +} + +pub fn dc_div( + x: DynamicConstantID, + y: DynamicConstantID, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + match (&dynamic_constants[x.idx()], &dynamic_constants[y.idx()]) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => + insert_dc(DynamicConstant::Constant(x / y), dynamic_constants, reverse_map), + (_, DynamicConstant::Constant(1)) => x, + _ => insert_dc(DynamicConstant::Div(x, y), dynamic_constants, reverse_map), + } +} + +pub fn dc_rem( + x: DynamicConstantID, + y: DynamicConstantID, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + match (&dynamic_constants[x.idx()], &dynamic_constants[y.idx()]) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => + insert_dc(DynamicConstant::Constant(x % y), dynamic_constants, reverse_map), + _ => insert_dc(DynamicConstant::Rem(x, y), dynamic_constants, reverse_map), + } +} diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs index d8a124e2..9dcd768c 100644 --- a/hercules_ir/src/ir.rs +++ b/hercules_ir/src/ir.rs @@ -1,4 +1,3 @@ -use std::cmp::{max, min}; use std::collections::HashSet; use std::fmt::Write; use std::ops::Coroutine; @@ -120,13 +119,14 @@ pub enum DynamicConstant { // function is this). Parameter(usize), // Supported integer operations on dynamic constants. - Add(DynamicConstantID, DynamicConstantID), + Add(Vec<DynamicConstantID>), + Mul(Vec<DynamicConstantID>), + Min(Vec<DynamicConstantID>), + Max(Vec<DynamicConstantID>), + Sub(DynamicConstantID, DynamicConstantID), - Mul(DynamicConstantID, DynamicConstantID), Div(DynamicConstantID, DynamicConstantID), Rem(DynamicConstantID, DynamicConstantID), - Min(DynamicConstantID, DynamicConstantID), - Max(DynamicConstantID, DynamicConstantID), } /* @@ -464,21 +464,31 @@ impl Module { match &self.dynamic_constants[dc_id.idx()] { DynamicConstant::Constant(cons) => write!(w, "{}", cons), DynamicConstant::Parameter(param) => write!(w, "#{}", param), - DynamicConstant::Add(x, y) - | DynamicConstant::Sub(x, y) - | DynamicConstant::Mul(x, y) + DynamicConstant::Add(xs) + | DynamicConstant::Mul(xs) + | DynamicConstant::Min(xs) + | DynamicConstant::Max(xs) => { + match &self.dynamic_constants[dc_id.idx()] { + DynamicConstant::Add(_) => write!(w, "+")?, + DynamicConstant::Mul(_) => write!(w, "*")?, + DynamicConstant::Min(_) => write!(w, "min")?, + DynamicConstant::Max(_) => write!(w, "max")?, + _ => (), + } + write!(w, "(")?; + for arg in xs { + self.write_dynamic_constant(*arg, w)?; + write!(w, ",")?; + } + write!(w, ")") + } + DynamicConstant::Sub(x, y) | DynamicConstant::Div(x, y) - | DynamicConstant::Rem(x, y) - | DynamicConstant::Min(x, y) - | DynamicConstant::Max(x, y) => { + | DynamicConstant::Rem(x, y) => { match &self.dynamic_constants[dc_id.idx()] { - DynamicConstant::Add(_, _) => write!(w, "+")?, DynamicConstant::Sub(_, _) => write!(w, "-")?, - DynamicConstant::Mul(_, _) => write!(w, "*")?, DynamicConstant::Div(_, _) => write!(w, "/")?, DynamicConstant::Rem(_, _) => write!(w, "%")?, - DynamicConstant::Min(_, _) => write!(w, "min")?, - DynamicConstant::Max(_, _) => write!(w, "max")?, _ => (), } write!(w, "(")?; @@ -638,15 +648,33 @@ pub fn dynamic_constants_bottom_up( if visited[id.idx()] { continue; } - match dynamic_constants[id.idx()] { - DynamicConstant::Add(left, right) - | DynamicConstant::Sub(left, right) - | DynamicConstant::Mul(left, right) - | DynamicConstant::Div(left, right) - | DynamicConstant::Rem(left, right) => { + match &dynamic_constants[id.idx()] { + DynamicConstant::Add(args) + | DynamicConstant::Mul(args) + | DynamicConstant::Min(args) + | DynamicConstant::Max(args) => { // We have to yield the children of this node before // this node itself. We keep track of which nodes have // yielded using visited. + if args.iter().any(|i| i.idx() >= visited.len()) { + // Some argument is an invalid dynamic constant and should be skipped + continue; + } + + if args.iter().all(|i| visited[i.idx()]) { + // Since all children have been yielded, we yield ourself + visited.set(id.idx(), true); + yield id; + } else { + // Otherwise push self onto stack so that the children will get popped + // first + stack.push(id); + stack.extend(args.clone()); + } + } + DynamicConstant::Sub(left, right) + | DynamicConstant::Div(left, right) + | DynamicConstant::Rem(left, right) => { if left.idx() >= visited.len() || right.idx() >= visited.len() { // This is an invalid dynamic constant and should be // skipped. @@ -660,8 +688,8 @@ pub fn dynamic_constants_bottom_up( // Push ourselves, then children, so that children // get popped first. stack.push(id); - stack.push(left); - stack.push(right); + stack.push(*left); + stack.push(*right); } } _ => { @@ -1024,33 +1052,10 @@ pub fn evaluate_dynamic_constant( cons: DynamicConstantID, dcs: &Vec<DynamicConstant>, ) -> Option<usize> { - match dcs[cons.idx()] { - DynamicConstant::Constant(cons) => Some(cons), - DynamicConstant::Parameter(_) => None, - DynamicConstant::Add(left, right) => { - Some(evaluate_dynamic_constant(left, dcs)? + evaluate_dynamic_constant(right, dcs)?) - } - DynamicConstant::Sub(left, right) => { - Some(evaluate_dynamic_constant(left, dcs)? - evaluate_dynamic_constant(right, dcs)?) - } - DynamicConstant::Mul(left, right) => { - Some(evaluate_dynamic_constant(left, dcs)? * evaluate_dynamic_constant(right, dcs)?) - } - DynamicConstant::Div(left, right) => { - Some(evaluate_dynamic_constant(left, dcs)? / evaluate_dynamic_constant(right, dcs)?) - } - DynamicConstant::Rem(left, right) => { - Some(evaluate_dynamic_constant(left, dcs)? % evaluate_dynamic_constant(right, dcs)?) - } - DynamicConstant::Min(left, right) => Some(min( - evaluate_dynamic_constant(left, dcs)?, - evaluate_dynamic_constant(right, dcs)?, - )), - DynamicConstant::Max(left, right) => Some(max( - evaluate_dynamic_constant(left, dcs)?, - evaluate_dynamic_constant(right, dcs)?, - )), - } + // Because of normalization, if a dynamic constant can be expressed as a constant it must be a + // constant + let DynamicConstant::Constant(cons) = dcs[cons.idx()] else { return None; }; + Some(cons) } /* diff --git a/hercules_ir/src/lib.rs b/hercules_ir/src/lib.rs index 85dc277f..bc1fbb9f 100644 --- a/hercules_ir/src/lib.rs +++ b/hercules_ir/src/lib.rs @@ -10,6 +10,7 @@ pub mod build; pub mod callgraph; pub mod collections; pub mod dataflow; +pub mod dc_normalization; pub mod def_use; pub mod device; pub mod dom; @@ -26,6 +27,7 @@ pub use crate::build::*; pub use crate::callgraph::*; pub use crate::collections::*; pub use crate::dataflow::*; +pub use crate::dc_normalization::*; pub use crate::def_use::*; pub use crate::device::*; pub use crate::dom::*; -- GitLab From 6beb6f4389d7f311ffaa41438269ee3279e162ac Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 15:59:20 -0600 Subject: [PATCH 03/16] Normalize DCs if there's only one term --- hercules_ir/src/dc_normalization.rs | 116 +++++++++++++++------------- 1 file changed, 64 insertions(+), 52 deletions(-) diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index cfeaf744..55effa3b 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -18,6 +18,22 @@ fn insert_dc( } } +pub fn dc_const( + val: usize, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + insert_dc(DynamicConstant::Constant(val), dynamic_constants, reverse_map) +} + +pub fn dc_param( + index: usize, + dynamic_constants: &mut Vec<DynamicConstant>, + reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, +) -> DynamicConstantID { + insert_dc(DynamicConstant::Parameter(index), dynamic_constants, reverse_map) +} + pub fn dc_add( dcs: Vec<DynamicConstantID>, dynamic_constants: &mut Vec<DynamicConstant>, @@ -34,22 +50,18 @@ pub fn dc_add( } } - let new_dc = - if fields.len() == 0 { - // If there are no non-constants, our result is a constant - DynamicConstant::Constant(constant_val) - } else if constant_val == 0 { - // If there are non-constants and our constant value is zero, omit it - fields.sort(); - DynamicConstant::Add(fields) - } else { - // Both non-constant and constant pieces - fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); - fields.sort(); - DynamicConstant::Add(fields) - }; - - insert_dc(new_dc, dynamic_constants, reverse_map) + // If either there are no fields or the constant is non-zero, add it + if constant_val != 0 || fields.len() == 0 { + fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); + } + + if fields.len() <= 1 { + // If there is only one term to add, just return it + fields[0] + } else { + fields.sort(); + insert_dc(DynamicConstant::Add(fields), dynamic_constants, reverse_map) + } } pub fn dc_mul( @@ -68,22 +80,20 @@ pub fn dc_mul( } } - let new_dc = - if fields.len() == 0 { - // If there are no non-constants, our result is a constant - DynamicConstant::Constant(constant_val) - } else if constant_val == 1 { - // If there are non-constants and our constant value is one, omit it - fields.sort(); - DynamicConstant::Mul(fields) - } else { - // Both non-constant and constant pieces - fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); - fields.sort(); - DynamicConstant::Mul(fields) - }; - - insert_dc(new_dc, dynamic_constants, reverse_map) + if constant_val == 0 { + return insert_dc(DynamicConstant::Constant(0), dynamic_constants, reverse_map); + } + + if constant_val != 1 || fields.len() == 0 { + fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); + } + + if fields.len() <= 1 { + fields[0] + } else { + fields.sort(); + insert_dc(DynamicConstant::Mul(fields), dynamic_constants, reverse_map) + } } pub fn dc_min( @@ -108,17 +118,18 @@ pub fn dc_min( } } - let new_dc = - if let Some(const_val) = constant_val { - fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); - fields.sort(); - DynamicConstant::Min(fields) - } else { - fields.sort(); - DynamicConstant::Min(fields) - }; + if let Some(const_val) = constant_val { + fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); + } + + assert!(fields.len() > 0, "Min of 0 dynamic constant expressions is undefined"); - insert_dc(new_dc, dynamic_constants, reverse_map) + if fields.len() <= 1 { + fields[0] + } else { + fields.sort(); + insert_dc(DynamicConstant::Min(fields), dynamic_constants, reverse_map) + } } pub fn dc_max( @@ -143,17 +154,18 @@ pub fn dc_max( } } - let new_dc = - if let Some(const_val) = constant_val { - fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); - fields.sort(); - DynamicConstant::Max(fields) - } else { - fields.sort(); - DynamicConstant::Max(fields) - }; + if let Some(const_val) = constant_val { + fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); + } - insert_dc(new_dc, dynamic_constants, reverse_map) + assert!(fields.len() > 0, "Max of 0 dynamic constant expressions is undefined"); + + if fields.len() <= 1 { + fields[0] + } else { + fields.sort(); + insert_dc(DynamicConstant::Max(fields), dynamic_constants, reverse_map) + } } pub fn dc_sub( -- GitLab From deebc46fbcd96ca0b03f361f059399d8bc3c29d7 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 15:59:31 -0600 Subject: [PATCH 04/16] Update builder to use dc normalization --- hercules_ir/src/build.rs | 55 ++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/hercules_ir/src/build.rs b/hercules_ir/src/build.rs index 1dd326c3..bc57781d 100644 --- a/hercules_ir/src/build.rs +++ b/hercules_ir/src/build.rs @@ -70,17 +70,6 @@ impl<'a> Builder<'a> { } } - fn intern_dynamic_constant(&mut self, dyn_cons: DynamicConstant) -> DynamicConstantID { - if let Some(id) = self.interned_dynamic_constants.get(&dyn_cons) { - *id - } else { - let id = DynamicConstantID::new(self.interned_dynamic_constants.len()); - self.interned_dynamic_constants.insert(dyn_cons.clone(), id); - self.module.dynamic_constants.push(dyn_cons); - id - } - } - pub fn add_label(&mut self, label: &String) -> LabelID { if let Some(id) = self.interned_labels.get(label) { *id @@ -406,11 +395,11 @@ impl<'a> Builder<'a> { } pub fn create_dynamic_constant_constant(&mut self, val: usize) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Constant(val)) + dc_const(val, &mut self.module.dynamic_constants, &mut self.interned_dynamic_constants) } - pub fn create_dynamic_constant_parameter(&mut self, val: usize) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Parameter(val)) + pub fn create_dynamic_constant_parameter(&mut self, idx: usize) -> DynamicConstantID { + dc_param(idx, &mut self.module.dynamic_constants, &mut self.interned_dynamic_constants) } pub fn create_dynamic_constant_add( @@ -418,7 +407,18 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Add(x, y)) + dc_add(vec![x, y], + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) + } + + pub fn create_dynamic_constant_add_many( + &mut self, + xs: Vec<DynamicConstantID>, + ) -> DynamicConstantID { + dc_add(xs, + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) } pub fn create_dynamic_constant_sub( @@ -426,7 +426,9 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Sub(x, y)) + dc_sub(x, y, + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) } pub fn create_dynamic_constant_mul( @@ -434,7 +436,18 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Mul(x, y)) + dc_mul(vec![x, y], + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) + } + + pub fn create_dynamic_constant_mul_many( + &mut self, + xs: Vec<DynamicConstantID>, + ) -> DynamicConstantID { + dc_mul(xs, + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) } pub fn create_dynamic_constant_div( @@ -442,7 +455,9 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Div(x, y)) + dc_div(x, y, + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) } pub fn create_dynamic_constant_rem( @@ -450,7 +465,9 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - self.intern_dynamic_constant(DynamicConstant::Rem(x, y)) + dc_rem(x, y, + &mut self.module.dynamic_constants, + &mut self.interned_dynamic_constants) } pub fn create_field_index(&self, idx: usize) -> Index { -- GitLab From 46537c8f4bed7c4090f97e8a7fe35d999d6f2aed Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 17:30:48 -0600 Subject: [PATCH 05/16] Update to normalization and implement in editor --- hercules_ir/src/build.rs | 49 ++++++----- hercules_ir/src/dc_normalization.rs | 125 ++++++++++++++-------------- hercules_opt/src/editor.rs | 42 ++++++---- 3 files changed, 113 insertions(+), 103 deletions(-) diff --git a/hercules_ir/src/build.rs b/hercules_ir/src/build.rs index bc57781d..b7844806 100644 --- a/hercules_ir/src/build.rs +++ b/hercules_ir/src/build.rs @@ -25,6 +25,23 @@ pub struct Builder<'a> { module: Module, } +impl<'a> DynamicConstantView for Builder<'a> { + fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + &self.module.dynamic_constants[id.idx()] + } + + fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID { + if let Some(id) = self.interned_dynamic_constants.get(&dc) { + *id + } else { + let id = DynamicConstantID::new(self.module.dynamic_constants.len()); + self.module.dynamic_constants.push(dc.clone()); + self.interned_dynamic_constants.insert(dc, id); + id + } + } +} + /* * Since the builder doesn't provide string names for nodes, we need a different * mechanism for allowing one to allocate node IDs before actually creating the @@ -395,11 +412,11 @@ impl<'a> Builder<'a> { } pub fn create_dynamic_constant_constant(&mut self, val: usize) -> DynamicConstantID { - dc_const(val, &mut self.module.dynamic_constants, &mut self.interned_dynamic_constants) + dc_const(val, self) } pub fn create_dynamic_constant_parameter(&mut self, idx: usize) -> DynamicConstantID { - dc_param(idx, &mut self.module.dynamic_constants, &mut self.interned_dynamic_constants) + dc_param(idx, self) } pub fn create_dynamic_constant_add( @@ -407,18 +424,14 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_add(vec![x, y], - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_add(vec![x, y], self) } pub fn create_dynamic_constant_add_many( &mut self, xs: Vec<DynamicConstantID>, ) -> DynamicConstantID { - dc_add(xs, - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_add(xs, self) } pub fn create_dynamic_constant_sub( @@ -426,9 +439,7 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_sub(x, y, - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_sub(x, y, self) } pub fn create_dynamic_constant_mul( @@ -436,18 +447,14 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_mul(vec![x, y], - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_mul(vec![x, y], self) } pub fn create_dynamic_constant_mul_many( &mut self, xs: Vec<DynamicConstantID>, ) -> DynamicConstantID { - dc_mul(xs, - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_mul(xs, self) } pub fn create_dynamic_constant_div( @@ -455,9 +462,7 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_div(x, y, - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_div(x, y, self) } pub fn create_dynamic_constant_rem( @@ -465,9 +470,7 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_rem(x, y, - &mut self.module.dynamic_constants, - &mut self.interned_dynamic_constants) + dc_rem(x, y, self) } pub fn create_field_index(&self, idx: usize) -> Index { diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index 55effa3b..869ddbf8 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -3,47 +3,34 @@ use crate::*; use std::collections::HashMap; use std::cmp::{min, max}; -fn insert_dc( - dc: DynamicConstant, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, -) -> DynamicConstantID { - if let Some(id) = reverse_map.get(&dc) { - *id - } else { - let id = DynamicConstantID::new(dynamic_constants.len()); - dynamic_constants.push(dc.clone()); - reverse_map.insert(dc, id); - id - } +pub trait DynamicConstantView { + fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant; + fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID; } -pub fn dc_const( +pub fn dc_const<T: DynamicConstantView>( val: usize, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { - insert_dc(DynamicConstant::Constant(val), dynamic_constants, reverse_map) + view.add_dynconst(DynamicConstant::Constant(val)) } -pub fn dc_param( +pub fn dc_param<T: DynamicConstantView>( index: usize, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { - insert_dc(DynamicConstant::Parameter(index), dynamic_constants, reverse_map) + view.add_dynconst(DynamicConstant::Parameter(index)) } -pub fn dc_add( +pub fn dc_add<T: DynamicConstantView>( dcs: Vec<DynamicConstantID>, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { let mut constant_val = 0; let mut fields = vec![]; for dc in dcs { - match &dynamic_constants[dc.idx()] { + match view.get_dynconst(dc) { DynamicConstant::Constant(x) => constant_val += x, DynamicConstant::Add(xs) => fields.extend_from_slice(xs), _ => fields.push(dc), @@ -52,7 +39,7 @@ pub fn dc_add( // If either there are no fields or the constant is non-zero, add it if constant_val != 0 || fields.len() == 0 { - fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); + fields.push(view.add_dynconst(DynamicConstant::Constant(constant_val))); } if fields.len() <= 1 { @@ -60,20 +47,19 @@ pub fn dc_add( fields[0] } else { fields.sort(); - insert_dc(DynamicConstant::Add(fields), dynamic_constants, reverse_map) + view.add_dynconst(DynamicConstant::Add(fields)) } } -pub fn dc_mul( +pub fn dc_mul<T: DynamicConstantView>( dcs: Vec<DynamicConstantID>, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { let mut constant_val = 1; let mut fields = vec![]; for dc in dcs { - match &dynamic_constants[dc.idx()] { + match view.get_dynconst(dc) { DynamicConstant::Constant(x) => constant_val *= x, DynamicConstant::Mul(xs) => fields.extend_from_slice(xs), _ => fields.push(dc), @@ -81,31 +67,30 @@ pub fn dc_mul( } if constant_val == 0 { - return insert_dc(DynamicConstant::Constant(0), dynamic_constants, reverse_map); + return view.add_dynconst(DynamicConstant::Constant(0)); } if constant_val != 1 || fields.len() == 0 { - fields.push(insert_dc(DynamicConstant::Constant(constant_val), dynamic_constants, reverse_map)); + fields.push(view.add_dynconst(DynamicConstant::Constant(constant_val))); } if fields.len() <= 1 { fields[0] } else { fields.sort(); - insert_dc(DynamicConstant::Mul(fields), dynamic_constants, reverse_map) + view.add_dynconst(DynamicConstant::Mul(fields)) } } -pub fn dc_min( +pub fn dc_min<T: DynamicConstantView>( dcs: Vec<DynamicConstantID>, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { let mut constant_val : Option<usize> = None; let mut fields = vec![]; for dc in dcs { - match &dynamic_constants[dc.idx()] { + match view.get_dynconst(dc) { DynamicConstant::Constant(x) => { if let Some(cur_min) = constant_val { constant_val = Some(min(cur_min, *x)); @@ -119,7 +104,7 @@ pub fn dc_min( } if let Some(const_val) = constant_val { - fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); + fields.push(view.add_dynconst(DynamicConstant::Constant(const_val))); } assert!(fields.len() > 0, "Min of 0 dynamic constant expressions is undefined"); @@ -128,20 +113,19 @@ pub fn dc_min( fields[0] } else { fields.sort(); - insert_dc(DynamicConstant::Min(fields), dynamic_constants, reverse_map) + view.add_dynconst(DynamicConstant::Min(fields)) } } -pub fn dc_max( +pub fn dc_max<T: DynamicConstantView>( dcs: Vec<DynamicConstantID>, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { let mut constant_val : Option<usize> = None; let mut fields = vec![]; for dc in dcs { - match &dynamic_constants[dc.idx()] { + match view.get_dynconst(dc) { DynamicConstant::Constant(x) => { if let Some(cur_max) = constant_val { constant_val = Some(max(cur_max, *x)); @@ -155,7 +139,7 @@ pub fn dc_max( } if let Some(const_val) = constant_val { - fields.push(insert_dc(DynamicConstant::Constant(const_val), dynamic_constants, reverse_map)); + fields.push(view.add_dynconst(DynamicConstant::Constant(const_val))); } assert!(fields.len() > 0, "Max of 0 dynamic constant expressions is undefined"); @@ -164,47 +148,60 @@ pub fn dc_max( fields[0] } else { fields.sort(); - insert_dc(DynamicConstant::Max(fields), dynamic_constants, reverse_map) + view.add_dynconst(DynamicConstant::Max(fields)) } } -pub fn dc_sub( +pub fn dc_sub<T: DynamicConstantView>( x: DynamicConstantID, y: DynamicConstantID, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { - match (&dynamic_constants[x.idx()], &dynamic_constants[y.idx()]) { + match (view.get_dynconst(x), view.get_dynconst(y)) { (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - insert_dc(DynamicConstant::Constant(x - y), dynamic_constants, reverse_map), + view.add_dynconst(DynamicConstant::Constant(x - y)), (_, DynamicConstant::Constant(0)) => x, - _ => insert_dc(DynamicConstant::Sub(x, y), dynamic_constants, reverse_map), + _ => view.add_dynconst(DynamicConstant::Sub(x, y)), } } -pub fn dc_div( +pub fn dc_div<T: DynamicConstantView>( x: DynamicConstantID, y: DynamicConstantID, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { - match (&dynamic_constants[x.idx()], &dynamic_constants[y.idx()]) { + match (view.get_dynconst(x), view.get_dynconst(y)) { (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - insert_dc(DynamicConstant::Constant(x / y), dynamic_constants, reverse_map), + view.add_dynconst(DynamicConstant::Constant(x / y)), (_, DynamicConstant::Constant(1)) => x, - _ => insert_dc(DynamicConstant::Div(x, y), dynamic_constants, reverse_map), + _ => view.add_dynconst(DynamicConstant::Div(x, y)), } } -pub fn dc_rem( +pub fn dc_rem<T: DynamicConstantView>( x: DynamicConstantID, y: DynamicConstantID, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + view: &mut T, ) -> DynamicConstantID { - match (&dynamic_constants[x.idx()], &dynamic_constants[y.idx()]) { + match (view.get_dynconst(x), view.get_dynconst(y)) { (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - insert_dc(DynamicConstant::Constant(x % y), dynamic_constants, reverse_map), - _ => insert_dc(DynamicConstant::Rem(x, y), dynamic_constants, reverse_map), + view.add_dynconst(DynamicConstant::Constant(x % y)), + _ => view.add_dynconst(DynamicConstant::Rem(x, y)), + } +} + +pub fn dc_normalize<T: DynamicConstantView>( + dc: DynamicConstant, + view: &mut T, +) -> DynamicConstantID { + match dc { + DynamicConstant::Add(xs) => dc_add(xs, view), + DynamicConstant::Mul(xs) => dc_mul(xs, view), + DynamicConstant::Min(xs) => dc_min(xs, view), + DynamicConstant::Max(xs) => dc_max(xs, view), + DynamicConstant::Sub(x, y) => dc_sub(x, y, view), + DynamicConstant::Div(x, y) => dc_div(x, y, view), + DynamicConstant::Rem(x, y) => dc_rem(x, y, view), + _ => view.add_dynconst(dc), } } diff --git a/hercules_opt/src/editor.rs b/hercules_opt/src/editor.rs index 8b90710e..8164ff9d 100644 --- a/hercules_opt/src/editor.rs +++ b/hercules_opt/src/editor.rs @@ -725,22 +725,7 @@ impl<'a, 'b> FunctionEdit<'a, 'b> { } pub fn add_dynamic_constant(&mut self, dynamic_constant: DynamicConstant) -> DynamicConstantID { - let pos = self - .editor - .dynamic_constants - .borrow() - .iter() - .chain(self.added_dynamic_constants.iter()) - .position(|c| *c == dynamic_constant); - if let Some(idx) = pos { - DynamicConstantID::new(idx) - } else { - let id = DynamicConstantID::new( - self.editor.dynamic_constants.borrow().len() + self.added_dynamic_constants.len(), - ); - self.added_dynamic_constants.push(dynamic_constant); - id - } + dc_normalize(dynamic_constant, self) } pub fn get_dynamic_constant( @@ -770,6 +755,31 @@ impl<'a, 'b> FunctionEdit<'a, 'b> { } } +impl<'a, 'b> DynamicConstantView for FunctionEdit<'a, 'b> { + fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + self.get_dynamic_constant(id) + } + + fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID { + let pos = self + .editor + .dynamic_constants + .borrow() + .iter() + .chain(self.added_dynamic_constants.iter()) + .position(|c| *c == dc); + if let Some(idx) = pos { + DynamicConstantID::new(idx) + } else { + let id = DynamicConstantID::new( + self.editor.dynamic_constants.borrow().len() + self.added_dynamic_constants.len(), + ); + self.added_dynamic_constants.push(dc); + id + } + } +} + #[cfg(test)] mod editor_tests { #[allow(unused_imports)] -- GitLab From c547e93db5aa3e5a959bf4b103e8c2c458d100c3 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 17:37:01 -0600 Subject: [PATCH 06/16] Normalize in parser --- hercules_ir/src/dc_normalization.rs | 1 - hercules_ir/src/parse.rs | 32 ++++++++++++++++++----------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index 869ddbf8..4705eac3 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -1,6 +1,5 @@ use crate::*; -use std::collections::HashMap; use std::cmp::{min, max}; pub trait DynamicConstantView { diff --git a/hercules_ir/src/parse.rs b/hercules_ir/src/parse.rs index cdad54f9..1f6d931e 100644 --- a/hercules_ir/src/parse.rs +++ b/hercules_ir/src/parse.rs @@ -87,16 +87,7 @@ impl<'a> Context<'a> { } fn get_dynamic_constant_id(&mut self, dynamic_constant: DynamicConstant) -> DynamicConstantID { - if let Some(id) = self.interned_dynamic_constants.get(&dynamic_constant) { - *id - } else { - let id = DynamicConstantID::new(self.interned_dynamic_constants.len()); - self.interned_dynamic_constants - .insert(dynamic_constant.clone(), id); - self.reverse_dynamic_constant_map - .insert(id, dynamic_constant); - id - } + dc_normalize(dynamic_constant, self) } fn get_label_id(&mut self, label: String) -> LabelID { @@ -110,6 +101,23 @@ impl<'a> Context<'a> { } } +impl<'a> DynamicConstantView for Context<'a> { + fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + &self.reverse_dynamic_constant_map[&id] + } + + fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID { + if let Some(id) = self.interned_dynamic_constants.get(&dc) { + *id + } else { + let id = DynamicConstantID::new(self.reverse_dynamic_constant_map.len()); + self.interned_dynamic_constants.insert(dc.clone(), id); + self.reverse_dynamic_constant_map.insert(id, dc); + id + } + } +} + /* * A module is just a file with a list of functions. */ @@ -946,9 +954,9 @@ fn parse_dynamic_constant<'a>( ), )), |(op, (x, y))| match op { - '+' => DynamicConstant::Add(x, y), + '+' => DynamicConstant::Add(vec![x, y]), '-' => DynamicConstant::Sub(x, y), - '*' => DynamicConstant::Mul(x, y), + '*' => DynamicConstant::Mul(vec![x, y]), '/' => DynamicConstant::Div(x, y), '%' => DynamicConstant::Rem(x, y), _ => panic!("Invalid parse"), -- GitLab From e45a5aaf0b1e5933c13d0848b32d72dff307c44f Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Wed, 29 Jan 2025 18:03:46 -0600 Subject: [PATCH 07/16] Handle normalization in type-checker --- hercules_ir/src/typecheck.rs | 424 +++++++++++------------------------ 1 file changed, 129 insertions(+), 295 deletions(-) diff --git a/hercules_ir/src/typecheck.rs b/hercules_ir/src/typecheck.rs index a80dd422..698223b4 100644 --- a/hercules_ir/src/typecheck.rs +++ b/hercules_ir/src/typecheck.rs @@ -1,4 +1,3 @@ -use std::cmp::{max, min}; use std::collections::HashMap; use std::iter::zip; @@ -184,18 +183,20 @@ fn typeflow( dynamic_constants: &Vec<DynamicConstant>, num_parameters: u32, ) -> bool { - match dynamic_constants[root.idx()] { + match &dynamic_constants[root.idx()] { DynamicConstant::Constant(_) => true, - DynamicConstant::Parameter(idx) => idx < num_parameters as usize, - DynamicConstant::Add(x, y) - | DynamicConstant::Sub(x, y) - | DynamicConstant::Mul(x, y) + DynamicConstant::Parameter(idx) => *idx < num_parameters as usize, + DynamicConstant::Add(xs) + | DynamicConstant::Mul(xs) + | DynamicConstant::Min(xs) + | DynamicConstant::Max(xs) => { + xs.iter().all(|dc| check_dynamic_constants(*dc, dynamic_constants, num_parameters)) + } + DynamicConstant::Sub(x, y) | DynamicConstant::Div(x, y) - | DynamicConstant::Rem(x, y) - | DynamicConstant::Min(x, y) - | DynamicConstant::Max(x, y) => { - check_dynamic_constants(x, dynamic_constants, num_parameters) - && check_dynamic_constants(y, dynamic_constants, num_parameters) + | DynamicConstant::Rem(x, y) => { + check_dynamic_constants(*x, dynamic_constants, num_parameters) + && check_dynamic_constants(*y, dynamic_constants, num_parameters) } } } @@ -733,10 +734,14 @@ fn typeflow( } } + // Construct the substitution object + let mut subst = DCSubst::new(types, reverse_type_map, dynamic_constants, reverse_dynamic_constant_map, dc_args); + // Check argument types. for (input, param_ty) in zip(inputs.iter().skip(1), callee.param_types.iter()) { + let param_ty = subst.type_subst(*param_ty); if let Concrete(input_id) = input { - if !types_match(types, dynamic_constants, dc_args, *param_ty, *input_id) { + if param_ty != *input_id { return Error(String::from( "Call node mismatches argument types with callee function.", )); @@ -747,14 +752,7 @@ fn typeflow( } } - Concrete(type_subst( - types, - dynamic_constants, - reverse_type_map, - reverse_dynamic_constant_map, - dc_args, - callee.return_type, - )) + Concrete(subst.type_subst(callee.return_type)) } Node::IntrinsicCall { intrinsic, args: _ } => { let num_params = match intrinsic { @@ -1071,307 +1069,143 @@ pub fn cast_compatible(src_ty: &Type, dst_ty: &Type) -> bool { } /* - * Determine if the given type matches the parameter type when the provided - * dynamic constants are substituted in for the dynamic constants used in the - * parameter type. + * Data structures and methods for substituting given dynamic constant arguments into the provided + * types and dynamic constants */ -fn types_match( - types: &Vec<Type>, - dynamic_constants: &Vec<DynamicConstant>, - dc_args: &Box<[DynamicConstantID]>, - param: TypeID, - input: TypeID, -) -> bool { - // Note that we can't just check whether the type ids are equal since them - // being equal does not mean they match when we properly substitute in the - // dynamic constant arguments - - match (&types[param.idx()], &types[input.idx()]) { - (Type::Control, Type::Control) - | (Type::Boolean, Type::Boolean) - | (Type::Integer8, Type::Integer8) - | (Type::Integer16, Type::Integer16) - | (Type::Integer32, Type::Integer32) - | (Type::Integer64, Type::Integer64) - | (Type::UnsignedInteger8, Type::UnsignedInteger8) - | (Type::UnsignedInteger16, Type::UnsignedInteger16) - | (Type::UnsignedInteger32, Type::UnsignedInteger32) - | (Type::UnsignedInteger64, Type::UnsignedInteger64) - | (Type::Float32, Type::Float32) - | (Type::Float64, Type::Float64) => true, - (Type::Product(ps), Type::Product(is)) | (Type::Summation(ps), Type::Summation(is)) => { - ps.len() == is.len() - && ps - .iter() - .zip(is.iter()) - .all(|(p, i)| types_match(types, dynamic_constants, dc_args, *p, *i)) - } - (Type::Array(p, pds), Type::Array(i, ids)) => { - types_match(types, dynamic_constants, dc_args, *p, *i) - && pds.len() == ids.len() - && pds - .iter() - .zip(ids.iter()) - .all(|(pd, id)| dyn_consts_match(dynamic_constants, dc_args, *pd, *id)) - } - (_, _) => false, - } +struct DCSubst<'a> { + types: &'a mut Vec<Type>, + reverse_type_map: &'a mut HashMap<Type, TypeID>, + dynamic_constants: &'a mut Vec<DynamicConstant>, + reverse_dynamic_constant_map: &'a mut HashMap<DynamicConstant, DynamicConstantID>, + dc_args: &'a [DynamicConstantID], } -/* - * Determine if the given dynamic constant matches the parameter's dynamic - * constants when the provided dynamic constants are substituted in for the - * dynamic constants used in the parameter's dynamic constant. Implement dynamic - * constant normalization here as well - i.e., 1 * 2 * 3 = 6. - */ -fn dyn_consts_match( - dynamic_constants: &Vec<DynamicConstant>, - dc_args: &Box<[DynamicConstantID]>, - left: DynamicConstantID, - right: DynamicConstantID, -) -> bool { - // First, try evaluating the DCs and seeing if they're the same value. - if let (Some(cons1), Some(cons2)) = ( - evaluate_dynamic_constant(left, dynamic_constants), - evaluate_dynamic_constant(right, dynamic_constants), - ) { - return cons1 == cons2; +impl<'a> DynamicConstantView for DCSubst<'a> { + fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + &self.dynamic_constants[id.idx()] } - match ( - &dynamic_constants[left.idx()], - &dynamic_constants[right.idx()], - ) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => x == y, - (DynamicConstant::Parameter(l), DynamicConstant::Parameter(r)) => l == r, - (DynamicConstant::Parameter(i), _) => dyn_consts_match( - dynamic_constants, - dc_args, - min(right, dc_args[*i]), - max(right, dc_args[*i]), - ), - (_, DynamicConstant::Parameter(i)) => dyn_consts_match( + fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID { + if let Some(id) = self.reverse_dynamic_constant_map.get(&dc) { + *id + } else { + let id = DynamicConstantID::new(self.dynamic_constants.len()); + self.reverse_dynamic_constant_map.insert(dc.clone(), id); + self.dynamic_constants.push(dc); + id + } + } +} + +impl<'a> DCSubst<'a> { + fn new( + types: &'a mut Vec<Type>, + reverse_type_map: &'a mut HashMap<Type, TypeID>, + dynamic_constants: &'a mut Vec<DynamicConstant>, + reverse_dynamic_constant_map: &'a mut HashMap<DynamicConstant, DynamicConstantID>, + dc_args: &'a [DynamicConstantID], + ) -> Self { + Self { + types, + reverse_type_map, dynamic_constants, + reverse_dynamic_constant_map, dc_args, - min(left, dc_args[*i]), - max(left, dc_args[*i]), - ), - (DynamicConstant::Add(ll, lr), DynamicConstant::Add(rl, rr)) - | (DynamicConstant::Mul(ll, lr), DynamicConstant::Mul(rl, rr)) - | (DynamicConstant::Min(ll, lr), DynamicConstant::Min(rl, rr)) - | (DynamicConstant::Max(ll, lr), DynamicConstant::Max(rl, rr)) => { - // Normalize for associative ops by always looking at smaller DC ID - // as left arm and larger DC ID as right arm. - dyn_consts_match(dynamic_constants, dc_args, min(*ll, *lr), min(*rl, *rr)) - && dyn_consts_match(dynamic_constants, dc_args, max(*ll, *lr), max(*rl, *rr)) } - (DynamicConstant::Sub(ll, lr), DynamicConstant::Sub(rl, rr)) - | (DynamicConstant::Div(ll, lr), DynamicConstant::Div(rl, rr)) - | (DynamicConstant::Rem(ll, lr), DynamicConstant::Rem(rl, rr)) => { - dyn_consts_match(dynamic_constants, dc_args, *ll, *rl) - && dyn_consts_match(dynamic_constants, dc_args, *lr, *rr) - } - (_, _) => false, } -} -/* - * Substitutes the given dynamic constant arguments into the provided type and - * returns the appropriate typeID (potentially creating new types and dynamic - * constants in the process) - */ -fn type_subst( - types: &mut Vec<Type>, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_type_map: &mut HashMap<Type, TypeID>, - reverse_dynamic_constant_map: &mut HashMap<DynamicConstant, DynamicConstantID>, - dc_args: &Box<[DynamicConstantID]>, - typ: TypeID, -) -> TypeID { fn intern_type( + &mut self, ty: Type, - types: &mut Vec<Type>, - reverse_type_map: &mut HashMap<Type, TypeID>, ) -> TypeID { - if let Some(id) = reverse_type_map.get(&ty) { + if let Some(id) = self.reverse_type_map.get(&ty) { *id } else { - let id = TypeID::new(types.len()); - reverse_type_map.insert(ty.clone(), id); - types.push(ty); + let id = TypeID::new(self.types.len()); + self.reverse_type_map.insert(ty.clone(), id); + self.types.push(ty); id } } - match &types[typ.idx()] { - Type::Control - | Type::Boolean - | Type::Integer8 - | Type::Integer16 - | Type::Integer32 - | Type::Integer64 - | Type::UnsignedInteger8 - | Type::UnsignedInteger16 - | Type::UnsignedInteger32 - | Type::UnsignedInteger64 - | Type::Float32 - | Type::Float64 => typ, - Type::Product(ts) => { - let mut new_ts = vec![]; - for t in ts.clone().iter() { - new_ts.push(type_subst( - types, - dynamic_constants, - reverse_type_map, - reverse_dynamic_constant_map, - dc_args, - *t, - )); + fn type_subst( + &mut self, + typ: TypeID, + ) -> TypeID { + match &self.types[typ.idx()] { + Type::Control + | Type::Boolean + | Type::Integer8 + | Type::Integer16 + | Type::Integer32 + | Type::Integer64 + | Type::UnsignedInteger8 + | Type::UnsignedInteger16 + | Type::UnsignedInteger32 + | Type::UnsignedInteger64 + | Type::Float32 + | Type::Float64 => typ, + Type::Product(ts) => { + let new_ts = ts.clone().iter().map(|t| self.type_subst(*t)).collect(); + self.intern_type(Type::Product(new_ts)) } - intern_type(Type::Product(new_ts.into()), types, reverse_type_map) - } - Type::Summation(ts) => { - let mut new_ts = vec![]; - for t in ts.clone().iter() { - new_ts.push(type_subst( - types, - dynamic_constants, - reverse_type_map, - reverse_dynamic_constant_map, - dc_args, - *t, - )); + Type::Summation(ts) => { + let new_ts = ts.clone().iter().map(|t| self.type_subst(*t)).collect(); + self.intern_type(Type::Summation(new_ts)) } - intern_type(Type::Summation(new_ts.into()), types, reverse_type_map) - } - Type::Array(elem, dims) => { - let ds = dims.clone(); - let new_elem = type_subst( - types, - dynamic_constants, - reverse_type_map, - reverse_dynamic_constant_map, - dc_args, - *elem, - ); - let mut new_dims = vec![]; - for d in ds.iter() { - new_dims.push(dyn_const_subst( - dynamic_constants, - reverse_dynamic_constant_map, - dc_args, - *d, - )); + Type::Array(elem, dims) => { + let elem = *elem; + let new_dims = dims.clone().iter().map(|d| self.dyn_const_subst(*d)).collect(); + let new_elem = self.type_subst(elem); + self.intern_type(Type::Array(new_elem, new_dims)) } - intern_type( - Type::Array(new_elem, new_dims.into()), - types, - reverse_type_map, - ) } } -} -fn dyn_const_subst( - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_dynamic_constant_map: &mut HashMap<DynamicConstant, DynamicConstantID>, - dc_args: &Box<[DynamicConstantID]>, - dyn_const: DynamicConstantID, -) -> DynamicConstantID { - fn intern_dyn_const( - dc: DynamicConstant, - dynamic_constants: &mut Vec<DynamicConstant>, - reverse_dynamic_constant_map: &mut HashMap<DynamicConstant, DynamicConstantID>, + fn dyn_const_subst( + &mut self, + dyn_const: DynamicConstantID, ) -> DynamicConstantID { - if let Some(id) = reverse_dynamic_constant_map.get(&dc) { - *id - } else { - let id = DynamicConstantID::new(dynamic_constants.len()); - reverse_dynamic_constant_map.insert(dc.clone(), id); - dynamic_constants.push(dc); - id - } - } - - match &dynamic_constants[dyn_const.idx()] { - DynamicConstant::Constant(_) => dyn_const, - DynamicConstant::Parameter(i) => dc_args[*i], - DynamicConstant::Add(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Add(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) - } - DynamicConstant::Sub(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Sub(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) - } - DynamicConstant::Mul(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Mul(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) - } - DynamicConstant::Div(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Div(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) - } - DynamicConstant::Rem(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Rem(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) - } - DynamicConstant::Min(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Min(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) - } - DynamicConstant::Max(l, r) => { - let x = *l; - let y = *r; - let sx = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, x); - let sy = dyn_const_subst(dynamic_constants, reverse_dynamic_constant_map, dc_args, y); - intern_dyn_const( - DynamicConstant::Max(sx, sy), - dynamic_constants, - reverse_dynamic_constant_map, - ) + match &self.dynamic_constants[dyn_const.idx()] { + DynamicConstant::Constant(_) => dyn_const, + DynamicConstant::Parameter(i) => self.dc_args[*i], + DynamicConstant::Add(xs) => { + let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + dc_add(sxs, self) + } + DynamicConstant::Sub(l, r) => { + let x = *l; + let y = *r; + let sx = self.dyn_const_subst(x); + let sy = self.dyn_const_subst(y); + dc_sub(sx, sy, self) + } + DynamicConstant::Mul(xs) => { + let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + dc_mul(sxs, self) + } + DynamicConstant::Div(l, r) => { + let x = *l; + let y = *r; + let sx = self.dyn_const_subst(x); + let sy = self.dyn_const_subst(y); + dc_div(sx, sy, self) + } + DynamicConstant::Rem(l, r) => { + let x = *l; + let y = *r; + let sx = self.dyn_const_subst(x); + let sy = self.dyn_const_subst(y); + dc_rem(sx, sy, self) + } + DynamicConstant::Min(xs) => { + let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + dc_min(sxs, self) + } + DynamicConstant::Max(xs) => { + let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + dc_max(sxs, self) + } } } } -- GitLab From c156579b16eadcf46123ab795aa7f6e24a2b7a89 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 10:27:37 -0600 Subject: [PATCH 08/16] Handle n-ary dynamic constants in cpu back-end --- hercules_cg/src/cpu.rs | 108 +++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 30 deletions(-) diff --git a/hercules_cg/src/cpu.rs b/hercules_cg/src/cpu.rs index 3750c4f6..94b8cc5d 100644 --- a/hercules_cg/src/cpu.rs +++ b/hercules_cg/src/cpu.rs @@ -562,12 +562,12 @@ impl<'a> CPUContext<'a> { ) -> Result<(), Error> { let body = &mut block.body; for dc in dynamic_constants_bottom_up(&self.dynamic_constants) { - match self.dynamic_constants[dc.idx()] { + match &self.dynamic_constants[dc.idx()] { DynamicConstant::Constant(val) => { write!(body, " %dc{} = bitcast i64 {} to i64\n", dc.idx(), val)? } DynamicConstant::Parameter(idx) => { - if idx < num_dc_params as usize { + if *idx < num_dc_params as usize { write!( body, " %dc{} = bitcast i64 %dc_p{} to i64\n", @@ -578,13 +578,25 @@ impl<'a> CPUContext<'a> { write!(body, " %dc{} = bitcast i64 0 to i64\n", dc.idx())? } } - DynamicConstant::Add(left, right) => write!( - body, - " %dc{} = add i64%dc{},%dc{}\n", - dc.idx(), - left.idx(), - right.idx() - )?, + DynamicConstant::Add(xs) => { + let mut xs = xs.iter().peekable(); + let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); + let mut idx = 0; + while let Some(x) = xs.next() { + let new_val = format!("%dc{}{}", dc.idx(), + if xs.peek().is_some() { format!(".{}", idx) } + else { "".to_string() }); + write!( + body, + " {} = add i64{},%dc{}\n", + new_val, + cur_value, + x.idx() + )?; + cur_value = new_val; + idx += 1; + } + } DynamicConstant::Sub(left, right) => write!( body, " %dc{} = sub i64%dc{},%dc{}\n", @@ -592,13 +604,25 @@ impl<'a> CPUContext<'a> { left.idx(), right.idx() )?, - DynamicConstant::Mul(left, right) => write!( - body, - " %dc{} = mul i64%dc{},%dc{}\n", - dc.idx(), - left.idx(), - right.idx() - )?, + DynamicConstant::Mul(xs) => { + let mut xs = xs.iter().peekable(); + let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); + let mut idx = 0; + while let Some(x) = xs.next() { + let new_val = format!("%dc{}{}", dc.idx(), + if xs.peek().is_some() { format!(".{}", idx) } + else { "".to_string() }); + write!( + body, + " {} = mul i64{},%dc{}\n", + new_val, + cur_value, + x.idx() + )?; + cur_value = new_val; + idx += 1; + } + } DynamicConstant::Div(left, right) => write!( body, " %dc{} = udiv i64%dc{},%dc{}\n", @@ -613,20 +637,44 @@ impl<'a> CPUContext<'a> { left.idx(), right.idx() )?, - DynamicConstant::Min(left, right) => write!( - body, - " %dc{} = call @llvm.umin.i64(i64%dc{},i64%dc{})\n", - dc.idx(), - left.idx(), - right.idx() - )?, - DynamicConstant::Max(left, right) => write!( - body, - " %dc{} = call @llvm.umax.i64(i64%dc{},i64%dc{})\n", - dc.idx(), - left.idx(), - right.idx() - )?, + DynamicConstant::Min(xs) => { + let mut xs = xs.iter().peekable(); + let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); + let mut idx = 0; + while let Some(x) = xs.next() { + let new_val = format!("%dc{}{}", dc.idx(), + if xs.peek().is_some() { format!(".{}", idx) } + else { "".to_string() }); + write!( + body, + " {} = call @llvm.umin.i64(i64{},i64%dc{}))\n", + new_val, + cur_value, + x.idx() + )?; + cur_value = new_val; + idx += 1; + } + } + DynamicConstant::Max(xs) => { + let mut xs = xs.iter().peekable(); + let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); + let mut idx = 0; + while let Some(x) = xs.next() { + let new_val = format!("%dc{}{}", dc.idx(), + if xs.peek().is_some() { format!(".{}", idx) } + else { "".to_string() }); + write!( + body, + " {} = call @llvm.umax.i64(i64{},i64%dc{}))\n", + new_val, + cur_value, + x.idx() + )?; + cur_value = new_val; + idx += 1; + } + } } } Ok(()) -- GitLab From f826fd64b6375af5690d639bf960606d41f4b44f Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 10:37:12 -0600 Subject: [PATCH 09/16] Handle n-ary dynamic constants in rt back-end --- hercules_cg/src/rt.rs | 86 +++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/hercules_cg/src/rt.rs b/hercules_cg/src/rt.rs index 1bfc01fe..ddf892fc 100644 --- a/hercules_cg/src/rt.rs +++ b/hercules_cg/src/rt.rs @@ -441,57 +441,89 @@ impl<'a> RTContext<'a> { id: DynamicConstantID, w: &mut W, ) -> Result<(), Error> { - match self.module.dynamic_constants[id.idx()] { + match &self.module.dynamic_constants[id.idx()] { DynamicConstant::Constant(val) => write!(w, "{}", val)?, DynamicConstant::Parameter(idx) => write!(w, "dc_p{}", idx)?, - DynamicConstant::Add(left, right) => { + DynamicConstant::Add(xs) => { write!(w, "(")?; - self.codegen_dynamic_constant(left, w)?; - write!(w, "+")?; - self.codegen_dynamic_constant(right, w)?; + let mut xs = xs.iter(); + self.codegen_dynamic_constant(*xs.next().unwrap(), w)?; + for x in xs { + write!(w, "+")?; + self.codegen_dynamic_constant(*x, w)?; + } write!(w, ")")?; } DynamicConstant::Sub(left, right) => { write!(w, "(")?; - self.codegen_dynamic_constant(left, w)?; + self.codegen_dynamic_constant(*left, w)?; write!(w, "-")?; - self.codegen_dynamic_constant(right, w)?; + self.codegen_dynamic_constant(*right, w)?; write!(w, ")")?; } - DynamicConstant::Mul(left, right) => { + DynamicConstant::Mul(xs) => { write!(w, "(")?; - self.codegen_dynamic_constant(left, w)?; - write!(w, "*")?; - self.codegen_dynamic_constant(right, w)?; + let mut xs = xs.iter(); + self.codegen_dynamic_constant(*xs.next().unwrap(), w)?; + for x in xs { + write!(w, "*")?; + self.codegen_dynamic_constant(*x, w)?; + } write!(w, ")")?; } DynamicConstant::Div(left, right) => { write!(w, "(")?; - self.codegen_dynamic_constant(left, w)?; + self.codegen_dynamic_constant(*left, w)?; write!(w, "/")?; - self.codegen_dynamic_constant(right, w)?; + self.codegen_dynamic_constant(*right, w)?; write!(w, ")")?; } DynamicConstant::Rem(left, right) => { write!(w, "(")?; - self.codegen_dynamic_constant(left, w)?; + self.codegen_dynamic_constant(*left, w)?; write!(w, "%")?; - self.codegen_dynamic_constant(right, w)?; + self.codegen_dynamic_constant(*right, w)?; write!(w, ")")?; } - DynamicConstant::Min(left, right) => { - write!(w, "::core::cmp::min(")?; - self.codegen_dynamic_constant(left, w)?; - write!(w, ",")?; - self.codegen_dynamic_constant(right, w)?; - write!(w, ")")?; + DynamicConstant::Min(xs) => { + let mut xs = xs.iter().peekable(); + + // Track the number of parentheses we open that need to be closed later + let mut opens = 0; + while let Some(x) = xs.next() { + if xs.peek().is_none() { + // For the last element, we just print it + self.codegen_dynamic_constant(*x, w)?; + } else { + // Otherwise, we create a new call to min and print the element as the + // first argument + write!(w, "::core::cmp::min(")?; + self.codegen_dynamic_constant(*x, w)?; + write!(w, ",")?; + opens += 1; + } + } + for _ in 0..opens { + write!(w, ")")?; + } } - DynamicConstant::Max(left, right) => { - write!(w, "::core::cmp::max(")?; - self.codegen_dynamic_constant(left, w)?; - write!(w, ",")?; - self.codegen_dynamic_constant(right, w)?; - write!(w, ")")?; + DynamicConstant::Max(xs) => { + let mut xs = xs.iter().peekable(); + + let mut opens = 0; + while let Some(x) = xs.next() { + if xs.peek().is_none() { + self.codegen_dynamic_constant(*x, w)?; + } else { + write!(w, "::core::cmp::max(")?; + self.codegen_dynamic_constant(*x, w)?; + write!(w, ",")?; + opens += 1; + } + } + for _ in 0..opens { + write!(w, ")")?; + } } } Ok(()) -- GitLab From 9338f1eb0d2f26a76c122378e609a9801cff8947 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 12:18:41 -0600 Subject: [PATCH 10/16] Fixes to optimizations and interface --- Cargo.lock | 1 + hercules_ir/Cargo.toml | 1 + hercules_ir/src/build.rs | 21 +- hercules_ir/src/dc_normalization.rs | 344 +++++++++++++++------------- hercules_ir/src/ir.rs | 28 +++ hercules_ir/src/parse.rs | 5 +- hercules_ir/src/typecheck.rs | 17 +- hercules_opt/src/editor.rs | 5 +- hercules_opt/src/gcm.rs | 18 +- hercules_opt/src/lift_dc_math.rs | 14 +- hercules_opt/src/utils.rs | 44 +--- 11 files changed, 267 insertions(+), 231 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bb64bd2..c02ec0b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -824,6 +824,7 @@ name = "hercules_ir" version = "0.1.0" dependencies = [ "bitvec", + "either", "nom", "ordered-float", "rand", diff --git a/hercules_ir/Cargo.toml b/hercules_ir/Cargo.toml index deda9cc5..26950d4b 100644 --- a/hercules_ir/Cargo.toml +++ b/hercules_ir/Cargo.toml @@ -10,3 +10,4 @@ nom = "*" ordered-float = { version = "*", features = ["serde"] } bitvec = "*" serde = { version = "*", features = ["derive"] } +either = "*" diff --git a/hercules_ir/src/build.rs b/hercules_ir/src/build.rs index b7844806..b8044045 100644 --- a/hercules_ir/src/build.rs +++ b/hercules_ir/src/build.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap, HashSet}; +use std::ops::Deref; use crate::*; @@ -26,7 +27,7 @@ pub struct Builder<'a> { } impl<'a> DynamicConstantView for Builder<'a> { - fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + fn get_dynconst(&self, id: DynamicConstantID) -> impl Deref<Target = DynamicConstant> + '_ { &self.module.dynamic_constants[id.idx()] } @@ -412,11 +413,11 @@ impl<'a> Builder<'a> { } pub fn create_dynamic_constant_constant(&mut self, val: usize) -> DynamicConstantID { - dc_const(val, self) + self.dc_const(val) } pub fn create_dynamic_constant_parameter(&mut self, idx: usize) -> DynamicConstantID { - dc_param(idx, self) + self.dc_param(idx) } pub fn create_dynamic_constant_add( @@ -424,14 +425,14 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_add(vec![x, y], self) + self.dc_add(vec![x, y]) } pub fn create_dynamic_constant_add_many( &mut self, xs: Vec<DynamicConstantID>, ) -> DynamicConstantID { - dc_add(xs, self) + self.dc_add(xs) } pub fn create_dynamic_constant_sub( @@ -439,7 +440,7 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_sub(x, y, self) + self.dc_sub(x, y) } pub fn create_dynamic_constant_mul( @@ -447,14 +448,14 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_mul(vec![x, y], self) + self.dc_mul(vec![x, y]) } pub fn create_dynamic_constant_mul_many( &mut self, xs: Vec<DynamicConstantID>, ) -> DynamicConstantID { - dc_mul(xs, self) + self.dc_mul(xs) } pub fn create_dynamic_constant_div( @@ -462,7 +463,7 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_div(x, y, self) + self.dc_div(x, y) } pub fn create_dynamic_constant_rem( @@ -470,7 +471,7 @@ impl<'a> Builder<'a> { x: DynamicConstantID, y: DynamicConstantID, ) -> DynamicConstantID { - dc_rem(x, y, self) + self.dc_rem(x, y) } pub fn create_field_index(&self, idx: usize) -> Index { diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index 4705eac3..ca76f3f7 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -1,206 +1,228 @@ use crate::*; use std::cmp::{min, max}; +use std::ops::Deref; -pub trait DynamicConstantView { - fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant; +use either::Either; + +pub trait DynamicConstantView +{ + fn get_dynconst(&self, id: DynamicConstantID) -> impl Deref<Target = DynamicConstant> + '_; fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID; -} -pub fn dc_const<T: DynamicConstantView>( - val: usize, - view: &mut T, -) -> DynamicConstantID { - view.add_dynconst(DynamicConstant::Constant(val)) -} + fn dc_const( + &mut self, + val: usize, + ) -> DynamicConstantID { + self.add_dynconst(DynamicConstant::Constant(val)) + } -pub fn dc_param<T: DynamicConstantView>( - index: usize, - view: &mut T, -) -> DynamicConstantID { - view.add_dynconst(DynamicConstant::Parameter(index)) -} + fn dc_param( + &mut self, + index: usize, + ) -> DynamicConstantID { + self.add_dynconst(DynamicConstant::Parameter(index)) + } -pub fn dc_add<T: DynamicConstantView>( - dcs: Vec<DynamicConstantID>, - view: &mut T, -) -> DynamicConstantID { - let mut constant_val = 0; - let mut fields = vec![]; + fn dc_add( + &mut self, + dcs: Vec<DynamicConstantID>, + ) -> DynamicConstantID { + let mut constant_val = 0; + let mut fields = vec![]; - for dc in dcs { - match view.get_dynconst(dc) { - DynamicConstant::Constant(x) => constant_val += x, - DynamicConstant::Add(xs) => fields.extend_from_slice(xs), - _ => fields.push(dc), + for dc in dcs { + match self.get_dynconst(dc).deref() { + DynamicConstant::Constant(x) => constant_val += x, + DynamicConstant::Add(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), + } } - } - // If either there are no fields or the constant is non-zero, add it - if constant_val != 0 || fields.len() == 0 { - fields.push(view.add_dynconst(DynamicConstant::Constant(constant_val))); - } + // If either there are no fields or the constant is non-zero, add it + if constant_val != 0 || fields.len() == 0 { + fields.push(self.add_dynconst(DynamicConstant::Constant(constant_val))); + } - if fields.len() <= 1 { - // If there is only one term to add, just return it - fields[0] - } else { - fields.sort(); - view.add_dynconst(DynamicConstant::Add(fields)) + if fields.len() <= 1 { + // If there is only one term to add, just return it + fields[0] + } else { + fields.sort(); + self.add_dynconst(DynamicConstant::Add(fields)) + } } -} -pub fn dc_mul<T: DynamicConstantView>( - dcs: Vec<DynamicConstantID>, - view: &mut T, -) -> DynamicConstantID { - let mut constant_val = 1; - let mut fields = vec![]; + fn dc_mul( + &mut self, + dcs: Vec<DynamicConstantID>, + ) -> DynamicConstantID { + let mut constant_val = 1; + let mut fields = vec![]; - for dc in dcs { - match view.get_dynconst(dc) { - DynamicConstant::Constant(x) => constant_val *= x, - DynamicConstant::Mul(xs) => fields.extend_from_slice(xs), - _ => fields.push(dc), + for dc in dcs { + match self.get_dynconst(dc).deref() { + DynamicConstant::Constant(x) => constant_val *= x, + DynamicConstant::Mul(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), + } } - } - if constant_val == 0 { - return view.add_dynconst(DynamicConstant::Constant(0)); - } + if constant_val == 0 { + return self.add_dynconst(DynamicConstant::Constant(0)); + } - if constant_val != 1 || fields.len() == 0 { - fields.push(view.add_dynconst(DynamicConstant::Constant(constant_val))); - } + if constant_val != 1 || fields.len() == 0 { + fields.push(self.add_dynconst(DynamicConstant::Constant(constant_val))); + } - if fields.len() <= 1 { - fields[0] - } else { - fields.sort(); - view.add_dynconst(DynamicConstant::Mul(fields)) + if fields.len() <= 1 { + fields[0] + } else { + fields.sort(); + self.add_dynconst(DynamicConstant::Mul(fields)) + } } -} -pub fn dc_min<T: DynamicConstantView>( - dcs: Vec<DynamicConstantID>, - view: &mut T, -) -> DynamicConstantID { - let mut constant_val : Option<usize> = None; - let mut fields = vec![]; - - for dc in dcs { - match view.get_dynconst(dc) { - DynamicConstant::Constant(x) => { - if let Some(cur_min) = constant_val { - constant_val = Some(min(cur_min, *x)); - } else { - constant_val = Some(*x); + fn dc_min( + &mut self, + dcs: Vec<DynamicConstantID>, + ) -> DynamicConstantID { + let mut constant_val : Option<usize> = None; + let mut fields = vec![]; + + for dc in dcs { + match self.get_dynconst(dc).deref() { + DynamicConstant::Constant(x) => { + if let Some(cur_min) = constant_val { + constant_val = Some(min(cur_min, *x)); + } else { + constant_val = Some(*x); + } } + DynamicConstant::Min(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), } - DynamicConstant::Min(xs) => fields.extend_from_slice(xs), - _ => fields.push(dc), } - } - if let Some(const_val) = constant_val { - fields.push(view.add_dynconst(DynamicConstant::Constant(const_val))); - } + if let Some(const_val) = constant_val { + fields.push(self.add_dynconst(DynamicConstant::Constant(const_val))); + } - assert!(fields.len() > 0, "Min of 0 dynamic constant expressions is undefined"); + assert!(fields.len() > 0, "Min of 0 dynamic constant expressions is undefined"); - if fields.len() <= 1 { - fields[0] - } else { - fields.sort(); - view.add_dynconst(DynamicConstant::Min(fields)) + if fields.len() <= 1 { + fields[0] + } else { + fields.sort(); + self.add_dynconst(DynamicConstant::Min(fields)) + } } -} -pub fn dc_max<T: DynamicConstantView>( - dcs: Vec<DynamicConstantID>, - view: &mut T, -) -> DynamicConstantID { - let mut constant_val : Option<usize> = None; - let mut fields = vec![]; - - for dc in dcs { - match view.get_dynconst(dc) { - DynamicConstant::Constant(x) => { - if let Some(cur_max) = constant_val { - constant_val = Some(max(cur_max, *x)); - } else { - constant_val = Some(*x); + fn dc_max( + &mut self, + dcs: Vec<DynamicConstantID>, + ) -> DynamicConstantID { + let mut constant_val : Option<usize> = None; + let mut fields = vec![]; + + for dc in dcs { + match self.get_dynconst(dc).deref() { + DynamicConstant::Constant(x) => { + if let Some(cur_max) = constant_val { + constant_val = Some(max(cur_max, *x)); + } else { + constant_val = Some(*x); + } } + DynamicConstant::Max(xs) => fields.extend_from_slice(xs), + _ => fields.push(dc), } - DynamicConstant::Max(xs) => fields.extend_from_slice(xs), - _ => fields.push(dc), } - } - if let Some(const_val) = constant_val { - fields.push(view.add_dynconst(DynamicConstant::Constant(const_val))); - } + if let Some(const_val) = constant_val { + fields.push(self.add_dynconst(DynamicConstant::Constant(const_val))); + } - assert!(fields.len() > 0, "Max of 0 dynamic constant expressions is undefined"); + assert!(fields.len() > 0, "Max of 0 dynamic constant expressions is undefined"); - if fields.len() <= 1 { - fields[0] - } else { - fields.sort(); - view.add_dynconst(DynamicConstant::Max(fields)) + if fields.len() <= 1 { + fields[0] + } else { + fields.sort(); + self.add_dynconst(DynamicConstant::Max(fields)) + } } -} -pub fn dc_sub<T: DynamicConstantView>( - x: DynamicConstantID, - y: DynamicConstantID, - view: &mut T, -) -> DynamicConstantID { - match (view.get_dynconst(x), view.get_dynconst(y)) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - view.add_dynconst(DynamicConstant::Constant(x - y)), - (_, DynamicConstant::Constant(0)) => x, - _ => view.add_dynconst(DynamicConstant::Sub(x, y)), + fn dc_sub( + &mut self, + x: DynamicConstantID, + y: DynamicConstantID, + ) -> DynamicConstantID { + let dc = + match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => + Either::Left(DynamicConstant::Constant(x - y)), + (_, DynamicConstant::Constant(0)) => Either::Right(x), + _ => Either::Left(DynamicConstant::Sub(x, y)), + }; + + match dc { + Either::Left(dc) => self.add_dynconst(dc), + Either::Right(id) => id, + } } -} -pub fn dc_div<T: DynamicConstantView>( - x: DynamicConstantID, - y: DynamicConstantID, - view: &mut T, -) -> DynamicConstantID { - match (view.get_dynconst(x), view.get_dynconst(y)) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - view.add_dynconst(DynamicConstant::Constant(x / y)), - (_, DynamicConstant::Constant(1)) => x, - _ => view.add_dynconst(DynamicConstant::Div(x, y)), + fn dc_div( + &mut self, + x: DynamicConstantID, + y: DynamicConstantID, + ) -> DynamicConstantID { + let dc = + match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => + Either::Left(DynamicConstant::Constant(x / y)), + (_, DynamicConstant::Constant(1)) => Either::Right(x), + _ => Either::Left(DynamicConstant::Div(x, y)), + }; + + match dc { + Either::Left(dc) => self.add_dynconst(dc), + Either::Right(id) => id, + } } -} -pub fn dc_rem<T: DynamicConstantView>( - x: DynamicConstantID, - y: DynamicConstantID, - view: &mut T, -) -> DynamicConstantID { - match (view.get_dynconst(x), view.get_dynconst(y)) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - view.add_dynconst(DynamicConstant::Constant(x % y)), - _ => view.add_dynconst(DynamicConstant::Rem(x, y)), + fn dc_rem( + &mut self, + x: DynamicConstantID, + y: DynamicConstantID, + ) -> DynamicConstantID { + let dc = + match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => + Either::Left(DynamicConstant::Constant(x % y)), + _ => Either::Left(DynamicConstant::Rem(x, y)), + }; + + match dc { + Either::Left(dc) => self.add_dynconst(dc), + Either::Right(id) => id, + } } -} -pub fn dc_normalize<T: DynamicConstantView>( - dc: DynamicConstant, - view: &mut T, -) -> DynamicConstantID { - match dc { - DynamicConstant::Add(xs) => dc_add(xs, view), - DynamicConstant::Mul(xs) => dc_mul(xs, view), - DynamicConstant::Min(xs) => dc_min(xs, view), - DynamicConstant::Max(xs) => dc_max(xs, view), - DynamicConstant::Sub(x, y) => dc_sub(x, y, view), - DynamicConstant::Div(x, y) => dc_div(x, y, view), - DynamicConstant::Rem(x, y) => dc_rem(x, y, view), - _ => view.add_dynconst(dc), + fn dc_normalize( + &mut self, + dc: DynamicConstant, + ) -> DynamicConstantID { + match dc { + DynamicConstant::Add(xs) => self.dc_add(xs), + DynamicConstant::Mul(xs) => self.dc_mul(xs), + DynamicConstant::Min(xs) => self.dc_min(xs), + DynamicConstant::Max(xs) => self.dc_max(xs), + DynamicConstant::Sub(x, y) => self.dc_sub(x, y), + DynamicConstant::Div(x, y) => self.dc_div(x, y), + DynamicConstant::Rem(x, y) => self.dc_rem(x, y), + _ => self.add_dynconst(dc), + } } } diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs index 784bc2de..ba8d607e 100644 --- a/hercules_ir/src/ir.rs +++ b/hercules_ir/src/ir.rs @@ -1020,6 +1020,34 @@ impl Constant { } impl DynamicConstant { + pub fn add(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Add(vec![x, y]) + } + + pub fn sub(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Sub(x, y) + } + + pub fn mul(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Mul(vec![x, y]) + } + + pub fn div(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Div(x, y) + } + + pub fn rem(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Rem(x, y) + } + + pub fn min(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Min(vec![x, y]) + } + + pub fn max(x: DynamicConstantID, y: DynamicConstantID) -> Self { + Self::Max(vec![x, y]) + } + pub fn is_parameter(&self) -> bool { if let DynamicConstant::Parameter(_) = self { true diff --git a/hercules_ir/src/parse.rs b/hercules_ir/src/parse.rs index 1f6d931e..257dd4d9 100644 --- a/hercules_ir/src/parse.rs +++ b/hercules_ir/src/parse.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; +use std::ops::Deref; use std::str::FromStr; use crate::*; @@ -87,7 +88,7 @@ impl<'a> Context<'a> { } fn get_dynamic_constant_id(&mut self, dynamic_constant: DynamicConstant) -> DynamicConstantID { - dc_normalize(dynamic_constant, self) + self.dc_normalize(dynamic_constant) } fn get_label_id(&mut self, label: String) -> LabelID { @@ -102,7 +103,7 @@ impl<'a> Context<'a> { } impl<'a> DynamicConstantView for Context<'a> { - fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + fn get_dynconst(&self, id: DynamicConstantID) -> impl Deref<Target = DynamicConstant> + '_ { &self.reverse_dynamic_constant_map[&id] } diff --git a/hercules_ir/src/typecheck.rs b/hercules_ir/src/typecheck.rs index 698223b4..fdbbd46e 100644 --- a/hercules_ir/src/typecheck.rs +++ b/hercules_ir/src/typecheck.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::iter::zip; +use std::ops::Deref; use crate::*; @@ -1081,7 +1082,7 @@ struct DCSubst<'a> { } impl<'a> DynamicConstantView for DCSubst<'a> { - fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + fn get_dynconst(&self, id: DynamicConstantID) -> impl Deref<Target = DynamicConstant> + '_ { &self.dynamic_constants[id.idx()] } @@ -1171,40 +1172,40 @@ impl<'a> DCSubst<'a> { DynamicConstant::Parameter(i) => self.dc_args[*i], DynamicConstant::Add(xs) => { let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); - dc_add(sxs, self) + self.dc_add(sxs) } DynamicConstant::Sub(l, r) => { let x = *l; let y = *r; let sx = self.dyn_const_subst(x); let sy = self.dyn_const_subst(y); - dc_sub(sx, sy, self) + self.dc_sub(sx, sy) } DynamicConstant::Mul(xs) => { let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); - dc_mul(sxs, self) + self.dc_mul(sxs) } DynamicConstant::Div(l, r) => { let x = *l; let y = *r; let sx = self.dyn_const_subst(x); let sy = self.dyn_const_subst(y); - dc_div(sx, sy, self) + self.dc_div(sx, sy) } DynamicConstant::Rem(l, r) => { let x = *l; let y = *r; let sx = self.dyn_const_subst(x); let sy = self.dyn_const_subst(y); - dc_rem(sx, sy, self) + self.dc_rem(sx, sy) } DynamicConstant::Min(xs) => { let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); - dc_min(sxs, self) + self.dc_min(sxs) } DynamicConstant::Max(xs) => { let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); - dc_max(sxs, self) + self.dc_max(sxs) } } } diff --git a/hercules_opt/src/editor.rs b/hercules_opt/src/editor.rs index 8164ff9d..cbfa49c0 100644 --- a/hercules_opt/src/editor.rs +++ b/hercules_opt/src/editor.rs @@ -8,6 +8,7 @@ use either::Either; use hercules_ir::def_use::*; use hercules_ir::ir::*; +use hercules_ir::DynamicConstantView; /* * Helper object for editing Hercules functions in a trackable manner. Edits @@ -725,7 +726,7 @@ impl<'a, 'b> FunctionEdit<'a, 'b> { } pub fn add_dynamic_constant(&mut self, dynamic_constant: DynamicConstant) -> DynamicConstantID { - dc_normalize(dynamic_constant, self) + self.dc_normalize(dynamic_constant) } pub fn get_dynamic_constant( @@ -756,7 +757,7 @@ impl<'a, 'b> FunctionEdit<'a, 'b> { } impl<'a, 'b> DynamicConstantView for FunctionEdit<'a, 'b> { - fn get_dynconst(&self, id: DynamicConstantID) -> &DynamicConstant { + fn get_dynconst(&self, id: DynamicConstantID) -> impl Deref<Target = DynamicConstant> + '_ { self.get_dynamic_constant(id) } diff --git a/hercules_opt/src/gcm.rs b/hercules_opt/src/gcm.rs index b5822a51..f80973ee 100644 --- a/hercules_opt/src/gcm.rs +++ b/hercules_opt/src/gcm.rs @@ -1061,9 +1061,9 @@ fn align(edit: &mut FunctionEdit, mut acc: DynamicConstantID, align: usize) -> D if align != 1 { let align_dc = edit.add_dynamic_constant(DynamicConstant::Constant(align)); let align_m1_dc = edit.add_dynamic_constant(DynamicConstant::Constant(align - 1)); - acc = edit.add_dynamic_constant(DynamicConstant::Add(acc, align_m1_dc)); - acc = edit.add_dynamic_constant(DynamicConstant::Div(acc, align_dc)); - acc = edit.add_dynamic_constant(DynamicConstant::Mul(acc, align_dc)); + acc = edit.add_dynamic_constant(DynamicConstant::add(acc, align_m1_dc)); + acc = edit.add_dynamic_constant(DynamicConstant::div(acc, align_dc)); + acc = edit.add_dynamic_constant(DynamicConstant::mul(acc, align_dc)); } acc } @@ -1095,7 +1095,7 @@ fn type_size(edit: &mut FunctionEdit, ty_id: TypeID, alignments: &Vec<usize>) -> // the field. let field_size = type_size(edit, field, alignments); acc_size = align(edit, acc_size, alignments[field.idx()]); - acc_size = edit.add_dynamic_constant(DynamicConstant::Add(acc_size, field_size)); + acc_size = edit.add_dynamic_constant(DynamicConstant::add(acc_size, field_size)); } // Finally, round up to the alignment of the whole product, since // the size needs to be a multiple of the alignment. @@ -1109,11 +1109,11 @@ fn type_size(edit: &mut FunctionEdit, ty_id: TypeID, alignments: &Vec<usize>) -> // Pick the size of the largest variant, since that's the most // memory we would need. let variant_size = type_size(edit, variant, alignments); - acc_size = edit.add_dynamic_constant(DynamicConstant::Max(acc_size, variant_size)); + acc_size = edit.add_dynamic_constant(DynamicConstant::max(acc_size, variant_size)); } // Add one byte for the discriminant and align the whole summation. let one = edit.add_dynamic_constant(DynamicConstant::Constant(1)); - acc_size = edit.add_dynamic_constant(DynamicConstant::Add(acc_size, one)); + acc_size = edit.add_dynamic_constant(DynamicConstant::add(acc_size, one)); acc_size = align(edit, acc_size, alignments[ty_id.idx()]); acc_size } @@ -1121,7 +1121,7 @@ fn type_size(edit: &mut FunctionEdit, ty_id: TypeID, alignments: &Vec<usize>) -> // The layout of an array is row-major linear in memory. let mut acc_size = type_size(edit, elem, alignments); for bound in bounds { - acc_size = edit.add_dynamic_constant(DynamicConstant::Mul(acc_size, bound)); + acc_size = edit.add_dynamic_constant(DynamicConstant::mul(acc_size, bound)); } acc_size } @@ -1157,7 +1157,7 @@ fn object_allocation( *total = align(&mut edit, *total, alignments[typing[id.idx()].idx()]); offsets.insert(id, *total); let type_size = type_size(&mut edit, typing[id.idx()], alignments); - *total = edit.add_dynamic_constant(DynamicConstant::Add(*total, type_size)); + *total = edit.add_dynamic_constant(DynamicConstant::add(*total, type_size)); } } Node::Call { @@ -1199,7 +1199,7 @@ fn object_allocation( &mut edit, ); } - *total = edit.add_dynamic_constant(DynamicConstant::Add( + *total = edit.add_dynamic_constant(DynamicConstant::add( *total, callee_backing_size, )); diff --git a/hercules_opt/src/lift_dc_math.rs b/hercules_opt/src/lift_dc_math.rs index afdb2120..8256c889 100644 --- a/hercules_opt/src/lift_dc_math.rs +++ b/hercules_opt/src/lift_dc_math.rs @@ -41,11 +41,11 @@ pub fn lift_dc_math(editor: &mut FunctionEditor) { continue; }; match op { - BinaryOperator::Add => DynamicConstant::Add(left, right), - BinaryOperator::Sub => DynamicConstant::Sub(left, right), - BinaryOperator::Mul => DynamicConstant::Mul(left, right), - BinaryOperator::Div => DynamicConstant::Div(left, right), - BinaryOperator::Rem => DynamicConstant::Rem(left, right), + BinaryOperator::Add => DynamicConstant::add(left, right), + BinaryOperator::Sub => DynamicConstant::sub(left, right), + BinaryOperator::Mul => DynamicConstant::mul(left, right), + BinaryOperator::Div => DynamicConstant::div(left, right), + BinaryOperator::Rem => DynamicConstant::rem(left, right), _ => { continue; } @@ -64,8 +64,8 @@ pub fn lift_dc_math(editor: &mut FunctionEditor) { continue; }; match intrinsic { - Intrinsic::Min => DynamicConstant::Min(left, right), - Intrinsic::Max => DynamicConstant::Max(left, right), + Intrinsic::Min => DynamicConstant::min(left, right), + Intrinsic::Max => DynamicConstant::max(left, right), _ => { continue; } diff --git a/hercules_opt/src/utils.rs b/hercules_opt/src/utils.rs index aa0d53fe..191c0502 100644 --- a/hercules_opt/src/utils.rs +++ b/hercules_opt/src/utils.rs @@ -87,14 +87,9 @@ pub(crate) fn substitute_dynamic_constants( match dc_clone { DynamicConstant::Constant(_) | DynamicConstant::Parameter(_) => dc_c, // This is a certified Rust moment. - DynamicConstant::Add(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); - if new_left != left || new_right != right { - edit.add_dynamic_constant(DynamicConstant::Add(new_left, new_right)) - } else { - dc_c - } + DynamicConstant::Add(xs) => { + let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); + edit.add_dynamic_constant(DynamicConstant::Add(new_xs)) } DynamicConstant::Sub(left, right) => { let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); @@ -105,14 +100,9 @@ pub(crate) fn substitute_dynamic_constants( dc_c } } - DynamicConstant::Mul(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); - if new_left != left || new_right != right { - edit.add_dynamic_constant(DynamicConstant::Mul(new_left, new_right)) - } else { - dc_c - } + DynamicConstant::Mul(xs) => { + let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); + edit.add_dynamic_constant(DynamicConstant::Mul(new_xs)) } DynamicConstant::Div(left, right) => { let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); @@ -132,23 +122,13 @@ pub(crate) fn substitute_dynamic_constants( dc_c } } - DynamicConstant::Min(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); - if new_left != left || new_right != right { - edit.add_dynamic_constant(DynamicConstant::Min(new_left, new_right)) - } else { - dc_c - } + DynamicConstant::Min(xs) => { + let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); + edit.add_dynamic_constant(DynamicConstant::Min(new_xs)) } - DynamicConstant::Max(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); - if new_left != left || new_right != right { - edit.add_dynamic_constant(DynamicConstant::Max(new_left, new_right)) - } else { - dc_c - } + DynamicConstant::Max(xs) => { + let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); + edit.add_dynamic_constant(DynamicConstant::Max(new_xs)) } } } -- GitLab From c7b53e45c7a6a8202154bfc73453cc9a497f2e72 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 14:03:24 -0600 Subject: [PATCH 11/16] Fix dynamic constant substitution --- hercules_opt/src/gcm.rs | 29 ++--- hercules_opt/src/inline.rs | 37 +------ hercules_opt/src/interprocedural_sroa.rs | 55 +++------- hercules_opt/src/utils.rs | 130 ++++++++++++----------- juno_samples/concat/src/main.rs | 16 +++ 5 files changed, 112 insertions(+), 155 deletions(-) diff --git a/hercules_opt/src/gcm.rs b/hercules_opt/src/gcm.rs index f80973ee..a22805b0 100644 --- a/hercules_opt/src/gcm.rs +++ b/hercules_opt/src/gcm.rs @@ -1166,7 +1166,10 @@ fn object_allocation( ref dynamic_constants, args: _, } => { - let dynamic_constants = dynamic_constants.clone(); + let dynamic_constants = dynamic_constants.to_vec(); + let dc_args = (0..dynamic_constants.len()).map(|i| edit.add_dynamic_constant(DynamicConstant::Parameter(i))); + let substs = dc_args.zip(dynamic_constants.into_iter()).collect::<HashMap<_, _>>(); + for device in BACKED_DEVICES { if let Some(mut callee_backing_size) = backing_allocations[&callee] .get(&device) @@ -1180,25 +1183,11 @@ fn object_allocation( offsets.insert(id, *total); // Substitute the dynamic constant parameters in the // callee's backing size. - let first_dc = edit.num_dynamic_constants() + 10000; - for (p_idx, dc_n) in zip(0..dynamic_constants.len(), first_dc..) { - let dc_a = - edit.add_dynamic_constant(DynamicConstant::Parameter(p_idx)); - callee_backing_size = substitute_dynamic_constants( - dc_a, - DynamicConstantID::new(dc_n), - callee_backing_size, - &mut edit, - ); - } - for (dc_n, dc_b) in zip(first_dc.., dynamic_constants.iter()) { - callee_backing_size = substitute_dynamic_constants( - DynamicConstantID::new(dc_n), - *dc_b, - callee_backing_size, - &mut edit, - ); - } + callee_backing_size = substitute_dynamic_constants( + &substs, + callee_backing_size, + &mut edit, + ); *total = edit.add_dynamic_constant(DynamicConstant::add( *total, callee_backing_size, diff --git a/hercules_opt/src/inline.rs b/hercules_opt/src/inline.rs index 1d2bac97..f63fa44c 100644 --- a/hercules_opt/src/inline.rs +++ b/hercules_opt/src/inline.rs @@ -119,7 +119,8 @@ fn inline_func( // Assemble all the info we'll need to do the edit. let dcs_a = &dc_param_idx_to_dc_id[..dynamic_constants.len()]; - let dcs_b = dynamic_constants.clone(); + let dcs_b = dynamic_constants.to_vec(); + let substs = dcs_a.iter().map(|i| *i).zip(dcs_b.into_iter()).collect::<HashMap<_, _>>(); let args = args.clone(); let old_num_nodes = editor.func().nodes.len(); let old_id_to_new_id = |old_id: NodeID| NodeID::new(old_id.idx() + old_num_nodes); @@ -163,39 +164,7 @@ fn inline_func( || node.is_dynamic_constant() || node.is_call() { - // We have to perform the subsitution in two steps. First, - // we map every dynamic constant A to a non-sense dynamic - // constant ID. Second, we map each non-sense dynamic - // constant ID to the appropriate dynamic constant B. Why - // not just do this in one step from A to B? We update - // dynamic constants one at a time, so imagine the following - // A -> B mappings: - // ID 0 -> ID 1 - // ID 1 -> ID 0 - // First, we apply the first mapping. This changes all - // references to dynamic constant 0 to dynamic constant 1. - // Then, we apply the second mapping. This updates all - // already present references to dynamic constant 1, as well - // as the new references we just made in the first step. We - // actually want to institute all the updates - // *simultaneously*, hence the two step maneuver. - let first_dc = edit.num_dynamic_constants() + 10000; - for (dc_a, dc_n) in zip(dcs_a, first_dc..) { - substitute_dynamic_constants_in_node( - *dc_a, - DynamicConstantID::new(dc_n), - &mut node, - &mut edit, - ); - } - for (dc_n, dc_b) in zip(first_dc.., dcs_b.iter()) { - substitute_dynamic_constants_in_node( - DynamicConstantID::new(dc_n), - *dc_b, - &mut node, - &mut edit, - ); - } + substitute_dynamic_constants_in_node(&substs, &mut node, &mut edit); } let mut uses = get_uses_mut(&mut node); for u in uses.as_mut() { diff --git a/hercules_opt/src/interprocedural_sroa.rs b/hercules_opt/src/interprocedural_sroa.rs index f597cd80..1797427e 100644 --- a/hercules_opt/src/interprocedural_sroa.rs +++ b/hercules_opt/src/interprocedural_sroa.rs @@ -313,31 +313,20 @@ fn compress_return_products(editors: &mut Vec<FunctionEditor>, all_callsites_edi // If this becomes a common pattern, it would be worth creating // a better abstraction around bulk replacement. - let new_dcs = (*dynamic_constants).clone(); + let new_dcs = (*dynamic_constants).to_vec(); + let old_dcs = dc_param_idx_to_dc_id[..new_dcs.len()].to_vec(); + assert_eq!(old_dcs.len(), new_dcs.len()); + let substs = old_dcs.into_iter().zip(new_dcs.into_iter()).collect::<HashMap<_, _>>(); let edit_successful = editor.edit(|mut edit| { - let old_dcs = dc_param_idx_to_dc_id[..new_dcs.len()].to_vec().clone(); let mut substituted = old_return_type_ids[function_id.idx()]; - assert_eq!(old_dcs.len(), new_dcs.len()); - let first_dc = edit.num_dynamic_constants() + 10000; - for (dc_a, dc_n) in zip(old_dcs, first_dc..) { - substituted = substitute_dynamic_constants_in_type( - dc_a, - DynamicConstantID::new(dc_n), - substituted, + let substituted = + substitute_dynamic_constants_in_type( + &substs, + old_return_type_ids[function_id.idx()], &mut edit, ); - } - - for (dc_n, dc_b) in zip(first_dc.., new_dcs.iter()) { - substituted = substitute_dynamic_constants_in_type( - DynamicConstantID::new(dc_n), - *dc_b, - substituted, - &mut edit, - ); - } let (expanded_product, readers) = uncompress_product(&mut edit, &call_node_id, &substituted); @@ -419,34 +408,24 @@ fn remove_return_singletons(editors: &mut Vec<FunctionEditor>, all_callsites_edi for call_node_id in call_node_ids { let (_, function, dc_args, _) = editor.func().nodes[call_node_id.idx()].try_call().unwrap(); - let dc_args = dc_args.clone(); + + let dc_args = dc_args.to_vec(); if singleton_removed[function.idx()] { let edit_successful = editor.edit(|mut edit| { - let mut substituted = old_return_type_ids[function.idx()]; - let first_dc = edit.num_dynamic_constants() + 10000; - let dc_params: Vec<_> = (0..dc_args.len()) + let dc_params = (0..dc_args.len()) .map(|param_idx| { edit.add_dynamic_constant(DynamicConstant::Parameter(param_idx)) }) - .collect(); - for (dc_a, dc_n) in zip(dc_params, first_dc..) { - substituted = substitute_dynamic_constants_in_type( - dc_a, - DynamicConstantID::new(dc_n), - substituted, - &mut edit, - ); - } + .collect::<Vec<_>>(); + let substs = dc_params.into_iter().zip(dc_args.into_iter()).collect::<HashMap<_, _>>(); - for (dc_n, dc_b) in zip(first_dc.., dc_args.iter()) { - substituted = substitute_dynamic_constants_in_type( - DynamicConstantID::new(dc_n), - *dc_b, - substituted, + let substituted = + substitute_dynamic_constants_in_type( + &substs, + old_return_type_ids[function.idx()], &mut edit, ); - } let empty_constant_id = edit.add_zero_constant(substituted); let empty_node_id = edit.add_node(Node::Constant { id: empty_constant_id, diff --git a/hercules_opt/src/utils.rs b/hercules_opt/src/utils.rs index 191c0502..08dbd131 100644 --- a/hercules_opt/src/utils.rs +++ b/hercules_opt/src/utils.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::iter::zip; use hercules_ir::def_use::*; @@ -6,12 +7,11 @@ use hercules_ir::ir::*; use crate::*; /* - * Substitute all uses of a dynamic constant A with dynamic constant B in a - * type. Return the substituted version of the type, once memozied. + * Substitute all uses of dynamic constants in a type that are keys in the substs map with the + * dynamic constant value for that key. Return the substituted version of the type, once memoized. */ pub(crate) fn substitute_dynamic_constants_in_type( - dc_a: DynamicConstantID, - dc_b: DynamicConstantID, + substs: &HashMap<DynamicConstantID, DynamicConstantID>, ty: TypeID, edit: &mut FunctionEdit, ) -> TypeID { @@ -21,7 +21,7 @@ pub(crate) fn substitute_dynamic_constants_in_type( Type::Product(ref fields) => { let new_fields = fields .into_iter() - .map(|field_id| substitute_dynamic_constants_in_type(dc_a, dc_b, *field_id, edit)) + .map(|field_id| substitute_dynamic_constants_in_type(substs, *field_id, edit)) .collect(); if new_fields != *fields { edit.add_type(Type::Product(new_fields)) @@ -33,7 +33,7 @@ pub(crate) fn substitute_dynamic_constants_in_type( let new_variants = variants .into_iter() .map(|variant_id| { - substitute_dynamic_constants_in_type(dc_a, dc_b, *variant_id, edit) + substitute_dynamic_constants_in_type(substs, *variant_id, edit) }) .collect(); if new_variants != *variants { @@ -43,10 +43,10 @@ pub(crate) fn substitute_dynamic_constants_in_type( } } Type::Array(elem_ty, ref dims) => { - let new_elem_ty = substitute_dynamic_constants_in_type(dc_a, dc_b, elem_ty, edit); + let new_elem_ty = substitute_dynamic_constants_in_type(substs, elem_ty, edit); let new_dims = dims .into_iter() - .map(|dim_id| substitute_dynamic_constants(dc_a, dc_b, *dim_id, edit)) + .map(|dim_id| substitute_dynamic_constants(substs, *dim_id, edit)) .collect(); if new_elem_ty != elem_ty || new_dims != *dims { edit.add_type(Type::Array(new_elem_ty, new_dims)) @@ -59,87 +59,93 @@ pub(crate) fn substitute_dynamic_constants_in_type( } /* - * Substitute all uses of a dynamic constant A with dynamic constant B in a - * dynamic constant C. Return the substituted version of C, once memoized. Takes - * a mutable edit instead of an editor since this may create new dynamic - * constants, which can only be done inside an edit. + * Substitute all uses of dynamic constants in a dynamic constant dc that are keys in the + * substs map and replace them with their appropriate replacement values. Return the substituted + * version of dc, once memoized. Takes a mutable edit instead of an editor since this may create + * new dynamic constants, which can only be done inside an edit. */ pub(crate) fn substitute_dynamic_constants( - dc_a: DynamicConstantID, - dc_b: DynamicConstantID, - dc_c: DynamicConstantID, + substs: &HashMap<DynamicConstantID, DynamicConstantID>, + dc: DynamicConstantID, edit: &mut FunctionEdit, ) -> DynamicConstantID { - // If C is just A, then just replace all of C with B. - if dc_a == dc_c { - return dc_b; + // If this dynamic constant should be substituted, just return the substitution + if let Some(subst) = substs.get(&dc) { + return *subst; } - // Since we substitute non-sense dynamic constant IDs earlier, we explicitly - // check that the provided ID to replace inside of is valid. Otherwise, - // ignore. - if dc_c.idx() >= edit.num_dynamic_constants() { - return dc_c; - } - - // If C is not just A, look inside of it to possibly substitute a child DC. - let dc_clone = edit.get_dynamic_constant(dc_c).clone(); + // Look inside the dynamic constant to perform substitution in its children + let dc_clone = edit.get_dynamic_constant(dc).clone(); match dc_clone { - DynamicConstant::Constant(_) | DynamicConstant::Parameter(_) => dc_c, - // This is a certified Rust moment. + DynamicConstant::Constant(_) | DynamicConstant::Parameter(_) => dc, DynamicConstant::Add(xs) => { - let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); - edit.add_dynamic_constant(DynamicConstant::Add(new_xs)) + let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + if new_xs != xs { + edit.add_dynamic_constant(DynamicConstant::Add(new_xs)) + } else { + dc + } } DynamicConstant::Sub(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); + let new_left = substitute_dynamic_constants(substs, left, edit); + let new_right = substitute_dynamic_constants(substs, right, edit); if new_left != left || new_right != right { edit.add_dynamic_constant(DynamicConstant::Sub(new_left, new_right)) } else { - dc_c + dc } } DynamicConstant::Mul(xs) => { - let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); - edit.add_dynamic_constant(DynamicConstant::Mul(new_xs)) + let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + if new_xs != xs { + edit.add_dynamic_constant(DynamicConstant::Mul(new_xs)) + } else { + dc + } } DynamicConstant::Div(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); + let new_left = substitute_dynamic_constants(substs, left, edit); + let new_right = substitute_dynamic_constants(substs, right, edit); if new_left != left || new_right != right { edit.add_dynamic_constant(DynamicConstant::Div(new_left, new_right)) } else { - dc_c + dc } } DynamicConstant::Rem(left, right) => { - let new_left = substitute_dynamic_constants(dc_a, dc_b, left, edit); - let new_right = substitute_dynamic_constants(dc_a, dc_b, right, edit); + let new_left = substitute_dynamic_constants(substs, left, edit); + let new_right = substitute_dynamic_constants(substs, right, edit); if new_left != left || new_right != right { edit.add_dynamic_constant(DynamicConstant::Rem(new_left, new_right)) } else { - dc_c + dc } } DynamicConstant::Min(xs) => { - let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); - edit.add_dynamic_constant(DynamicConstant::Min(new_xs)) + let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + if new_xs != xs { + edit.add_dynamic_constant(DynamicConstant::Min(new_xs)) + } else { + dc + } } DynamicConstant::Max(xs) => { - let new_xs = xs.into_iter().map(|x| substitute_dynamic_constants(dc_a, dc_b, x, edit)).collect::<Vec<_>>(); - edit.add_dynamic_constant(DynamicConstant::Max(new_xs)) + let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + if new_xs != xs { + edit.add_dynamic_constant(DynamicConstant::Max(new_xs)) + } else { + dc + } } } } /* - * Substitute all uses of a dynamic constant A with dynamic constant B in a - * constant. Return the substituted version of the constant, once memozied. + * Substitute all uses of the dynamic constants specified by the subst map in a constant. Return + * the substituted version of the constant, once memozied. */ pub(crate) fn substitute_dynamic_constants_in_constant( - dc_a: DynamicConstantID, - dc_b: DynamicConstantID, + substs: &HashMap<DynamicConstantID, DynamicConstantID>, cons: ConstantID, edit: &mut FunctionEdit, ) -> ConstantID { @@ -147,11 +153,11 @@ pub(crate) fn substitute_dynamic_constants_in_constant( let cons_clone = edit.get_constant(cons).clone(); match cons_clone { Constant::Product(ty, fields) => { - let new_ty = substitute_dynamic_constants_in_type(dc_a, dc_b, ty, edit); + let new_ty = substitute_dynamic_constants_in_type(substs, ty, edit); let new_fields = fields .iter() .map(|field_id| { - substitute_dynamic_constants_in_constant(dc_a, dc_b, *field_id, edit) + substitute_dynamic_constants_in_constant(substs, *field_id, edit) }) .collect(); if new_ty != ty || new_fields != fields { @@ -161,8 +167,8 @@ pub(crate) fn substitute_dynamic_constants_in_constant( } } Constant::Summation(ty, idx, variant) => { - let new_ty = substitute_dynamic_constants_in_type(dc_a, dc_b, ty, edit); - let new_variant = substitute_dynamic_constants_in_constant(dc_a, dc_b, variant, edit); + let new_ty = substitute_dynamic_constants_in_type(substs, ty, edit); + let new_variant = substitute_dynamic_constants_in_constant(substs, variant, edit); if new_ty != ty || new_variant != variant { edit.add_constant(Constant::Summation(new_ty, idx, new_variant)) } else { @@ -170,7 +176,7 @@ pub(crate) fn substitute_dynamic_constants_in_constant( } } Constant::Array(ty) => { - let new_ty = substitute_dynamic_constants_in_type(dc_a, dc_b, ty, edit); + let new_ty = substitute_dynamic_constants_in_type(substs, ty, edit); if new_ty != ty { edit.add_constant(Constant::Array(new_ty)) } else { @@ -182,12 +188,10 @@ pub(crate) fn substitute_dynamic_constants_in_constant( } /* - * Substitute all uses of a dynamic constant A with dynamic constant B in a - * node. + * Substitute all uses of the dynamic constants specified by the subst map in a node. */ pub(crate) fn substitute_dynamic_constants_in_node( - dc_a: DynamicConstantID, - dc_b: DynamicConstantID, + substs: &HashMap<DynamicConstantID, DynamicConstantID>, node: &mut Node, edit: &mut FunctionEdit, ) { @@ -197,14 +201,14 @@ pub(crate) fn substitute_dynamic_constants_in_node( factors, } => { for factor in factors.into_iter() { - *factor = substitute_dynamic_constants(dc_a, dc_b, *factor, edit); + *factor = substitute_dynamic_constants(substs, *factor, edit); } } Node::Constant { id } => { - *id = substitute_dynamic_constants_in_constant(dc_a, dc_b, *id, edit); + *id = substitute_dynamic_constants_in_constant(substs, *id, edit); } Node::DynamicConstant { id } => { - *id = substitute_dynamic_constants(dc_a, dc_b, *id, edit); + *id = substitute_dynamic_constants(substs, *id, edit); } Node::Call { control: _, @@ -213,7 +217,7 @@ pub(crate) fn substitute_dynamic_constants_in_node( args: _, } => { for dc_arg in dynamic_constants.into_iter() { - *dc_arg = substitute_dynamic_constants(dc_a, dc_b, *dc_arg, edit); + *dc_arg = substitute_dynamic_constants(substs, *dc_arg, edit); } } _ => {} diff --git a/juno_samples/concat/src/main.rs b/juno_samples/concat/src/main.rs index db3f37fd..8bcd7ba5 100644 --- a/juno_samples/concat/src/main.rs +++ b/juno_samples/concat/src/main.rs @@ -1,6 +1,7 @@ #![feature(concat_idents)] use hercules_rt::runner; +use hercules_rt::HerculesCPURef; juno_build::juno!("concat"); @@ -10,6 +11,21 @@ fn main() { let output = r.run(7).await; println!("{}", output); assert_eq!(output, 42); + + const N: usize = 3; + let arr : Box<[i32]> = (2..=4).collect(); + let arr = HerculesCPURef::from_slice(&arr); + + let mut r = runner!(concat_switch); + let output = r.run(N as u64, 50, arr.clone()).await; + let result = output.as_slice::<i32>(); + println!("{:?}", result); + assert_eq!(result, [0, 1, 2, 3, 4]); + + let output = r.run(N as u64, 30, arr).await; + let result = output.as_slice::<i32>(); + println!("{:?}", result); + assert_eq!(result, [2, 3, 4, 0, 1]); }); } -- GitLab From 7c5a8b722b948d8f67f2e5a7c4f1364695baefd6 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 14:06:17 -0600 Subject: [PATCH 12/16] Clean-up formatting --- hercules_cg/src/cpu.rs | 48 +++++++--- hercules_ir/src/dc_normalization.rs | 112 +++++++++-------------- hercules_ir/src/ir.rs | 21 +++-- hercules_ir/src/typecheck.rs | 59 +++++++----- hercules_opt/src/gcm.rs | 7 +- hercules_opt/src/inline.rs | 6 +- hercules_opt/src/interprocedural_sroa.rs | 34 ++++--- hercules_opt/src/utils.rs | 28 ++++-- 8 files changed, 176 insertions(+), 139 deletions(-) diff --git a/hercules_cg/src/cpu.rs b/hercules_cg/src/cpu.rs index 94b8cc5d..23c53d66 100644 --- a/hercules_cg/src/cpu.rs +++ b/hercules_cg/src/cpu.rs @@ -583,9 +583,15 @@ impl<'a> CPUContext<'a> { let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); let mut idx = 0; while let Some(x) = xs.next() { - let new_val = format!("%dc{}{}", dc.idx(), - if xs.peek().is_some() { format!(".{}", idx) } - else { "".to_string() }); + let new_val = format!( + "%dc{}{}", + dc.idx(), + if xs.peek().is_some() { + format!(".{}", idx) + } else { + "".to_string() + } + ); write!( body, " {} = add i64{},%dc{}\n", @@ -609,9 +615,15 @@ impl<'a> CPUContext<'a> { let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); let mut idx = 0; while let Some(x) = xs.next() { - let new_val = format!("%dc{}{}", dc.idx(), - if xs.peek().is_some() { format!(".{}", idx) } - else { "".to_string() }); + let new_val = format!( + "%dc{}{}", + dc.idx(), + if xs.peek().is_some() { + format!(".{}", idx) + } else { + "".to_string() + } + ); write!( body, " {} = mul i64{},%dc{}\n", @@ -642,9 +654,15 @@ impl<'a> CPUContext<'a> { let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); let mut idx = 0; while let Some(x) = xs.next() { - let new_val = format!("%dc{}{}", dc.idx(), - if xs.peek().is_some() { format!(".{}", idx) } - else { "".to_string() }); + let new_val = format!( + "%dc{}{}", + dc.idx(), + if xs.peek().is_some() { + format!(".{}", idx) + } else { + "".to_string() + } + ); write!( body, " {} = call @llvm.umin.i64(i64{},i64%dc{}))\n", @@ -661,9 +679,15 @@ impl<'a> CPUContext<'a> { let mut cur_value = format!("%dc{}", xs.next().unwrap().idx()); let mut idx = 0; while let Some(x) = xs.next() { - let new_val = format!("%dc{}{}", dc.idx(), - if xs.peek().is_some() { format!(".{}", idx) } - else { "".to_string() }); + let new_val = format!( + "%dc{}{}", + dc.idx(), + if xs.peek().is_some() { + format!(".{}", idx) + } else { + "".to_string() + } + ); write!( body, " {} = call @llvm.umax.i64(i64{},i64%dc{}))\n", diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index ca76f3f7..e4f68f3d 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -1,33 +1,23 @@ use crate::*; -use std::cmp::{min, max}; +use std::cmp::{max, min}; use std::ops::Deref; use either::Either; -pub trait DynamicConstantView -{ +pub trait DynamicConstantView { fn get_dynconst(&self, id: DynamicConstantID) -> impl Deref<Target = DynamicConstant> + '_; fn add_dynconst(&mut self, dc: DynamicConstant) -> DynamicConstantID; - fn dc_const( - &mut self, - val: usize, - ) -> DynamicConstantID { + fn dc_const(&mut self, val: usize) -> DynamicConstantID { self.add_dynconst(DynamicConstant::Constant(val)) } - fn dc_param( - &mut self, - index: usize, - ) -> DynamicConstantID { + fn dc_param(&mut self, index: usize) -> DynamicConstantID { self.add_dynconst(DynamicConstant::Parameter(index)) } - fn dc_add( - &mut self, - dcs: Vec<DynamicConstantID>, - ) -> DynamicConstantID { + fn dc_add(&mut self, dcs: Vec<DynamicConstantID>) -> DynamicConstantID { let mut constant_val = 0; let mut fields = vec![]; @@ -53,10 +43,7 @@ pub trait DynamicConstantView } } - fn dc_mul( - &mut self, - dcs: Vec<DynamicConstantID>, - ) -> DynamicConstantID { + fn dc_mul(&mut self, dcs: Vec<DynamicConstantID>) -> DynamicConstantID { let mut constant_val = 1; let mut fields = vec![]; @@ -84,11 +71,8 @@ pub trait DynamicConstantView } } - fn dc_min( - &mut self, - dcs: Vec<DynamicConstantID>, - ) -> DynamicConstantID { - let mut constant_val : Option<usize> = None; + fn dc_min(&mut self, dcs: Vec<DynamicConstantID>) -> DynamicConstantID { + let mut constant_val: Option<usize> = None; let mut fields = vec![]; for dc in dcs { @@ -109,7 +93,10 @@ pub trait DynamicConstantView fields.push(self.add_dynconst(DynamicConstant::Constant(const_val))); } - assert!(fields.len() > 0, "Min of 0 dynamic constant expressions is undefined"); + assert!( + fields.len() > 0, + "Min of 0 dynamic constant expressions is undefined" + ); if fields.len() <= 1 { fields[0] @@ -119,11 +106,8 @@ pub trait DynamicConstantView } } - fn dc_max( - &mut self, - dcs: Vec<DynamicConstantID>, - ) -> DynamicConstantID { - let mut constant_val : Option<usize> = None; + fn dc_max(&mut self, dcs: Vec<DynamicConstantID>) -> DynamicConstantID { + let mut constant_val: Option<usize> = None; let mut fields = vec![]; for dc in dcs { @@ -144,7 +128,10 @@ pub trait DynamicConstantView fields.push(self.add_dynconst(DynamicConstant::Constant(const_val))); } - assert!(fields.len() > 0, "Max of 0 dynamic constant expressions is undefined"); + assert!( + fields.len() > 0, + "Max of 0 dynamic constant expressions is undefined" + ); if fields.len() <= 1 { fields[0] @@ -154,18 +141,14 @@ pub trait DynamicConstantView } } - fn dc_sub( - &mut self, - x: DynamicConstantID, - y: DynamicConstantID, - ) -> DynamicConstantID { - let dc = - match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - Either::Left(DynamicConstant::Constant(x - y)), - (_, DynamicConstant::Constant(0)) => Either::Right(x), - _ => Either::Left(DynamicConstant::Sub(x, y)), - }; + fn dc_sub(&mut self, x: DynamicConstantID, y: DynamicConstantID) -> DynamicConstantID { + let dc = match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => { + Either::Left(DynamicConstant::Constant(x - y)) + } + (_, DynamicConstant::Constant(0)) => Either::Right(x), + _ => Either::Left(DynamicConstant::Sub(x, y)), + }; match dc { Either::Left(dc) => self.add_dynconst(dc), @@ -173,18 +156,14 @@ pub trait DynamicConstantView } } - fn dc_div( - &mut self, - x: DynamicConstantID, - y: DynamicConstantID, - ) -> DynamicConstantID { - let dc = - match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - Either::Left(DynamicConstant::Constant(x / y)), - (_, DynamicConstant::Constant(1)) => Either::Right(x), - _ => Either::Left(DynamicConstant::Div(x, y)), - }; + fn dc_div(&mut self, x: DynamicConstantID, y: DynamicConstantID) -> DynamicConstantID { + let dc = match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => { + Either::Left(DynamicConstant::Constant(x / y)) + } + (_, DynamicConstant::Constant(1)) => Either::Right(x), + _ => Either::Left(DynamicConstant::Div(x, y)), + }; match dc { Either::Left(dc) => self.add_dynconst(dc), @@ -192,17 +171,13 @@ pub trait DynamicConstantView } } - fn dc_rem( - &mut self, - x: DynamicConstantID, - y: DynamicConstantID, - ) -> DynamicConstantID { - let dc = - match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { - (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => - Either::Left(DynamicConstant::Constant(x % y)), - _ => Either::Left(DynamicConstant::Rem(x, y)), - }; + fn dc_rem(&mut self, x: DynamicConstantID, y: DynamicConstantID) -> DynamicConstantID { + let dc = match (self.get_dynconst(x).deref(), self.get_dynconst(y).deref()) { + (DynamicConstant::Constant(x), DynamicConstant::Constant(y)) => { + Either::Left(DynamicConstant::Constant(x % y)) + } + _ => Either::Left(DynamicConstant::Rem(x, y)), + }; match dc { Either::Left(dc) => self.add_dynconst(dc), @@ -210,10 +185,7 @@ pub trait DynamicConstantView } } - fn dc_normalize( - &mut self, - dc: DynamicConstant, - ) -> DynamicConstantID { + fn dc_normalize(&mut self, dc: DynamicConstant) -> DynamicConstantID { match dc { DynamicConstant::Add(xs) => self.dc_add(xs), DynamicConstant::Mul(xs) => self.dc_mul(xs), diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs index ba8d607e..af9f0275 100644 --- a/hercules_ir/src/ir.rs +++ b/hercules_ir/src/ir.rs @@ -657,7 +657,10 @@ pub fn dynamic_constants_bottom_up( // We have to yield the children of this node before // this node itself. We keep track of which nodes have // yielded using visited. - if args.iter().any(|i| i.idx() >= visited.len() || invalid[i.idx()]) { + if args + .iter() + .any(|i| i.idx() >= visited.len() || invalid[i.idx()]) + { // This is an invalid dynamic constant and should be skipped invalid.set(id.idx(), true); continue; @@ -1023,27 +1026,27 @@ impl DynamicConstant { pub fn add(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Add(vec![x, y]) } - + pub fn sub(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Sub(x, y) } - + pub fn mul(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Mul(vec![x, y]) } - + pub fn div(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Div(x, y) } - + pub fn rem(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Rem(x, y) } - + pub fn min(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Min(vec![x, y]) } - + pub fn max(x: DynamicConstantID, y: DynamicConstantID) -> Self { Self::Max(vec![x, y]) } @@ -1087,7 +1090,9 @@ pub fn evaluate_dynamic_constant( ) -> Option<usize> { // Because of normalization, if a dynamic constant can be expressed as a constant it must be a // constant - let DynamicConstant::Constant(cons) = dcs[cons.idx()] else { return None; }; + let DynamicConstant::Constant(cons) = dcs[cons.idx()] else { + return None; + }; Some(cons) } diff --git a/hercules_ir/src/typecheck.rs b/hercules_ir/src/typecheck.rs index fdbbd46e..f7ea397e 100644 --- a/hercules_ir/src/typecheck.rs +++ b/hercules_ir/src/typecheck.rs @@ -190,9 +190,9 @@ fn typeflow( DynamicConstant::Add(xs) | DynamicConstant::Mul(xs) | DynamicConstant::Min(xs) - | DynamicConstant::Max(xs) => { - xs.iter().all(|dc| check_dynamic_constants(*dc, dynamic_constants, num_parameters)) - } + | DynamicConstant::Max(xs) => xs + .iter() + .all(|dc| check_dynamic_constants(*dc, dynamic_constants, num_parameters)), DynamicConstant::Sub(x, y) | DynamicConstant::Div(x, y) | DynamicConstant::Rem(x, y) => { @@ -736,7 +736,13 @@ fn typeflow( } // Construct the substitution object - let mut subst = DCSubst::new(types, reverse_type_map, dynamic_constants, reverse_dynamic_constant_map, dc_args); + let mut subst = DCSubst::new( + types, + reverse_type_map, + dynamic_constants, + reverse_dynamic_constant_map, + dc_args, + ); // Check argument types. for (input, param_ty) in zip(inputs.iter().skip(1), callee.param_types.iter()) { @@ -1115,10 +1121,7 @@ impl<'a> DCSubst<'a> { } } - fn intern_type( - &mut self, - ty: Type, - ) -> TypeID { + fn intern_type(&mut self, ty: Type) -> TypeID { if let Some(id) = self.reverse_type_map.get(&ty) { *id } else { @@ -1129,10 +1132,7 @@ impl<'a> DCSubst<'a> { } } - fn type_subst( - &mut self, - typ: TypeID, - ) -> TypeID { + fn type_subst(&mut self, typ: TypeID) -> TypeID { match &self.types[typ.idx()] { Type::Control | Type::Boolean @@ -1156,22 +1156,27 @@ impl<'a> DCSubst<'a> { } Type::Array(elem, dims) => { let elem = *elem; - let new_dims = dims.clone().iter().map(|d| self.dyn_const_subst(*d)).collect(); + let new_dims = dims + .clone() + .iter() + .map(|d| self.dyn_const_subst(*d)) + .collect(); let new_elem = self.type_subst(elem); self.intern_type(Type::Array(new_elem, new_dims)) } } } - fn dyn_const_subst( - &mut self, - dyn_const: DynamicConstantID, - ) -> DynamicConstantID { + fn dyn_const_subst(&mut self, dyn_const: DynamicConstantID) -> DynamicConstantID { match &self.dynamic_constants[dyn_const.idx()] { DynamicConstant::Constant(_) => dyn_const, DynamicConstant::Parameter(i) => self.dc_args[*i], DynamicConstant::Add(xs) => { - let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + let sxs = xs + .clone() + .into_iter() + .map(|dc| self.dyn_const_subst(dc)) + .collect(); self.dc_add(sxs) } DynamicConstant::Sub(l, r) => { @@ -1182,7 +1187,11 @@ impl<'a> DCSubst<'a> { self.dc_sub(sx, sy) } DynamicConstant::Mul(xs) => { - let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + let sxs = xs + .clone() + .into_iter() + .map(|dc| self.dyn_const_subst(dc)) + .collect(); self.dc_mul(sxs) } DynamicConstant::Div(l, r) => { @@ -1200,11 +1209,19 @@ impl<'a> DCSubst<'a> { self.dc_rem(sx, sy) } DynamicConstant::Min(xs) => { - let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + let sxs = xs + .clone() + .into_iter() + .map(|dc| self.dyn_const_subst(dc)) + .collect(); self.dc_min(sxs) } DynamicConstant::Max(xs) => { - let sxs = xs.clone().into_iter().map(|dc| self.dyn_const_subst(dc)).collect(); + let sxs = xs + .clone() + .into_iter() + .map(|dc| self.dyn_const_subst(dc)) + .collect(); self.dc_max(sxs) } } diff --git a/hercules_opt/src/gcm.rs b/hercules_opt/src/gcm.rs index a22805b0..fe7c64a8 100644 --- a/hercules_opt/src/gcm.rs +++ b/hercules_opt/src/gcm.rs @@ -1167,8 +1167,11 @@ fn object_allocation( args: _, } => { let dynamic_constants = dynamic_constants.to_vec(); - let dc_args = (0..dynamic_constants.len()).map(|i| edit.add_dynamic_constant(DynamicConstant::Parameter(i))); - let substs = dc_args.zip(dynamic_constants.into_iter()).collect::<HashMap<_, _>>(); + let dc_args = (0..dynamic_constants.len()) + .map(|i| edit.add_dynamic_constant(DynamicConstant::Parameter(i))); + let substs = dc_args + .zip(dynamic_constants.into_iter()) + .collect::<HashMap<_, _>>(); for device in BACKED_DEVICES { if let Some(mut callee_backing_size) = backing_allocations[&callee] diff --git a/hercules_opt/src/inline.rs b/hercules_opt/src/inline.rs index f63fa44c..848d957f 100644 --- a/hercules_opt/src/inline.rs +++ b/hercules_opt/src/inline.rs @@ -120,7 +120,11 @@ fn inline_func( // Assemble all the info we'll need to do the edit. let dcs_a = &dc_param_idx_to_dc_id[..dynamic_constants.len()]; let dcs_b = dynamic_constants.to_vec(); - let substs = dcs_a.iter().map(|i| *i).zip(dcs_b.into_iter()).collect::<HashMap<_, _>>(); + let substs = dcs_a + .iter() + .map(|i| *i) + .zip(dcs_b.into_iter()) + .collect::<HashMap<_, _>>(); let args = args.clone(); let old_num_nodes = editor.func().nodes.len(); let old_id_to_new_id = |old_id: NodeID| NodeID::new(old_id.idx() + old_num_nodes); diff --git a/hercules_opt/src/interprocedural_sroa.rs b/hercules_opt/src/interprocedural_sroa.rs index 1797427e..f22c1fe8 100644 --- a/hercules_opt/src/interprocedural_sroa.rs +++ b/hercules_opt/src/interprocedural_sroa.rs @@ -316,17 +316,19 @@ fn compress_return_products(editors: &mut Vec<FunctionEditor>, all_callsites_edi let new_dcs = (*dynamic_constants).to_vec(); let old_dcs = dc_param_idx_to_dc_id[..new_dcs.len()].to_vec(); assert_eq!(old_dcs.len(), new_dcs.len()); - let substs = old_dcs.into_iter().zip(new_dcs.into_iter()).collect::<HashMap<_, _>>(); + let substs = old_dcs + .into_iter() + .zip(new_dcs.into_iter()) + .collect::<HashMap<_, _>>(); let edit_successful = editor.edit(|mut edit| { let mut substituted = old_return_type_ids[function_id.idx()]; - let substituted = - substitute_dynamic_constants_in_type( - &substs, - old_return_type_ids[function_id.idx()], - &mut edit, - ); + let substituted = substitute_dynamic_constants_in_type( + &substs, + old_return_type_ids[function_id.idx()], + &mut edit, + ); let (expanded_product, readers) = uncompress_product(&mut edit, &call_node_id, &substituted); @@ -418,14 +420,16 @@ fn remove_return_singletons(editors: &mut Vec<FunctionEditor>, all_callsites_edi edit.add_dynamic_constant(DynamicConstant::Parameter(param_idx)) }) .collect::<Vec<_>>(); - let substs = dc_params.into_iter().zip(dc_args.into_iter()).collect::<HashMap<_, _>>(); - - let substituted = - substitute_dynamic_constants_in_type( - &substs, - old_return_type_ids[function.idx()], - &mut edit, - ); + let substs = dc_params + .into_iter() + .zip(dc_args.into_iter()) + .collect::<HashMap<_, _>>(); + + let substituted = substitute_dynamic_constants_in_type( + &substs, + old_return_type_ids[function.idx()], + &mut edit, + ); let empty_constant_id = edit.add_zero_constant(substituted); let empty_node_id = edit.add_node(Node::Constant { id: empty_constant_id, diff --git a/hercules_opt/src/utils.rs b/hercules_opt/src/utils.rs index 08dbd131..cc6bf444 100644 --- a/hercules_opt/src/utils.rs +++ b/hercules_opt/src/utils.rs @@ -32,9 +32,7 @@ pub(crate) fn substitute_dynamic_constants_in_type( Type::Summation(ref variants) => { let new_variants = variants .into_iter() - .map(|variant_id| { - substitute_dynamic_constants_in_type(substs, *variant_id, edit) - }) + .map(|variant_id| substitute_dynamic_constants_in_type(substs, *variant_id, edit)) .collect(); if new_variants != *variants { edit.add_type(Type::Summation(new_variants)) @@ -79,7 +77,10 @@ pub(crate) fn substitute_dynamic_constants( match dc_clone { DynamicConstant::Constant(_) | DynamicConstant::Parameter(_) => dc, DynamicConstant::Add(xs) => { - let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + let new_xs = xs + .iter() + .map(|x| substitute_dynamic_constants(substs, *x, edit)) + .collect::<Vec<_>>(); if new_xs != xs { edit.add_dynamic_constant(DynamicConstant::Add(new_xs)) } else { @@ -96,7 +97,10 @@ pub(crate) fn substitute_dynamic_constants( } } DynamicConstant::Mul(xs) => { - let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + let new_xs = xs + .iter() + .map(|x| substitute_dynamic_constants(substs, *x, edit)) + .collect::<Vec<_>>(); if new_xs != xs { edit.add_dynamic_constant(DynamicConstant::Mul(new_xs)) } else { @@ -122,7 +126,10 @@ pub(crate) fn substitute_dynamic_constants( } } DynamicConstant::Min(xs) => { - let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + let new_xs = xs + .iter() + .map(|x| substitute_dynamic_constants(substs, *x, edit)) + .collect::<Vec<_>>(); if new_xs != xs { edit.add_dynamic_constant(DynamicConstant::Min(new_xs)) } else { @@ -130,7 +137,10 @@ pub(crate) fn substitute_dynamic_constants( } } DynamicConstant::Max(xs) => { - let new_xs = xs.iter().map(|x| substitute_dynamic_constants(substs, *x, edit)).collect::<Vec<_>>(); + let new_xs = xs + .iter() + .map(|x| substitute_dynamic_constants(substs, *x, edit)) + .collect::<Vec<_>>(); if new_xs != xs { edit.add_dynamic_constant(DynamicConstant::Max(new_xs)) } else { @@ -156,9 +166,7 @@ pub(crate) fn substitute_dynamic_constants_in_constant( let new_ty = substitute_dynamic_constants_in_type(substs, ty, edit); let new_fields = fields .iter() - .map(|field_id| { - substitute_dynamic_constants_in_constant(substs, *field_id, edit) - }) + .map(|field_id| substitute_dynamic_constants_in_constant(substs, *field_id, edit)) .collect(); if new_ty != ty || new_fields != fields { edit.add_constant(Constant::Product(new_ty, new_fields)) -- GitLab From 15a581b1cd205eca71679b007fe11e089327b3f8 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 14:13:11 -0600 Subject: [PATCH 13/16] Process min/max fields as a set --- hercules_ir/src/dc_normalization.rs | 33 +++++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index e4f68f3d..06c45fea 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -1,6 +1,7 @@ use crate::*; use std::cmp::{max, min}; +use std::collections::BTreeSet; use std::ops::Deref; use either::Either; @@ -73,7 +74,9 @@ pub trait DynamicConstantView { fn dc_min(&mut self, dcs: Vec<DynamicConstantID>) -> DynamicConstantID { let mut constant_val: Option<usize> = None; - let mut fields = vec![]; + // For min and max we track the fields via a set during normalization as this removes + // duplicates (and we use a BTreeSet as it can produce its elements in sorted order) + let mut fields = BTreeSet::new(); for dc in dcs { match self.get_dynconst(dc).deref() { @@ -84,13 +87,15 @@ pub trait DynamicConstantView { constant_val = Some(*x); } } - DynamicConstant::Min(xs) => fields.extend_from_slice(xs), - _ => fields.push(dc), + DynamicConstant::Min(xs) => fields.extend(xs), + _ => { + fields.insert(dc); + } } } if let Some(const_val) = constant_val { - fields.push(self.add_dynconst(DynamicConstant::Constant(const_val))); + fields.insert(self.add_dynconst(DynamicConstant::Constant(const_val))); } assert!( @@ -99,16 +104,15 @@ pub trait DynamicConstantView { ); if fields.len() <= 1 { - fields[0] + *fields.first().unwrap() } else { - fields.sort(); - self.add_dynconst(DynamicConstant::Min(fields)) + self.add_dynconst(DynamicConstant::Min(fields.into_iter().collect())) } } fn dc_max(&mut self, dcs: Vec<DynamicConstantID>) -> DynamicConstantID { let mut constant_val: Option<usize> = None; - let mut fields = vec![]; + let mut fields = BTreeSet::new(); for dc in dcs { match self.get_dynconst(dc).deref() { @@ -119,13 +123,15 @@ pub trait DynamicConstantView { constant_val = Some(*x); } } - DynamicConstant::Max(xs) => fields.extend_from_slice(xs), - _ => fields.push(dc), + DynamicConstant::Max(xs) => fields.extend(xs), + _ => { + fields.insert(dc); + } } } if let Some(const_val) = constant_val { - fields.push(self.add_dynconst(DynamicConstant::Constant(const_val))); + fields.insert(self.add_dynconst(DynamicConstant::Constant(const_val))); } assert!( @@ -134,10 +140,9 @@ pub trait DynamicConstantView { ); if fields.len() <= 1 { - fields[0] + *fields.first().unwrap() } else { - fields.sort(); - self.add_dynconst(DynamicConstant::Max(fields)) + self.add_dynconst(DynamicConstant::Max(fields.into_iter().collect())) } } -- GitLab From 3af4013e02d472b692212f64bd229f432199d27c Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 20:27:17 -0600 Subject: [PATCH 14/16] Fixes to dynamic constant usage --- hercules_opt/src/fork_guard_elim.rs | 29 +++++++------ hercules_opt/src/forkify.rs | 3 +- .../hercules_interpreter/src/interpreter.rs | 42 ++++++++++++------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/hercules_opt/src/fork_guard_elim.rs b/hercules_opt/src/fork_guard_elim.rs index 1abb8967..052fd0e4 100644 --- a/hercules_opt/src/fork_guard_elim.rs +++ b/hercules_opt/src/fork_guard_elim.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap, HashSet}; +use std::ops::Deref; use hercules_ir::*; @@ -70,22 +71,24 @@ fn guarded_fork( }; let mut factors = factors.iter().enumerate().map(|(idx, dc)| { - let DynamicConstant::Max(l, r) = *editor.get_dynamic_constant(*dc) else { + let factor = editor.get_dynamic_constant(*dc); + let DynamicConstant::Max(xs) = factor.deref() else { return Factor::Normal(*dc); }; - // There really needs to be a better way to work w/ associativity. - let binding = [(l, r), (r, l)]; - let id = binding.iter().find_map(|(a, b)| { - let DynamicConstant::Constant(1) = *editor.get_dynamic_constant(*a) else { - return None; - }; - Some(b) - }); - - match id { - Some(v) => Factor::Max(idx, *v), - None => Factor::Normal(*dc), + // Filter out any terms which are just 1s + let non_ones = xs.iter().filter(|i| { + if let DynamicConstant::Constant(1) = editor.get_dynamic_constant(**i).deref() { + false + } else { + true + } + }).collect::<Vec<_>>(); + // If we're left with just one term x, we had max { 1, x } + if non_ones.len() == 1 { + Factor::Max(idx, *non_ones[0]) + } else { + Factor::Normal(*dc) } }); diff --git a/hercules_opt/src/forkify.rs b/hercules_opt/src/forkify.rs index ce9ac141..ec4e9fbc 100644 --- a/hercules_opt/src/forkify.rs +++ b/hercules_opt/src/forkify.rs @@ -265,9 +265,8 @@ pub fn forkify_loop( let bound_dc_id = { let mut max_id = DynamicConstantID::new(0); editor.edit(|mut edit| { - // FIXME: Maybe add_dynamic_constant should intern? let one_id = edit.add_dynamic_constant(DynamicConstant::Constant(1)); - max_id = edit.add_dynamic_constant(DynamicConstant::Max(one_id, bound_dc_id)); + max_id = edit.add_dynamic_constant(DynamicConstant::max(one_id, bound_dc_id)); Ok(edit) }); max_id diff --git a/hercules_test/hercules_interpreter/src/interpreter.rs b/hercules_test/hercules_interpreter/src/interpreter.rs index a78330e4..871e304a 100644 --- a/hercules_test/hercules_interpreter/src/interpreter.rs +++ b/hercules_test/hercules_interpreter/src/interpreter.rs @@ -69,17 +69,17 @@ pub fn dyn_const_value( match dc { DynamicConstant::Constant(v) => *v, DynamicConstant::Parameter(v) => dyn_const_params[*v], - DynamicConstant::Add(a, b) => { - dyn_const_value(a, dyn_const_values, dyn_const_params) - + dyn_const_value(b, dyn_const_values, dyn_const_params) + DynamicConstant::Add(xs) => { + xs.iter().map(|x| dyn_const_value(x, dyn_const_values, dyn_const_params)) + .fold(0, |s, v| s + v) } DynamicConstant::Sub(a, b) => { dyn_const_value(a, dyn_const_values, dyn_const_params) - dyn_const_value(b, dyn_const_values, dyn_const_params) } - DynamicConstant::Mul(a, b) => { - dyn_const_value(a, dyn_const_values, dyn_const_params) - * dyn_const_value(b, dyn_const_values, dyn_const_params) + DynamicConstant::Mul(xs) => { + xs.iter().map(|x| dyn_const_value(x, dyn_const_values, dyn_const_params)) + .fold(1, |p, v| p * v) } DynamicConstant::Div(a, b) => { dyn_const_value(a, dyn_const_values, dyn_const_params) @@ -89,14 +89,28 @@ pub fn dyn_const_value( dyn_const_value(a, dyn_const_values, dyn_const_params) % dyn_const_value(b, dyn_const_values, dyn_const_params) } - DynamicConstant::Max(a, b) => max( - dyn_const_value(a, dyn_const_values, dyn_const_params), - dyn_const_value(b, dyn_const_values, dyn_const_params), - ), - DynamicConstant::Min(a, b) => min( - dyn_const_value(a, dyn_const_values, dyn_const_params), - dyn_const_value(b, dyn_const_values, dyn_const_params), - ), + DynamicConstant::Max(xs) => { + xs.iter().map(|x| dyn_const_value(x, dyn_const_values, dyn_const_params)) + .fold(None, |m, v| { + if let Some(m) = m { + Some(max(m, v)) + } else { + Some(v) + } + }) + .unwrap() + } + DynamicConstant::Min(xs) => { + xs.iter().map(|x| dyn_const_value(x, dyn_const_values, dyn_const_params)) + .fold(None, |m, v| { + if let Some(m) = m { + Some(min(m, v)) + } else { + Some(v) + } + }) + .unwrap() + } } } -- GitLab From 73bcb5399c81aff683ecf136e3633c0e08386207 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 20:38:10 -0600 Subject: [PATCH 15/16] Clean-up Juno's dynamic constant generation --- juno_frontend/src/dynconst.rs | 113 +++++++++++++++------------------- 1 file changed, 51 insertions(+), 62 deletions(-) diff --git a/juno_frontend/src/dynconst.rs b/juno_frontend/src/dynconst.rs index defab822..511dfa34 100644 --- a/juno_frontend/src/dynconst.rs +++ b/juno_frontend/src/dynconst.rs @@ -291,16 +291,16 @@ impl DynConst { .map(|(d, c)| self.build_mono(builder, d, c)) .partition(|(_, neg)| !*neg); - let pos_sum = pos - .into_iter() - .map(|(t, _)| t) - .reduce(|x, y| builder.create_dynamic_constant_add(x, y)) - .unwrap_or_else(|| builder.create_dynamic_constant_constant(0)); + let pos_sum = + builder.create_dynamic_constant_add_many(pos.into_iter().map(|(t, _)| t).collect()); - let neg_sum = neg - .into_iter() - .map(|(t, _)| t) - .reduce(|x, y| builder.create_dynamic_constant_add(x, y)); + let neg_sum = if neg.is_empty() { + None + } else { + Some( + builder.create_dynamic_constant_add_many(neg.into_iter().map(|(t, _)| t).collect()), + ) + }; match neg_sum { None => pos_sum, @@ -317,72 +317,61 @@ impl DynConst { term: &Vec<i64>, coeff: &Ratio<i64>, ) -> (DynamicConstantID, bool) { - let term_id = term + let (pos, neg): (Vec<_>, Vec<_>) = term .iter() .enumerate() .filter(|(_, p)| **p != 0) .map(|(v, p)| self.build_power(builder, v, *p)) - .collect::<Vec<_>>() - .into_iter() - .reduce(|x, y| builder.create_dynamic_constant_mul(x, y)); - - match term_id { - None => { - // This means all powers of the term are 0, so we just - // output the coefficient - if !coeff.is_integer() { - panic!("Dynamic constant is a non-integer constant") - } else { - let val: i64 = coeff.to_integer(); - ( - builder.create_dynamic_constant_constant(val.abs() as usize), - val < 0, - ) - } - } - Some(term) => { - if coeff.is_one() { - (term, false) - } else { - let numer: i64 = coeff.numer().abs(); - let denom: i64 = *coeff.denom(); // > 0 - - let with_numer = if numer == 1 { - term - } else { - let numer_id = builder.create_dynamic_constant_constant(numer as usize); - builder.create_dynamic_constant_mul(numer_id, term) - }; - let with_denom = if denom == 1 { - with_numer - } else { - let denom_id = builder.create_dynamic_constant_constant(denom as usize); - builder.create_dynamic_constant_div(with_numer, denom_id) - }; - - (with_denom, numer < 0) - } + .partition(|(_, neg)| !*neg); + let mut pos: Vec<_> = pos.into_iter().map(|(t, _)| t).collect(); + let mut neg: Vec<_> = neg.into_iter().map(|(t, _)| t).collect(); + + let numerator = { + let numer: i64 = coeff.numer().abs(); + let numer_dc = builder.create_dynamic_constant_constant(numer as usize); + pos.push(numer_dc); + builder.create_dynamic_constant_mul_many(pos) + }; + + let denominator = { + let denom: i64 = *coeff.denom(); + assert!(denom > 0); + + if neg.is_empty() && denom == 1 { + None + } else { + let denom_dc = builder.create_dynamic_constant_constant(denom as usize); + neg.push(denom_dc); + Some(builder.create_dynamic_constant_mul_many(neg)) } + }; + + if let Some(denominator) = denominator { + ( + builder.create_dynamic_constant_div(numerator, denominator), + *coeff.numer() < 0, + ) + } else { + (numerator, *coeff.numer() < 0) } } // Build's a dynamic constant that is a certain power of a specific variable - fn build_power(&self, builder: &mut Builder, v: usize, power: i64) -> DynamicConstantID { + // Returns the dynamic constant id of variable raised to the absolute value of the power and a + // boolean indicating whether the power is actually negative + fn build_power( + &self, + builder: &mut Builder, + v: usize, + power: i64, + ) -> (DynamicConstantID, bool) { assert!(power != 0); let power_pos = power.abs() as usize; let var_id = builder.create_dynamic_constant_parameter(v); - let power_id = iter::repeat(var_id) - .take(power_pos) - .map(|_| var_id) - .reduce(|x, y| builder.create_dynamic_constant_mul(x, y)) - .expect("Power is non-zero"); + let power_id = + builder.create_dynamic_constant_mul_many((0..power_pos).map(|_| var_id).collect()); - if power > 0 { - power_id - } else { - let one_id = builder.create_dynamic_constant_constant(1); - builder.create_dynamic_constant_div(one_id, power_id) - } + (power_id, power < 0) } } -- GitLab From 6d7f0a764816e01656f24f0efd42da06ecd15788 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Thu, 30 Jan 2025 21:49:01 -0600 Subject: [PATCH 16/16] Normalize min of zero --- hercules_ir/src/dc_normalization.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/hercules_ir/src/dc_normalization.rs b/hercules_ir/src/dc_normalization.rs index 06c45fea..e9f8f23a 100644 --- a/hercules_ir/src/dc_normalization.rs +++ b/hercules_ir/src/dc_normalization.rs @@ -95,15 +95,16 @@ pub trait DynamicConstantView { } if let Some(const_val) = constant_val { - fields.insert(self.add_dynconst(DynamicConstant::Constant(const_val))); + // Since dynamic constants are non-negative, ignore the constant if it is 0 + if const_val != 0 { + fields.insert(self.add_dynconst(DynamicConstant::Constant(const_val))); + } } - assert!( - fields.len() > 0, - "Min of 0 dynamic constant expressions is undefined" - ); - - if fields.len() <= 1 { + if fields.len() == 0 { + // The minimum of 0 dynamic constants is 0 since dynamic constants are non-negative + self.add_dynconst(DynamicConstant::Constant(0)) + } else if fields.len() <= 1 { *fields.first().unwrap() } else { self.add_dynconst(DynamicConstant::Min(fields.into_iter().collect())) -- GitLab