Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove ValueData::Alias #49

Merged
merged 4 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions crates/codegen/src/optim/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ impl GvnSolver {
value: Value,
edge: Edge,
) -> Value {
let mut rep_value = self.leader(func.dfg.resolve_alias(value));
let mut rep_value = self.leader(value);

if let Some(inferred_value) = self.infer_value_impl(edge, rep_value) {
rep_value = inferred_value;
Expand Down Expand Up @@ -1334,6 +1334,8 @@ struct RedundantCodeRemover<'a> {

/// Record resolved value phis.
resolved_value_phis: FxHashMap<ValuePhi, Value>,

renames: FxHashMap<Value, Value>,
}

impl<'a> RedundantCodeRemover<'a> {
Expand All @@ -1342,9 +1344,25 @@ impl<'a> RedundantCodeRemover<'a> {
solver,
avail_set: SecondaryMap::default(),
resolved_value_phis: FxHashMap::default(),
renames: FxHashMap::default(),
}
}

fn change_to_alias(&mut self, func: &mut Function, value: Value, target: Value) {
func.dfg.change_to_alias(value, target);
self.renames.insert(value, target);
}

fn resolve_alias(&self, mut value: Value) -> Value {
for _ in 0..1 + self.renames.len() {
match self.renames.get(&value) {
Some(v) => value = *v,
None => return value,
}
}
panic!("alias loop detected");
}

/// The entry function of redundant code removal.
///
/// This function
Expand Down Expand Up @@ -1421,7 +1439,7 @@ impl<'a> RedundantCodeRemover<'a> {

// Use representative value if the class is in avail set.
if let Some(value) = avails.get(&class) {
func.dfg.change_to_alias(insn_result, *value);
self.change_to_alias(func, insn_result, *value);
inserter.remove_insn(func);
continue;
}
Expand Down Expand Up @@ -1469,7 +1487,8 @@ impl<'a> RedundantCodeRemover<'a> {
ty,
block,
);
func.dfg.change_to_alias(insn_result, value);

self.change_to_alias(func, insn_result, value);
inserter.remove_insn(func);
continue;
}
Expand Down Expand Up @@ -1537,7 +1556,7 @@ impl<'a> RedundantCodeRemover<'a> {
for (value_phi, phi_block) in &phi_insn.args {
let resolved =
self.resolve_value_phi(func, inserter, value_phi, ty, *phi_block);
phi.append_phi_arg(resolved, *phi_block);
phi.append_phi_arg(self.resolve_alias(resolved), *phi_block);
}

// Insert new phi insn to top of the phi_insn block.
Expand Down
2 changes: 1 addition & 1 deletion crates/codegen/src/optim/licm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl LicmSolver {

/// Returns preheader of the loop.
/// 1. If there is natural preheader for the loop, then returns it without any modification of
/// function.
/// function.
/// 2. If no natural preheader for the loop, then create the preheader and modify function
/// layout, `cfg`, and `lpt`.
fn create_preheader(
Expand Down
2 changes: 0 additions & 2 deletions crates/codegen/src/optim/sccp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ impl SccpSolver {
for (i, from) in func.dfg.phi_blocks(insn).iter().enumerate() {
if self.is_reachable(func, *from, block) {
let phi_arg = func.dfg.insn_arg(insn, i);
let phi_arg = func.dfg.resolve_alias(phi_arg);

let v_cell = self.lattice[phi_arg];
eval_result = eval_result.join(v_cell);
}
Expand Down
10 changes: 5 additions & 5 deletions crates/codegen/src/optim/simplify_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use generated_code::{Context, SimplifyRawResult};

pub fn simplify_insn(dfg: &mut DataFlowGraph, insn: Insn) -> Option<SimplifyResult> {
if dfg.is_phi(insn) {
return simplify_phi(dfg, dfg.insn_data(insn));
return simplify_phi(dfg.insn_data(insn));
}

let mut ctx = SimplifyContext::new(dfg);
Expand All @@ -27,7 +27,7 @@ pub fn simplify_insn(dfg: &mut DataFlowGraph, insn: Insn) -> Option<SimplifyResu

pub fn simplify_insn_data(dfg: &mut DataFlowGraph, data: InsnData) -> Option<SimplifyResult> {
if matches!(data, InsnData::Phi { .. }) {
return simplify_phi(dfg, &data);
return simplify_phi(&data);
}

let mut ctx = SimplifyContext::new(dfg);
Expand All @@ -40,12 +40,12 @@ pub enum SimplifyResult {
Insn(InsnData),
}

fn simplify_phi(dfg: &DataFlowGraph, insn_data: &InsnData) -> Option<SimplifyResult> {
fn simplify_phi(insn_data: &InsnData) -> Option<SimplifyResult> {
match insn_data {
InsnData::Phi { values, .. } => {
let mut values = values.iter().copied();
let first_value = values.next().unwrap();
if values.all(|value| dfg.is_same_value(first_value, value)) {
if values.all(|value| value == first_value) {
Some(SimplifyResult::Value(first_value))
} else {
None
Expand Down Expand Up @@ -499,7 +499,7 @@ impl<'a> generated_code::Context for SimplifyContext<'a> {

fn is_eq(&mut self, arg0: ExprValue, arg1: ExprValue) -> Option<()> {
match (arg0.as_value(), arg1.as_value()) {
(Some(val1), Some(val2)) => self.dfg.is_same_value(val1, val2),
(Some(val1), Some(val2)) => val1 == val2,
_ => arg0 == arg1,
}
.then_some(())
Expand Down
8 changes: 4 additions & 4 deletions crates/filecheck/fixtures/adce/all_dests_remove.sntn
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ func public %all_dests_removed() -> i8 {
}

# check: block0:
# nextln: v1.i32 = add v0 v0;
# nextln: v1.i8 = add v0 v0;
# nextln: jump block3;
# nextln:
# nextln: block3:
# nextln: return v1;
func public %all_dests_removed2(v0.i32) -> i8 {
func public %all_dests_removed2(v0.i8) -> i8 {
block0:
v1.i32 = add v0 v0;
br_table v0 (v1 block1) (2.i32 block2);
v1.i8 = add v0 v0;
br_table v0 (v1 block1) (2.i8 block2);

block1:
v3.i8 = add v0 -10.i8;
Expand Down
2 changes: 1 addition & 1 deletion crates/filecheck/fixtures/adce/whole_loop_removed.sntn
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ target = "evm-ethereum-london"
# nextln: return 1.i8;
func public %whole_loop_removed() -> i8 {
block0:
v0.i1 = or 1.i8 0.i8;
v0.i8 = or 1.i8 0.i8;
v1.i8 = sext v0;
jump block2;

Expand Down
6 changes: 3 additions & 3 deletions crates/filecheck/fixtures/gvn/fold_predicted_value.sntn
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ target = "evm-ethereum-london"
# nextln: return 1.i1;
# check: block2:
# nextln: return 0.i1;
func public %fold_with_predicted_value(v0.i1) -> i8 {
func public %fold_with_predicted_value(v0.i1) -> i1 {
block0:
br v0 block1 block2;

block1:
v1.i8 = or v0 v0;
v1.i1 = or v0 v0;
return v1;

block2:
v2.i8 = or v0 v0;
v2.i1 = or v0 v0;
return v2;
}
4 changes: 2 additions & 2 deletions crates/filecheck/fixtures/insn_simplify/neg.sntn
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func public %neg0(v0.i8) -> i8 {
# check: v2.i16 = add v0 1.i16;
func public %neg1(v0.i16) -> i16 {
block0:
v1.i8 = not v0;
v2.i8 = neg v1;
v1.i16 = not v0;
v2.i16 = neg v1;
return v2;
}
12 changes: 6 additions & 6 deletions crates/interpreter/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ mod test {
v0.i16 = add 3.i16 4.i16;
v1.i16 = sub v0 1.i16;
v2.i16 = udiv v1 2.i16;
v3.i8 = sdiv v2 65535.i16;
v3.i16 = sdiv v2 65535.i16;
return v3;
}
";
Expand Down Expand Up @@ -380,7 +380,7 @@ mod test {
block0:
v0.*i32 = alloca i32;
store @memory v0 1.i32;
v1.*i32 = load @memory v0;
v1.i32 = load @memory v0;
return v1;
}
";
Expand Down Expand Up @@ -559,10 +559,10 @@ mod test {
let input = "
target = \"evm-ethereum-london\"

func private %test() -> *i1 {
func private %test() -> **i32 {
block0:
v0.*[*i32; 3] = alloca [*i32; 3];
v1.*i32 = gep v0 2.i8;
v1.**i32 = gep v0 2.i8;
return v1;
}
";
Expand All @@ -581,10 +581,10 @@ mod test {

type %s1 = {i32, [i16; 3], [i8; 2]};

func private %test() -> *i1 {
func private %test() -> *i8 {
block0:
v0.*%s1 = alloca %s1;
v1.*i1 = gep v0 2.i8 1.i8;
v1.*i8 = gep v0 2.i8 1.i8;
return v1;
}
";
Expand Down
85 changes: 59 additions & 26 deletions crates/ir/src/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::collections::BTreeSet;

use cranelift_entity::{entity_impl, packed_option::PackedOption, PrimaryMap, SecondaryMap};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;

use crate::{global_variable::ConstantValue, module::ModuleCtx, GlobalVariable};

Expand Down Expand Up @@ -82,23 +83,15 @@ impl DataFlowGraph {
}

pub fn change_to_alias(&mut self, value: Value, alias: Value) {
self.values[value] = ValueData::Alias {
alias: self.resolve_alias(alias),
}
}

pub fn resolve_alias(&self, mut value: Value) -> Value {
for _ in 0..self.values.len() {
match self.values[value] {
ValueData::Insn { .. }
| ValueData::Arg { .. }
| ValueData::Immediate { .. }
| ValueData::Global { .. } => return value,
ValueData::Alias { alias } => value = alias,
let mut users = std::mem::take(&mut self.users[value]);
for insn in &users {
for arg in self.insns[*insn].args_mut() {
if *arg == value {
*arg = alias;
}
}
}

panic!("alias loop detected");
self.users[alias].append(&mut users);
}

pub fn make_result(&mut self, insn: Insn) -> Option<ValueData> {
Expand Down Expand Up @@ -159,21 +152,18 @@ impl DataFlowGraph {
}

pub fn value_insn(&self, value: Value) -> Option<Insn> {
let value = self.resolve_alias(value);
match self.value_data(value) {
ValueData::Insn { insn, .. } => Some(*insn),
_ => None,
}
}

pub fn value_ty(&self, value: Value) -> Type {
let value = self.resolve_alias(value);
match &self.values[value] {
ValueData::Insn { ty, .. }
| ValueData::Arg { ty, .. }
| ValueData::Immediate { ty, .. }
| ValueData::Global { ty, .. } => *ty,
ValueData::Alias { .. } => unreachable!(),
}
}

Expand All @@ -182,7 +172,6 @@ impl DataFlowGraph {
}

pub fn value_imm(&self, value: Value) -> Option<Immediate> {
let value = self.resolve_alias(value);
match self.value_data(value) {
ValueData::Immediate { imm, .. } => Some(*imm),
ValueData::Global { gv, .. } => self.ctx.with_gv_store(|s| {
Expand All @@ -199,7 +188,6 @@ impl DataFlowGraph {
}

pub fn value_gv(&self, value: Value) -> Option<GlobalVariable> {
let value = self.resolve_alias(value);
match self.value_data(value) {
ValueData::Global { gv, .. } => Some(*gv),
_ => None,
Expand Down Expand Up @@ -262,7 +250,57 @@ impl DataFlowGraph {
}

pub fn remove_branch_dest(&mut self, insn: Insn, dest: Block) {
self.insns[insn].remove_branch_dest(dest)
let this = &mut self.insns[insn];
match this {
InsnData::Jump { .. } => panic!("can't remove destination from `Jump` insn"),

InsnData::Branch { dests, args } => {
let remain = if dests[0] == dest {
dests[1]
} else if dests[1] == dest {
dests[0]
} else {
panic!("no dests found in the branch destination")
};
self.users[args[0]].remove(&insn);
*this = InsnData::jump(remain);
}

InsnData::BrTable {
default,
table,
args,
} => {
if Some(dest) == *default {
*default = None;
} else if let Some((lhs, rest)) = args.split_first() {
type V<T> = SmallVec<[T; 8]>;
let (keep, drop): (V<_>, V<_>) = table
.iter()
.copied()
.zip(rest.iter().copied())
.partition(|(b, _)| *b != dest);
let (b, mut a): (V<_>, V<_>) = keep.into_iter().unzip();
a.insert(0, *lhs);
*args = a;
*table = b;

for (_, val) in drop {
self.users[val].remove(&insn);
}
}

let branch_info = this.analyze_branch();
if branch_info.dests_num() == 1 {
for val in this.args() {
self.users[*val].remove(&insn);
}
*this = InsnData::jump(branch_info.iter_dests().next().unwrap());
}
}

_ => panic!("not a branch"),
}
}

pub fn rewrite_branch_dest(&mut self, insn: Insn, from: Block, to: Block) {
Expand All @@ -281,18 +319,13 @@ impl DataFlowGraph {
self.insns[insn].is_branch()
}

pub fn is_same_value(&self, v0: Value, v1: Value) -> bool {
self.resolve_alias(v0) == self.resolve_alias(v1)
}

/// Returns `true` if `value` is an immediate.
pub fn is_imm(&self, value: Value) -> bool {
self.value_imm(value).is_some()
}

/// Returns `true` if `value` is a function argument.
pub fn is_arg(&self, value: Value) -> bool {
let value = self.resolve_alias(value);
matches!(self.value_data(value), ValueData::Arg { .. })
}
}
Expand Down
Loading