|
@@ -132,51 +132,66 @@ impl<'a> ir::MutVisitor for DfgOptimizer<'a> {
|
|
|
|
|
|
|
|
|
|
pub struct LinOptimizer {
|
|
pub struct LinOptimizer {
|
|
- offset: i64
|
|
|
|
|
|
+ offset: i64,
|
|
|
|
+ pub instructions: Vec<Instruction>
|
|
}
|
|
}
|
|
|
|
|
|
impl LinOptimizer {
|
|
impl LinOptimizer {
|
|
pub fn new() -> Self {
|
|
pub fn new() -> Self {
|
|
LinOptimizer {
|
|
LinOptimizer {
|
|
- offset: 0
|
|
|
|
|
|
+ offset: 0,
|
|
|
|
+ instructions: Vec::new()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl ir::MutVisitor for LinOptimizer {
|
|
impl ir::MutVisitor for LinOptimizer {
|
|
- type Ret = ();
|
|
|
|
|
|
+ type Ret = Option<Instruction>;
|
|
|
|
|
|
- fn visit_instructions(&mut self, instr: &mut Vec<Instruction>) {
|
|
|
|
- for inst in instr {
|
|
|
|
|
|
+ fn visit_instructions(&mut self, instrs: &mut Vec<Instruction>) {
|
|
|
|
+ for inst in instrs {
|
|
self.walk_instruction(inst);
|
|
self.walk_instruction(inst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_add(&mut self, add: &mut Instruction) {
|
|
|
|
- if let Instruction::Add{ offset, value: _value } = add {
|
|
|
|
- *offset += self.offset;
|
|
|
|
|
|
+ fn visit_add(&mut self, add: &mut Instruction) -> Self::Ret {
|
|
|
|
+ if let Instruction::Add{ offset, value } = add {
|
|
|
|
+ self.instructions.push(Instruction::Add{ offset: *offset + self.offset, value: *value });
|
|
}
|
|
}
|
|
|
|
+ None
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_set(&mut self, set: &mut Instruction) {
|
|
|
|
- if let Instruction::Set{ offset, value: _value } = set {
|
|
|
|
- *offset += self.offset;
|
|
|
|
|
|
+ fn visit_set(&mut self, set: &mut Instruction) -> Self::Ret {
|
|
|
|
+ if let Instruction::Set{ offset, value } = set {
|
|
|
|
+ self.instructions.push(Instruction::Set{ offset: *offset + self.offset, value: *value });
|
|
}
|
|
}
|
|
|
|
+ None
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_linear_loop(&mut self, lloop: &mut Instruction) {
|
|
|
|
|
|
+ fn visit_linear_loop(&mut self, lloop: &mut Instruction) -> Self::Ret {
|
|
|
|
+ self.instructions.push(std::mem::replace(lloop, Instruction::Nop));
|
|
|
|
+ None
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_move_ptr(&mut self, move_ptr: &mut Instruction) {
|
|
|
|
|
|
+ fn visit_move_ptr(&mut self, move_ptr: &mut Instruction) -> Self::Ret {
|
|
if let Instruction::MovePtr(offset) = move_ptr {
|
|
if let Instruction::MovePtr(offset) = move_ptr {
|
|
self.offset += *offset;
|
|
self.offset += *offset;
|
|
}
|
|
}
|
|
|
|
+ None
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_loop(&mut self, l: &mut Instruction) {
|
|
|
|
|
|
+ fn visit_loop(&mut self, l: &mut Instruction) -> Self::Ret {
|
|
if let Instruction::Loop(instrs) = l {
|
|
if let Instruction::Loop(instrs) = l {
|
|
let mut increments: BTreeMap<i64, i64> = BTreeMap::new();
|
|
let mut increments: BTreeMap<i64, i64> = BTreeMap::new();
|
|
let mut dirty = false;
|
|
let mut dirty = false;
|
|
|
|
+
|
|
|
|
+ // pointer movement to be added in case this loop cannot be linearized
|
|
|
|
+ let offset_before = self.offset;
|
|
|
|
+ self.offset = 0;
|
|
|
|
+
|
|
|
|
+ let mut swap: Vec<Instruction> = Vec::new();
|
|
|
|
+ std::mem::swap(&mut self.instructions, &mut swap);
|
|
|
|
+
|
|
for inst in instrs {
|
|
for inst in instrs {
|
|
self.walk_instruction(inst);
|
|
self.walk_instruction(inst);
|
|
if !dirty {
|
|
if !dirty {
|
|
@@ -190,38 +205,52 @@ impl ir::MutVisitor for LinOptimizer {
|
|
},
|
|
},
|
|
_ => {
|
|
_ => {
|
|
dirty = true;
|
|
dirty = true;
|
|
- break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ if self.offset != 0 {
|
|
|
|
+ self.instructions.push(Instruction::MovePtr(self.offset));
|
|
|
|
+ self.offset = 0;
|
|
|
|
+ }
|
|
|
|
+ std::mem::swap(&mut self.instructions, &mut swap);
|
|
|
|
|
|
if !dirty && increments.len() == 1 {
|
|
if !dirty && increments.len() == 1 {
|
|
|
|
+ self.offset = offset_before;
|
|
if let Some(&v) = increments.get(&0) {
|
|
if let Some(&v) = increments.get(&0) {
|
|
if v % 2 != 0 {
|
|
if v % 2 != 0 {
|
|
// cases like [-]
|
|
// cases like [-]
|
|
// also [---]
|
|
// also [---]
|
|
- std::mem::replace(l, Instruction::Set{ offset: self.offset, value: 0 });
|
|
|
|
|
|
+ self.instructions.push(Instruction::Set{ offset: self.offset, value: 0 });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if !dirty && increments.get(&0) == Some(&-1) {
|
|
else if !dirty && increments.get(&0) == Some(&-1) {
|
|
- std::mem::replace(l, Instruction::LinearLoop{ offset: self.offset, factors: increments });
|
|
|
|
|
|
+ self.offset = offset_before;
|
|
|
|
+ self.instructions.push(Instruction::LinearLoop{ offset: self.offset, factors: increments });
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ if offset_before != 0 {
|
|
|
|
+ self.instructions.push(Instruction::MovePtr(offset_before));
|
|
|
|
+ }
|
|
|
|
+ self.instructions.push(Instruction::Loop(swap));
|
|
}
|
|
}
|
|
-
|
|
|
|
// set cell at offset 0 to 0
|
|
// set cell at offset 0 to 0
|
|
}
|
|
}
|
|
|
|
+ None
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_read(&mut self, read: &'_ mut Instruction) {
|
|
|
|
|
|
+ fn visit_read(&mut self, read: &mut Instruction) -> Self::Ret {
|
|
if let Instruction::Read(offset) = read {
|
|
if let Instruction::Read(offset) = read {
|
|
- *offset += self.offset;
|
|
|
|
|
|
+ self.instructions.push(Instruction::Read(*offset + self.offset));
|
|
}
|
|
}
|
|
|
|
+ None
|
|
}
|
|
}
|
|
|
|
|
|
- fn visit_write(&mut self, write: &'_ mut Instruction) {
|
|
|
|
|
|
+ fn visit_write(&mut self, write: &'_ mut Instruction) -> Self::Ret {
|
|
if let Instruction::Write(offset) = write {
|
|
if let Instruction::Write(offset) = write {
|
|
- *offset += self.offset;
|
|
|
|
|
|
+ self.instructions.push(Instruction::Write(*offset + self.offset));
|
|
}
|
|
}
|
|
|
|
+ None
|
|
}
|
|
}
|
|
}
|
|
}
|