diff --git a/cranelift/filetests/regalloc/multi-constraints.cton b/cranelift/filetests/regalloc/multi-constraints.cton new file mode 100644 index 0000000000..80dc8f0658 --- /dev/null +++ b/cranelift/filetests/regalloc/multi-constraints.cton @@ -0,0 +1,29 @@ +test regalloc +set is_64bit +isa intel haswell + +; Test combinations of constraints. +; +; The Intel ushr instruction requires its second operand to be passed in %rcx and its output is +; tied to the first input operand. +; +; If we pass the same value to both operands, both constraints must be satisfied. + +; Found by the Binaryen fuzzer in PR221. +; +; Conditions triggering the problem: +; +; - The same value used for a tied operand and a fixed operand. +; - The common value is already in %rcx. +; - The tied output value is live outside the EBB. +; +; Under these conditions, Solver::add_tied_input() would create a variable for the tied input +; without considering the fixed constraint. +function %pr221(i64 [%rdi], i64 [%rsi], i64 [%rdx], i64 [%rcx]) -> i64 [%rax] { +ebb0(v0: i64, v1: i64, v2: i64, v3: i64): + v4 = ushr v3, v3 + jump ebb1 + +ebb1: + return v4 +} diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/cretonne/src/regalloc/coloring.rs index 9d82c0b21a..18d141eb75 100644 --- a/lib/cretonne/src/regalloc/coloring.rs +++ b/lib/cretonne/src/regalloc/coloring.rs @@ -499,14 +499,15 @@ impl<'a> Context<'a> { match op.kind { ConstraintKind::FixedReg(regunit) | ConstraintKind::FixedTied(regunit) => { - if regunit != cur_reg { - self.solver.reassign_in( - value, - op.regclass, - cur_reg, - regunit, - ); - } + // Add the fixed constraint even if `cur_reg == regunit`. + // It is possible that we will want to convert the value to a variable later, + // and this identity assignment prevents that from happening. + self.solver.reassign_in( + value, + op.regclass, + cur_reg, + regunit, + ); } ConstraintKind::Reg | ConstraintKind::Tied(_) => {