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

Update things related to registers #161

Merged
merged 2 commits into from
May 30, 2018
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
104 changes: 28 additions & 76 deletions src/analysis/functions/infer_regusage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use analysis::inst_combine;
use frontend::radeco_containers::{RadecoFunction, RadecoModule};
use middle::dce;
use middle::ir;
use middle::regfile::{RegisterId, RegisterUsage, SubRegisterFile};
use middle::regfile::*;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should explicitly spell out what you want to import. This helps:

  1. Makes it clear what's being imported
  2. In case more things are added to regfile, they won't "automatically" be imported here.

use middle::ssa::cfg_traits::*;
use middle::ssa::ssa_traits::*;
use middle::ssa::ssastorage::SSAStorage;
use middle::ssa::utils;

use petgraph::visit::{DfsPostOrder, Walker};

Expand Down Expand Up @@ -119,11 +120,8 @@ impl Inferer {
let (call_tgt_addr, call_reg_map) = direct_call_info(fn_map[&fn_addr].ssa(), call_node)?;

// remove unread args
for (reg_idx, &op_node) in (0..).zip(&call_reg_map) {
if fn_map[&call_tgt_addr]
.regusage
.is_ignored(RegisterId::from_usize(reg_idx))
{
for (regid, &op_node) in &call_reg_map {
if fn_map[&call_tgt_addr].regusage.is_ignored(regid) {
fn_map
.get_mut(&fn_addr)
.unwrap()
Expand All @@ -133,25 +131,13 @@ impl Inferer {
}

// bridge preserved registers
// TODO: use utils::call_rets
for use_node in fn_map[&fn_addr].ssa().uses_of(call_node) {
let reg_idx = match fn_map[&fn_addr]
.ssa()
.sparse_operands_of(use_node)
.as_slice()
{
&[(reg_idx, _)] => reg_idx,
_ => panic!("invalid use of call as operand"),
};
if fn_map[&call_tgt_addr]
.regusage
.is_preserved(RegisterId::from_u8(reg_idx))
{
for (regid, (use_node, _)) in utils::call_rets(call_node, fn_map[&fn_addr].ssa()) {
if fn_map[&call_tgt_addr].regusage.is_preserved(regid) {
fn_map
.get_mut(&fn_addr)
.unwrap()
.ssa_mut()
.replace_value(use_node, call_reg_map[reg_idx as usize]);
.replace_value(use_node, call_reg_map[regid]);
}
}

Expand All @@ -165,75 +151,41 @@ impl Inferer {
let exit_regstate_node = ssa.registers_in(ssa.exit_node()?)?;
// some registers may not be present in the entry node;
// this means that the function neither reads nor preserves that register
let entry_regstate: Vec<Option<_>> = register_state_info(ssa, entry_regstate_node);
// every register must be present in the exit node though
let exit_regstate: Vec<_> = register_state_info(ssa, exit_regstate_node)
.into_iter()
.collect::<Option<_>>()?;
let entry_regstate = utils::register_state_info(entry_regstate_node, ssa);
let exit_regstate = utils::register_state_info(exit_regstate_node, ssa);

let mut ret = reginfo.new_register_usage();
ret.set_all_ignored();

// ignore registers not in entry regstate
let regstate_iter = (0..)
.zip(exit_regstate)
.zip(entry_regstate)
.filter_map(|((i, x), on)| on.map(|n| (i, n, x)));
for regid in ssa.regfile.iter_register_ids() {
// ignore registers not in entry regstate
if let Some(&(reg_val_entry, _)) = entry_regstate.get(regid) {
// bail if a register isn't present in exit regstate
let &(reg_val_exit, _) = exit_regstate.get(regid)?;

for (i, reg_val_entry, reg_val_exit) in regstate_iter {
if reg_val_exit == reg_val_entry {
ret.set_preserved(RegisterId::from_u8(i));
}
if reg_val_exit == reg_val_entry {
ret.set_preserved(regid);
}

// find all uses, ignoring entry/exit register state
let mut uses_iter = ssa.uses_of(reg_val_entry)
.into_iter()
.filter(|&n| n != entry_regstate_node && n != exit_regstate_node);
if uses_iter.next().is_some() {
ret.set_read(RegisterId::from_u8(i));
// find all uses, ignoring entry/exit register state
let mut uses_iter = ssa
.uses_of(reg_val_entry)
.into_iter()
.filter(|&n| n != entry_regstate_node && n != exit_regstate_node);
if uses_iter.next().is_some() {
ret.set_read(regid);
}
}
}

Some(ret)
}
}

/// Extracts the value of all registers at a `RegisterState` SSA node.
/// The length of the returned `Vec` is exactly `ssa.regnames.len() + 1`.
fn register_state_info(
ssa: &SSAStorage,
regstate_node: <SSAStorage as SSA>::ValueRef,
) -> Vec<Option<<SSAStorage as SSA>::ValueRef>> {
let mut reg_opt_map: Vec<Option<_>> = vec![None; ssa.regnames.len() + 1];
for (op_idx, op_node) in ssa.sparse_operands_of(regstate_node) {
if let Some(p) = reg_opt_map.get_mut(op_idx as usize) {
*p = Some(op_node);
}
}
reg_opt_map
}

/// Extracts the call target address and the value of all registers
/// The length of the returned `Vec` is exactly `ssa.regnames.len() + 1`.
/// Returns `None` if the call is indirect or if not all registers have a value.
// TODO: use new utils::call_info
fn direct_call_info(
ssa: &SSAStorage,
call_node: <SSAStorage as SSA>::ValueRef,
) -> Option<(u64, Vec<<SSAStorage as SSA>::ValueRef>)> {
let mut tgt_opt: Option<u64> = None;
let mut reg_opt_map: Vec<Option<_>> = vec![None; ssa.regnames.len() + 1];

for (op_idx, op_node) in ssa.sparse_operands_of(call_node) {
if op_idx == 0 {
tgt_opt = tgt_opt.or_else(|| ssa.constant(op_node));
} else {
if let Some(p) = reg_opt_map.get_mut((op_idx - 1) as usize) {
*p = Some(op_node);
}
}
}

let reg_map_opt: Option<Vec<_>> = reg_opt_map.into_iter().collect();
Some((tgt_opt?, reg_map_opt?))
) -> Option<(u64, RegisterMap<<SSAStorage as SSA>::ValueRef>)> {
let callinfo = utils::call_info(call_node, ssa)?;
Some((ssa.constant(callinfo.target)?, callinfo.register_args))
}
44 changes: 22 additions & 22 deletions src/frontend/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,28 +398,28 @@ impl<'a, T: 'a + Source> From<&'a mut T> for RadecoModule<'a, DefaultFnTy> {
let handle = thread::Builder::new().name(f.name.as_ref().unwrap().to_owned()).spawn(move || {
let mut rfn = ssa_single_fn(&f, &reg_info, instructions, offset);
// Attach additional information as necessay from `FunctionInfo`.
{
// Add all defined registers to bindings.
let regs = {
let ssa = rfn.ssa_mut();
let start = ssa.entry_node().expect("Incomplete CFG graph");
let rs = ssa.registers_in(start).expect("No registers state node found");
ssa.operands_of(rs)
};
for (i, reg) in regs.iter().enumerate() {
let mut bind = Binding::default();
bind.mark_register(rfn.ssa
.regnames
.get(i)
.cloned()
.unwrap_or_else(String::new));
bind.add_refs(vec![*reg]);
// Set the initial bind as register name, which may be
// changed after analyzed.
bind.set_name(rfn.ssa.regnames.get(i).cloned().unwrap_or_else(String::new));
rfn.bindings.insert(bind);
}
}
// {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this code if we don't plan on using it in the immediate future. We can always bring it back if need be as its in git.

// // Add all defined registers to bindings.
// let regs = {
// let ssa = rfn.ssa_mut();
// let start = ssa.entry_node().expect("Incomplete CFG graph");
// let rs = ssa.registers_in(start).expect("No registers state node found");
// ssa.operands_of(rs)
// };
// for (i, reg) in regs.iter().enumerate() {
// let mut bind = Binding::default();
// bind.mark_register(rfn.ssa
// .regnames
// .get(i)
// .cloned()
// .unwrap_or_else(String::new));
// bind.add_refs(vec![*reg]);
// // Set the initial bind as register name, which may be
// // changed after analyzed.
// bind.set_name(rfn.ssa.regnames.get(i).cloned().unwrap_or_else(String::new));
// rfn.bindings.insert(bind);
// }
// }
rfn.offset = offset;
fix_call_info(&mut rfn);
load_datarefs(&mut rfn, f.datarefs);
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/radeco_containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ impl<'a> ModuleLoader<'a> {
})
.unwrap_or(&NodeIndex::end());
}
vb.ridx = sub_reg_f.register_id_by_alias(alias);
vb.ridx = sub_reg_f.register_id_by_alias(alias).map(|rid| rid.to_u8() as u64);
Some(vb)
} else {
None
Expand Down
28 changes: 11 additions & 17 deletions src/middle/ir_reader/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use middle::ssa::ssa_traits::{SSAMod, ValueInfo, SSA};
use middle::ssa::ssastorage::SSAStorage;

use std::collections::HashMap;
use std::fmt::Write;
use std::error;
use std::fmt;
use std::fmt::Write;

pub type Result<T> = ::std::result::Result<T, LoweringError>;

Expand Down Expand Up @@ -70,7 +70,6 @@ impl<'a> LowerSsa<'a> {
}

fn lower_function(mut self, sfn: sast::Function) -> Result<()> {

self.lower_entry_reg_state(sfn.entry_reg_state)?;

let mut first = true;
Expand All @@ -89,9 +88,6 @@ impl<'a> LowerSsa<'a> {

self.lower_final_reg_state(sfn.final_reg_state)?;

let regs = self.ssa.regfile.whole_names.clone();
self.ssa.map_registers(regs);

Ok(())
}

Expand Down Expand Up @@ -223,7 +219,9 @@ impl<'a> LowerSsa<'a> {
if let Some(addr) = opt_addr {
write!(comment, "@{}", addr).unwrap();
}
let val = self.ssa.insert_comment(lower_valueinfo(sret.value.1), comment)?;
let val = self
.ssa
.insert_comment(lower_valueinfo(sret.value.1), comment)?;
self.ssa.op_use(val, regid.to_u8(), res);
self.values.insert(sret.value.0, val);
}
Expand Down Expand Up @@ -259,18 +257,14 @@ impl<'a> LowerSsa<'a> {

fn index_of_reg(&self, sreg: &sast::PhysReg) -> Result<RegisterId> {
if sreg.0 == "mem" {
Ok(RegisterId::from_usize(
self.ssa.regfile.whole_names.len(),
))
Ok(self.ssa.regfile.mem_id())
} else {
if let Some(x) = self.ssa.regfile.register_id_by_name(&sreg.0) {
Ok(RegisterId::from_usize(x as usize))
} else {
Err(LoweringError::InvalidAst(format!(
"no physical register: {}",
sreg.0
)))
}
self.ssa
.regfile
.register_id_by_name(&sreg.0)
.ok_or_else(|| {
LoweringError::InvalidAst(format!("no physical register: {}", sreg.0))
})
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/middle/ir_reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ define-fun main(unknown) -> unknown {
let frs_node = ssa.registers_in(exit).unwrap();
let frs = utils::register_state_info(frs_node, &ssa);

let rax_i = ssa.regfile.register_id_by_name("rax").unwrap() as usize;
let rax_i = ssa.regfile.register_id_by_name("rax").unwrap().to_usize();
let v1 = frs[RegisterId::from_usize(rax_i)].0;
assert!(exprs.contains(&v1));
assert_eq!(
Expand All @@ -171,7 +171,7 @@ define-fun main(unknown) -> unknown {
"rdi".to_owned()
)
);
let rdi_i = ssa.regfile.register_id_by_name("rdi").unwrap() as usize;
let rdi_i = ssa.regfile.register_id_by_name("rdi").unwrap().to_usize();
assert_eq!(cmt_rdi, ers[RegisterId::from_usize(rdi_i)].0);
}

Expand Down
3 changes: 0 additions & 3 deletions src/middle/phiplacement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,9 +1005,6 @@ impl<'a, T> PhiPlacer<'a, T>
}
}

// TODO: remove
self.ssa.map_registers(self.regfile.whole_names.clone());

// Associate basic block with correct block sizes.
for opn in ops.windows(2) {
let op1 = &opn[0];
Expand Down
Loading