Skip to content

Commit c8a1a34

Browse files
committed
fix(phi): finally understand when which phi should be moved to
1 parent c1bd5a9 commit c8a1a34

File tree

9 files changed

+272
-247
lines changed

9 files changed

+272
-247
lines changed

run-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env fish
22
cargo build --release
3-
nix run github:I-Al-Istannen/crow#client -- run-tests --test-dir tests/ --compiler-run ./run.sh
3+
nix run github:I-Al-Istannen/crow#client -- run-tests --test-dir tests/ --compiler-run ./run.sh --only-failing

src/backend/codegen.rs

Lines changed: 119 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::ir::{
1313

1414
use super::regalloc::{HardwareRegister, Register, RegisterAllocator};
1515

16-
type Registers<'a> = HashMap<(BlockIndex, NodeIndex), Box<dyn Register>>;
16+
pub type Registers = HashMap<(BlockIndex, NodeIndex), Box<dyn Register>>;
1717

1818
const TEMPLATE: &str = " .section .note.GNU-stack,\"\",@progbits
1919
.global main
@@ -135,14 +135,15 @@ impl CodeGenerator {
135135
ir_graph: &IRGraph,
136136
registers: &Registers,
137137
) -> String {
138-
// Start and End Nodes should not emit code
138+
// End Node should not emit code
139139
if block.get_nodes().is_empty() {
140140
return String::new();
141141
}
142142

143143
let mut code = String::new();
144144
let block_label = self.jump_label.get(&block_index).unwrap();
145145
code.push_str(&format!("{}:\n", block_label));
146+
146147
for (node_index, node) in block.get_nodes().iter().enumerate() {
147148
code.push_str(&self.generate_for_node(
148149
node,
@@ -229,7 +230,7 @@ impl CodeGenerator {
229230
));
230231
}
231232
Node::Return(data) => {
232-
code.push_str(&self.generate_return(ir_graph, data, registers));
233+
code.push_str(&self.generate_return(block, block_index, data, registers));
233234
}
234235
Node::ConstantInt(data) => {
235236
code.push_str(&self.generate_constant_int(
@@ -268,19 +269,33 @@ impl CodeGenerator {
268269
| Node::NotEquals(data)
269270
| Node::Lower(data)
270271
| Node::Higher(data) => {
271-
code.push_str(&self.generate_comparison(block, data, ir_graph, registers));
272+
code.push_str(&self.generate_comparison(
273+
block,
274+
block_index,
275+
data,
276+
ir_graph,
277+
registers,
278+
));
272279
}
273-
Node::ConstantBool(data) => code.push_str(&self.generate_constant_bool(data.value())),
274-
Node::Phi(data) => {
275-
debug!("Warning! Phi present: Aliasing {:?}", data.operands());
280+
Node::BitwiseNegate(data) => {
281+
let register = registers.get(&(block_index, data.input())).unwrap();
282+
code.push_str(&format!("not {}", register.as_assembly()));
276283
}
284+
Node::ConstantBool(data) => code.push_str(&self.generate_constant_bool(data.value())),
285+
Node::Phi(data) => {}
277286
Node::Jump => {
278287
trace!(
279288
"Generating assembly for jump: {} with destination XXX",
280289
node,
281290
);
282-
let previous_block_index = jump_information.get(&node_index).unwrap();
283-
let label = self.jump_label.get(previous_block_index).unwrap();
291+
let following_block_index = jump_information.get(&node_index).unwrap();
292+
let label = self.jump_label.get(following_block_index).unwrap();
293+
code.push_str(&self.generate_phi_moves(
294+
block_index,
295+
*following_block_index,
296+
registers,
297+
ir_graph,
298+
));
284299
code.push_str(&format!("jmp {}\n", label));
285300
}
286301
Node::ConditionalJump(_) => {}
@@ -289,19 +304,37 @@ impl CodeGenerator {
289304
"Generating IR for true projection (including jump) with jump information {:?}",
290305
jump_information
291306
);
292-
let previous_block_index = jump_information.get(&node_index).unwrap();
293-
let conditional_jump_code =
294-
self.generate_conditional_jump(node_index, block, *previous_block_index);
307+
let following_block_index = jump_information.get(&node_index).unwrap();
308+
let conditional_jump_code = self.generate_conditional_jump(
309+
node_index,
310+
block,
311+
block_index,
312+
*following_block_index,
313+
registers,
314+
);
315+
code.push_str(&self.generate_phi_moves(
316+
block_index,
317+
*following_block_index,
318+
registers,
319+
ir_graph,
320+
));
295321
code.push_str(&conditional_jump_code.expect("Expected jump code"));
296322
}
297323
Node::Projection(data)
298324
if data.projection_info().eq(&ProjectionInformation::IfFalse) =>
299325
{
300-
let previous_block_index = jump_information.get(&node_index).unwrap();
326+
let following_block_index = jump_information.get(&node_index).unwrap();
301327
let jump_label = self
302328
.jump_label
303-
.get(previous_block_index)
329+
.get(following_block_index)
304330
.expect("Expected jump label for false if");
331+
code.push_str(&self.generate_phi_moves(
332+
block_index,
333+
*following_block_index,
334+
registers,
335+
ir_graph,
336+
));
337+
305338
code.push_str(&format!("jmp {}\n", jump_label));
306339
}
307340
Node::Projection(_) => return code,
@@ -311,6 +344,42 @@ impl CodeGenerator {
311344
code
312345
}
313346

347+
pub fn generate_phi_moves(
348+
&self,
349+
current_block_index: BlockIndex,
350+
following_block_index: BlockIndex,
351+
registers: &Registers,
352+
ir_graph: &IRGraph,
353+
) -> String {
354+
let mut code = String::new();
355+
let following_block = ir_graph.get_block(following_block_index);
356+
for phi_index in following_block.phis() {
357+
let phi = following_block.get_node(*phi_index);
358+
if let Node::Phi(data) = phi {
359+
let destination_register =
360+
registers.get(&(following_block_index, *phi_index)).unwrap();
361+
for operand in data.operands() {
362+
if operand.0 != current_block_index {
363+
continue;
364+
}
365+
let source_register = registers.get(&operand).unwrap();
366+
code.push_str(&format!(
367+
"movq {}, {}\n",
368+
source_register.as_assembly(),
369+
destination_register.as_assembly()
370+
));
371+
break;
372+
}
373+
}
374+
}
375+
trace!(
376+
"Generated the following phi moves for block {}: {}",
377+
current_block_index,
378+
code
379+
);
380+
code
381+
}
382+
314383
pub fn generate_constant_bool(&self, value: bool) -> String {
315384
let mut code = String::new();
316385
if value {
@@ -325,7 +394,9 @@ impl CodeGenerator {
325394
&self,
326395
projection_index: usize,
327396
current_block: &Block,
397+
current_block_index: BlockIndex,
328398
previous_block: usize,
399+
registers: &Registers,
329400
) -> Option<String> {
330401
let mut code = String::new();
331402
let true_label = self.jump_label.get(&previous_block).unwrap();
@@ -343,6 +414,13 @@ impl CodeGenerator {
343414
Node::HigherEquals(_) => "jae",
344415
Node::Higher(_) => "ja",
345416
Node::ConstantBool(_) => "je",
417+
Node::BitwiseNegate(_) => "jne",
418+
Node::Phi(_) | Node::ConstantInt(_) => {
419+
let register = registers.get(&(current_block_index, comparision)).unwrap();
420+
code.push_str(&format!("testq $0x1, {}\n", register.as_assembly()));
421+
code.push_str(&format!("jnz {}\n", true_label));
422+
return Some(code);
423+
}
346424
node => panic!("Invalid operation before conditional jump: {}", node),
347425
};
348426
code.push_str(&format!("{} {}\n", op_code, true_label));
@@ -352,15 +430,22 @@ impl CodeGenerator {
352430
pub fn generate_comparison(
353431
&self,
354432
block: &Block,
433+
block_index: BlockIndex,
355434
operation_data: &BinaryOperationData,
356435
ir_graph: &IRGraph,
357436
registers: &Registers,
358437
) -> String {
359438
let left_value = registers
360-
.get(&predecessor_skip_projection(ir_graph, operation_data.lhs()))
439+
.get(&(
440+
block_index,
441+
predecessor_skip_projection(block, operation_data.lhs()),
442+
))
361443
.unwrap();
362444
let right_value = registers
363-
.get(&predecessor_skip_projection(ir_graph, operation_data.rhs()))
445+
.get(&(
446+
block_index,
447+
predecessor_skip_projection(block, operation_data.rhs()),
448+
))
364449
.unwrap();
365450
let mut code = String::new();
366451
if !left_value.hardware_register() && !right_value.hardware_register() {
@@ -393,10 +478,10 @@ impl CodeGenerator {
393478
op_code: &str,
394479
) -> String {
395480
let left_value = registers
396-
.get(&predecessor_skip_projection(ir_graph, data.lhs()))
481+
.get(&(block_index, predecessor_skip_projection(block, data.lhs())))
397482
.unwrap();
398483
let right_value = registers
399-
.get(&predecessor_skip_projection(ir_graph, data.rhs()))
484+
.get(&(block_index, predecessor_skip_projection(block, data.rhs())))
400485
.unwrap();
401486

402487
let destination_register = registers.get(&(block_index, node_index)).unwrap();
@@ -444,10 +529,10 @@ impl CodeGenerator {
444529
mode: &str,
445530
) -> String {
446531
let left_value = registers
447-
.get(&predecessor_skip_projection(ir_graph, data.lhs()))
532+
.get(&(block_index, predecessor_skip_projection(block, data.lhs())))
448533
.unwrap();
449534
let right_value = registers
450-
.get(&predecessor_skip_projection(ir_graph, data.rhs()))
535+
.get(&(block_index, predecessor_skip_projection(block, data.rhs())))
451536
.unwrap();
452537
let destination_register = registers.get(&(block_index, node_index)).unwrap();
453538
let mut code = String::new();
@@ -491,8 +576,8 @@ impl CodeGenerator {
491576
op_code: &str,
492577
) -> String {
493578
let mut code = String::new();
494-
let left_value = registers.get(&data.lhs()).unwrap();
495-
let right_value = registers.get(&data.rhs()).unwrap();
579+
let left_value = registers.get(&(block_index, data.lhs())).unwrap();
580+
let right_value = registers.get(&(block_index, data.rhs())).unwrap();
496581
code.push_str(&format!(
497582
"movq {}, {}\n",
498583
right_value.as_assembly(),
@@ -515,21 +600,27 @@ impl CodeGenerator {
515600

516601
pub fn generate_return(
517602
&self,
518-
ir_graph: &IRGraph,
603+
block: &Block,
604+
block_index: BlockIndex,
519605
data: &ReturnData,
520606
registers: &Registers,
521607
) -> String {
522608
debug!("Generating assembly for return");
523-
let return_node = predecessor_skip_projection(ir_graph, data.input());
609+
let return_node = predecessor_skip_projection(block, data.input());
524610
debug!(
525611
"Determined node {} that contains the return result",
526-
ir_graph.get_node(return_node)
612+
block.get_node(return_node)
527613
);
528614
debug!("Registers: {:?}", registers);
529615

530616
let mut code = String::new();
531617
code.push_str("mov ");
532-
code.push_str(&registers.get(&return_node).unwrap().as_assembly());
618+
code.push_str(
619+
&registers
620+
.get(&(block_index, return_node))
621+
.unwrap()
622+
.as_assembly(),
623+
);
533624
code.push_str(", %rax");
534625
code.push('\n');
535626

@@ -558,11 +649,8 @@ impl CodeGenerator {
558649
}
559650
}
560651

561-
fn predecessor_skip_projection(
562-
ir_graph: &IRGraph,
563-
data: (BlockIndex, NodeIndex),
564-
) -> (BlockIndex, NodeIndex) {
565-
let predecessor = ir_graph.get_node(data);
652+
fn predecessor_skip_projection(block: &Block, data: NodeIndex) -> NodeIndex {
653+
let predecessor = block.get_node(data);
566654
if let Node::Projection(data) = predecessor {
567655
data.input()
568656
} else {

src/backend/regalloc.rs

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ use std::{
55

66
use tracing::debug;
77

8-
use crate::ir::{
9-
block::NodeIndex,
10-
graph::{BlockIndex, IRGraph, END_BLOCK},
11-
node::Node,
8+
use crate::{
9+
backend::codegen::Registers,
10+
ir::{
11+
block::NodeIndex,
12+
graph::{BlockIndex, IRGraph, END_BLOCK},
13+
node::Node,
14+
},
1215
};
1316
pub trait Register {
1417
fn as_assembly(&self) -> String;
@@ -179,7 +182,7 @@ impl Display for StackRegister {
179182

180183
pub struct RegisterAllocator {
181184
current_stack_offset: usize,
182-
registers: HashMap<(BlockIndex, NodeIndex), Box<dyn Register>>,
185+
registers: Registers,
183186
// Denotes that the key has been aliased by the value
184187
aliased_nodes: HashMap<(BlockIndex, NodeIndex), (BlockIndex, NodeIndex)>,
185188
available_hardware_register: Vec<HardwareRegister>,
@@ -210,10 +213,7 @@ impl RegisterAllocator {
210213
}
211214
}
212215

213-
pub fn allocate_registers(
214-
mut self,
215-
graph: &IRGraph,
216-
) -> (HashMap<(BlockIndex, NodeIndex), Box<dyn Register>>, usize) {
216+
pub fn allocate_registers(mut self, graph: &IRGraph) -> (Registers, usize) {
217217
let mut visited = Vec::new();
218218
self.scan(END_BLOCK, graph, &mut visited);
219219
(self.registers, self.current_stack_offset)
@@ -270,28 +270,7 @@ impl RegisterAllocator {
270270
ir_graph: &IRGraph,
271271
register: &Box<dyn Register>,
272272
) {
273-
let node = ir_graph.get_node(node_index);
274-
if let Node::Phi(data) = node {
275-
debug!("Handling phi in register allocation: Aliasing the following nodes to store in the same node: {:?}", data.operands());
276-
for (predecessor_block, predecessor_index) in data.operands() {
277-
if self
278-
.aliased_nodes
279-
.contains_key(&(predecessor_block, predecessor_index))
280-
{
281-
self.registers.insert(
282-
*self
283-
.aliased_nodes
284-
.get(&(predecessor_block, predecessor_index))
285-
.unwrap(),
286-
register.box_clone(),
287-
);
288-
}
289-
self.registers
290-
.insert((predecessor_block, predecessor_index), register.box_clone());
291-
self.aliased_nodes
292-
.insert((predecessor_block, predecessor_index), node_index);
293-
}
294-
}
273+
return;
295274
}
296275

297276
pub fn has_available_hardware_register(&self) -> bool {

0 commit comments

Comments
 (0)