diff --git a/cranelift/filetests/regalloc/coalesce.cton b/cranelift/filetests/regalloc/coalesce.cton index 60ef905d15..41fc6e9771 100644 --- a/cranelift/filetests/regalloc/coalesce.cton +++ b/cranelift/filetests/regalloc/coalesce.cton @@ -91,3 +91,21 @@ ebb1(v10: i32, v11: i32): brnz v13, ebb1(v11, v12) return v12 } + +; Function arguments passed on the stack aren't allowed to be part of a virtual +; register, at least for now. This is because the other values in the virtual +; register would need to be spilled to the incoming_arg stack slot which we treat +; as belonging to the caller. +function %stackarg(i32, i32, i32, i32, i32, i32, i32, i32, i32) -> i32 { +; check: ss0 = incoming_arg 4 +; not: incoming_arg +ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32, v8: i32): + ; check: fill v8 + ; not: v8 + brnz v0, ebb1(v8) + jump ebb1(v7) + +ebb1(v10: i32): + v11 = iadd_imm v10, 1 + return v11 +} diff --git a/lib/cretonne/src/regalloc/coalescing.rs b/lib/cretonne/src/regalloc/coalescing.rs index 70a20e3897..634f0c0a32 100644 --- a/lib/cretonne/src/regalloc/coalescing.rs +++ b/lib/cretonne/src/regalloc/coalescing.rs @@ -8,7 +8,7 @@ use dbg::DisplayList; use dominator_tree::DominatorTree; use flowgraph::{ControlFlowGraph, BasicBlock}; -use ir::{DataFlowGraph, Layout, Cursor, InstBuilder}; +use ir::{DataFlowGraph, Layout, Cursor, InstBuilder, ValueDef}; use ir::{Function, Ebb, Inst, Value, ExpandedProgramPoint}; use regalloc::affinity::Affinity; use regalloc::liveness::Liveness; @@ -400,6 +400,22 @@ impl<'a> Context<'a> { pred_val, pred_ebb, self.func.dfg.display_inst(pred_inst)); + + // Never coalesce incoming function arguments on the stack. These arguments are + // pre-spilled, and the rest of the virtual register would be forced to spill to the + // `incoming_arg` stack slot too. + if let ValueDef::Arg(def_ebb, def_num) = self.func.dfg.value_def(pred_val) { + if Some(def_ebb) == self.func.layout.entry_block() && + self.func.signature.argument_types[def_num] + .location + .is_stack() { + dbg!("Isolating incoming stack parameter {}", pred_val); + let new_val = self.split_pred(pred_inst, pred_ebb, argnum, pred_val); + assert!(self.add_class(new_val).is_ok()); + continue; + } + } + if let Err((a, b)) = self.add_class(pred_val) { dbg!("Found conflict between {} and {}", a, b); // We have a conflict between the already merged value `a` and one of the new