Commit 21f48ca6 authored by qinsoon's avatar qinsoon

[wip] a single return sink

parent caf2aa5a
Pipeline #723 failed with stages
in 28 minutes and 20 seconds
......@@ -681,6 +681,13 @@ impl TreeNode {
})
}
/// creates a sharable Value TreeNode
pub fn new_value(v: P<Value>) -> P<TreeNode> {
P(TreeNode {
v: TreeNode_::Value(v)
})
}
/// extracts the MuID of an SSA TreeNode
/// if the node is not an SSA, returns None
pub fn extract_ssa_id(&self) -> Option<MuID> {
......
......@@ -92,8 +92,10 @@ impl Default for CompilerPolicy {
fn default() -> Self {
let mut passes : Vec<Box<CompilerPass>> = vec![];
passes.push(Box::new(passes::DotGen::new(".orig")));
passes.push(Box::new(passes::Inlining::new()));
// ir level passes
passes.push(Box::new(passes::RetSink::new()));
passes.push(Box::new(passes::Inlining::new()));
passes.push(Box::new(passes::DefUse::new()));
passes.push(Box::new(passes::TreeGen::new()));
passes.push(Box::new(passes::GenMovPhi::new()));
......
......@@ -22,6 +22,10 @@ use std::any::Any;
mod inlining;
pub use compiler::passes::inlining::Inlining;
/// A pass to check and rewrite RET instructions to ensure a single return sink for every function
mod ret_sink;
pub use compiler::passes::ret_sink::RetSink;
/// A Def-Use pass. Getting use info and count for SSA variables in the IR (we are not collecting
/// define info)
mod def_use;
......
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ast::ir::*;
use ast::inst::*;
use ast::ptr::*;
use vm::VM;
use compiler::CompilerPass;
use std::any::Any;
/// Mu IR the client gives us may contain several RET instructions. However,
/// internally we want a single exit point for a function. In this pass, we
/// create a return sink (a block), and rewrite all the RET instruction into
/// a BRANCH with return values.
pub struct RetSink {
name: &'static str
}
impl RetSink {
pub fn new() -> RetSink {
RetSink {
name: "Creating Return Sink"
}
}
}
impl CompilerPass for RetSink {
fn name(&self) -> &'static str {
self.name
}
fn as_any(&self) -> &Any {
self
}
fn visit_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
let mut f_content = func.content.take().unwrap();
// create a return sink
let return_sink = {
let block_name = format!("{}:epilogue", func.name());
trace!("created return sink {}", block_name);
let mut block = Block::new(MuEntityHeader::named(vm.next_id(), block_name));
vm.set_name(block.as_entity());
let sig = func.sig.clone();
let args : Vec<P<Value>> = sig.ret_tys.iter()
.map(|ty| func.new_ssa(MuEntityHeader::unnamed(vm.next_id()), ty.clone()).clone_value()).collect();
block.content = Some(BlockContent {
args: args.clone(),
exn_arg: None,
body: vec![
func.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: args.iter().map(|val| TreeNode::new_value(val.clone())).collect(),
v: Instruction_::Return((0..args.len()).collect())
})
],
keepalives: None
});
block
};
// rewrite existing RET instruction to a BRANCH
// use RET values as BRANCH's goto values
for (blk_id, mut block) in f_content.blocks.iter_mut() {
trace!("block: {}", blk_id);
// old block content
let block_content = block.content.as_ref().unwrap().clone();
let mut new_body = vec![];
for node in block_content.body.iter() {
match node.v {
TreeNode_::Instruction(Instruction {ref ops, v: Instruction_::Return(ref arg_index), ..}) => {
let branch_to_sink = func.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: ops.clone(),
v: Instruction_::Branch1(Destination {
target: return_sink.id(),
args: arg_index.iter().map(|i| DestArg::Normal(*i)).collect()
})
});
new_body.push(branch_to_sink);
}
_ => new_body.push(node.clone())
}
}
block.content = Some(BlockContent {
args : block_content.args.to_vec(),
exn_arg : block_content.exn_arg.clone(),
body : new_body,
keepalives: block_content.keepalives.clone()
});
}
// insert return sink
f_content.blocks.insert(return_sink.id(), return_sink);
// put back the function content
func.content = Some(f_content);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment