diff --git a/cranelift/filetests/isa/intel/prologue-epilogue.cton b/cranelift/filetests/isa/intel/prologue-epilogue.cton index 0eadcd27d7..ef42836a5a 100644 --- a/cranelift/filetests/isa/intel/prologue-epilogue.cton +++ b/cranelift/filetests/isa/intel/prologue-epilogue.cton @@ -207,3 +207,25 @@ ebb0(v0: i64, v1: i64): ; nextln: v54 = x86_pop.i64 ; nextln: return v54, v55, v56, v57, v58, v59 ; nextln: } + +; A function which uses diverted registers. + +function %divert(i32) -> i32 system_v { +ebb0(v0: i32): + v2 = iconst.i32 0 + v3 = iconst.i32 1 + jump ebb3(v0, v3, v2) + +ebb3(v4: i32, v5: i32, v6: i32): + brz v4, ebb4 + v7 = iadd v5, v6 + v8 = iadd_imm v4, -1 + jump ebb3(v8, v7, v5) + +ebb4: + return v5 +} + +; check: function %divert +; check: regmove v5, %rcx -> %rbx +; check: [RexOp1popq#58,%rbx] v15 = x86_pop.i64 diff --git a/lib/cretonne/src/isa/intel/abi.rs b/lib/cretonne/src/isa/intel/abi.rs index f1abd1cb42..488f8a3d49 100644 --- a/lib/cretonne/src/isa/intel/abi.rs +++ b/lib/cretonne/src/isa/intel/abi.rs @@ -184,6 +184,26 @@ fn callee_saved_gprs_used(flags: &shared_settings::Flags, func: &ir::Function) - } } + // regmove and regfill instructions may temporarily divert values into other registers, + // and these are not reflected in `func.locations`. Scan the function for such instructions + // and note which callee-saved registers they use. + // + // TODO: Consider re-evaluating how regmove/regfill/regspill work and whether it's possible + // to avoid this step. + for ebb in &func.layout { + for inst in func.layout.ebb_insts(ebb) { + match func.dfg[inst] { + ir::instructions::InstructionData::RegMove { dst, .. } | + ir::instructions::InstructionData::RegFill { dst, .. } => { + if !used.is_avail(GPR, dst) { + used.free(GPR, dst); + } + } + _ => (), + } + } + } + used.intersect(&all_callee_saved); return used; }