pub fn spill_rewrite(
    spills: &LinkedHashMap<MuID, P<Value>>,
    func: &mut MuFunctionVersion,
    cf: &mut CompiledFunction,
    vm: &VM
) -> LinkedHashMap<MuID, MuID> {
    trace!("spill rewrite for x86_64 asm backend");

    trace!("code before spilling");
    cf.mc().trace_mc();

    // if temp a gets spilled, all its uses and defines will become a use/def of a scratch temp
    // we maintain this mapping for later use
    let mut spilled_scratch_temps = LinkedHashMap::new();

    // record code and their insertion point, so we can do the copy/insertion all at once
    let mut spill_code_before: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new();
    let mut spill_code_after: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new();

    // map from old to new
    let mut temp_for_cur_inst: LinkedHashMap<MuID, P<Value>> = LinkedHashMap::new();

    // iterate through all instructions
    for i in 0..cf.mc().number_of_insts() {
        temp_for_cur_inst.clear();

        trace!("---Inst {}---", i);
        // find use of any register that gets spilled
        {
            let reg_uses = cf.mc().get_inst_reg_uses(i).to_vec();
            for reg in reg_uses {
                if spills.contains_key(&reg) {
                    let val_reg = func.context.get_value(reg).unwrap().value().clone();

                    // a register used here is spilled
                    let spill_mem = spills.get(&reg).unwrap();

                    // generate a random new temporary
                    let temp_ty = val_reg.ty.clone();
                    let temp = func.new_ssa(MuEntityHeader::unnamed(vm.next_id()), temp_ty.clone())
                        .clone_value();

                    // maintain mapping
                    trace!(
                        "reg {} used in Inst{} is replaced as {}",
                        val_reg.id(),
                        i,
                        temp
                    );
                    spilled_scratch_temps.insert(temp.id(), reg);

                    // generate a load
                    let code = {
                        let mut codegen = ASMCodeGen::new();
                        codegen.start_code_sequence();

                        if RegGroup::get_from_ty(&temp_ty) == RegGroup::FPR {
                            codegen.emit_spill_load_fpr(&temp, spill_mem);
                        } else if RegGroup::get_from_ty(&temp_ty) == RegGroup::GPR {
                            codegen.emit_spill_load_gpr(&temp, spill_mem);
                        } else {
                            panic!("expected spilling a reg or freg, found {}", temp_ty);
                        }

                        codegen.finish_code_sequence_asm()
                    };
                    // record that this load will be inserted at i
                    trace!("insert before inst #{}", i);
                    if spill_code_before.contains_key(&i) {
                        spill_code_before.get_mut(&i).unwrap().push(code);
                    } else {
                        spill_code_before.insert(i, vec![code]);
                    }

                    // replace register reg with temp
                    cf.mc_mut().replace_use_tmp_for_inst(reg, temp.id(), i);

                    temp_for_cur_inst.insert(reg, temp.clone());
                }
            }
        }

        // find define of any register that gets spilled
        {
            let reg_defines = cf.mc().get_inst_reg_defines(i).to_vec();
            for reg in reg_defines {
                if spills.contains_key(&reg) {
                    let val_reg = func.context.get_value(reg).unwrap().value().clone();

                    let spill_mem = spills.get(&reg).unwrap();

                    let temp = if temp_for_cur_inst.contains_key(&reg) {
                        temp_for_cur_inst.get(&reg).unwrap().clone()
                    } else {
                        let temp_ty = val_reg.ty.clone();
                        let temp =
                            func.new_ssa(MuEntityHeader::unnamed(vm.next_id()), temp_ty.clone())
                                .clone_value();

                        spilled_scratch_temps.insert(temp.id(), reg);

                        temp
                    };
                    trace!(
                        "reg {} defined in Inst{} is replaced as {}",
                        val_reg.id(),
                        i,
                        temp
                    );

                    let code = {
                        let mut codegen = ASMCodeGen::new();
                        codegen.start_code_sequence();

                        if RegGroup::get_from_ty(&temp.ty) == RegGroup::FPR {
                            codegen.emit_spill_store_fpr(spill_mem, &temp);
                        } else if RegGroup::get_from_ty(&temp.ty) == RegGroup::GPR {
                            codegen.emit_spill_store_gpr(spill_mem, &temp);
                        } else {
                            panic!("expected spilling a reg or freg, found {}", temp.ty);
                        }

                        codegen.finish_code_sequence_asm()
                    };

                    trace!("insert after inst #{}", i);
                    if spill_code_after.contains_key(&i) {
                        spill_code_after.get_mut(&i).unwrap().push(code);
                    } else {
                        spill_code_after.insert(i, vec![code]);
                    }

                    cf.mc_mut().replace_define_tmp_for_inst(reg, temp.id(), i);
                }
            }
        }
    }

    // copy and insert the code
    let new_mc = {
        let old_mc = cf.mc.take().unwrap();
        let old_mc_ref: &ASMCode = old_mc.as_any().downcast_ref().unwrap();
        old_mc_ref.rewrite_insert(spill_code_before, spill_code_after)
    };

    cf.mc = Some(new_mc);

    trace!("spill rewrite done");

    trace!("code after spilling");
    cf.mc().trace_mc();

    spilled_scratch_temps
}
/// rewrites the machine code of a function version for spilling.
/// spills: a map from temporary IDs that get spilled to memory operands of their spilling location
rewrites the machine code of a function version for spilling.
spills: a map from temporary IDs that get spilled to memory operands of their spilling location
rewrites the machine code of a function version for spilling . spills : a map from temporary IDs that get spilled to memory operands of their spilling location
pub fn spill_rewrite(
    spills: &LinkedHashMap<MuID, P<Value>>,
    func: &mut MuFunctionVersion,
    cf: &mut CompiledFunction,
    vm: &VM
) -> LinkedHashMap<MuID, MuID> {
    trace!("spill rewrite for x86_64 asm backend");
    trace!("code before spilling");
    cf.mc().trace_mc();
    // if temp a gets spilled, all its uses and defines will become a use/def of a scratch temp
    // we maintain this mapping for later use
    let mut spilled_scratch_temps = LinkedHashMap::new();
    // record code and their insertion point, so we can do the copy/insertion all at once
    let mut spill_code_before: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new();
    let mut spill_code_after: LinkedHashMap<usize, Vec<Box<ASMCode>>> = LinkedHashMap::new();
    // map from old to new
    let mut temp_for_cur_inst: LinkedHashMap<MuID, P<Value>> = LinkedHashMap::new();
    // iterate through all instructions
    for i in 0..cf.mc().number_of_insts() {
        temp_for_cur_inst.clear();
        trace!("---Inst {}---", i);
        // find use of any register that gets spilled
        {
            let reg_uses = cf.mc().get_inst_reg_uses(i).to_vec();
            for reg in reg_uses {
                if spills.contains_key(&reg) {
                    let val_reg = func.context.get_value(reg).unwrap().value().clone();
                    // a register used here is spilled
                    let spill_mem = spills.get(&reg).unwrap();
                    // generate a random new temporary
                    let temp_ty = val_reg.ty.clone();
                    let temp = func.new_ssa(MuEntityHeader::unnamed(vm.next_id()), temp_ty.clone())
                        .clone_value();
                    // maintain mapping
                    trace!(
                        "reg {} used in Inst{} is replaced as {}",
                        val_reg.id(),
                        i,
                        temp
                    );
                    spilled_scratch_temps.insert(temp.id(), reg);
                    // generate a load
                    let code = {
                        let mut codegen = ASMCodeGen::new();
                        codegen.start_code_sequence();
                        if RegGroup::get_from_ty(&temp_ty) == RegGroup::FPR {
                            codegen.emit_spill_load_fpr(&temp, spill_mem);
                        } else if RegGroup::get_from_ty(&temp_ty) == RegGroup::GPR {
                            codegen.emit_spill_load_gpr(&temp, spill_mem);
                        } else {
                            panic!("expected spilling a reg or freg, found {}", temp_ty);
                        }
                        codegen.finish_code_sequence_asm()
                    };
                    // record that this load will be inserted at i
                    trace!("insert before inst #{}", i);
                    if spill_code_before.contains_key(&i) {
                        spill_code_before.get_mut(&i).unwrap().push(code);
                    } else {
                        spill_code_before.insert(i, vec![code]);
                    }
                    // replace register reg with temp
                    cf.mc_mut().replace_use_tmp_for_inst(reg, temp.id(), i);
                    temp_for_cur_inst.insert(reg, temp.clone());
                }
            }
        }
        // find define of any register that gets spilled
        {
            let reg_defines = cf.mc().get_inst_reg_defines(i).to_vec();
            for reg in reg_defines {
                if spills.contains_key(&reg) {
                    let val_reg = func.context.get_value(reg).unwrap().value().clone();
                    let spill_mem = spills.get(&reg).unwrap();
                    let temp = if temp_for_cur_inst.contains_key(&reg) {
                        temp_for_cur_inst.get(&reg).unwrap().clone()
                    } else {
                        let temp_ty = val_reg.ty.clone();
                        let temp =
                            func.new_ssa(MuEntityHeader::unnamed(vm.next_id()), temp_ty.clone())
                                .clone_value();
                        spilled_scratch_temps.insert(temp.id(), reg);
                        temp
                    };
                    trace!(
                        "reg {} defined in Inst{} is replaced as {}",
                        val_reg.id(),
                        i,
                        temp
                    );
                    let code = {
                        let mut codegen = ASMCodeGen::new();
                        codegen.start_code_sequence();
                        if RegGroup::get_from_ty(&temp.ty) == RegGroup::FPR {
                            codegen.emit_spill_store_fpr(spill_mem, &temp);
                        } else if RegGroup::get_from_ty(&temp.ty) == RegGroup::GPR {
                            codegen.emit_spill_store_gpr(spill_mem, &temp);
                        } else {
                            panic!("expected spilling a reg or freg, found {}", temp.ty);
                        }
                        codegen.finish_code_sequence_asm()
                    };
                    trace!("insert after inst #{}", i);
                    if spill_code_after.contains_key(&i) {
                        spill_code_after.get_mut(&i).unwrap().push(code);
                    } else {
                        spill_code_after.insert(i, vec![code]);
                    }
                    cf.mc_mut().replace_define_tmp_for_inst(reg, temp.id(), i);
                }
            }
        }
    }
    // copy and insert the code
    let new_mc = {
        let old_mc = cf.mc.take().unwrap();
        let old_mc_ref: &ASMCode = old_mc.as_any().downcast_ref().unwrap();
        old_mc_ref.rewrite_insert(spill_code_before, spill_code_after)
    };
    cf.mc = Some(new_mc);
    trace!("spill rewrite done");
    trace!("code after spilling");
    cf.mc().trace_mc();
    spilled_scratch_temps
}
pub fn spill_rewrite ( spills : & LinkedHashMap < MuID , P < Value > > , func : & mut MuFunctionVersion , cf : & mut CompiledFunction , vm : & VM ) -> LinkedHashMap < MuID , MuID > { trace ! ( " " ) ; trace ! ( " " ) ; cf . mc ( ) . trace_mc ( ) ; // if temp a gets spilled, all its uses and defines will become a use/def of a scratch temp // we maintain this mapping for later use let mut spilled_scratch_temps = LinkedHashMap :: new ( ) ; // record code and their insertion point, so we can do the copy/insertion all at once let mut spill_code_before : LinkedHashMap < usize , Vec < Box < ASMCode > > > = LinkedHashMap :: new ( ) ; let mut spill_code_after : LinkedHashMap < usize , Vec < Box < ASMCode > > > = LinkedHashMap :: new ( ) ; // map from old to new let mut temp_for_cur_inst : LinkedHashMap < MuID , P < Value > > = LinkedHashMap :: new ( ) ; // iterate through all instructions for i in 0 .. cf . mc ( ) . number_of_insts ( ) { temp_for_cur_inst . clear ( ) ; trace ! ( " " i ) ; // find use of any register that gets spilled { let reg_uses = cf . mc ( ) . get_inst_reg_uses ( i ) . to_vec ( ) ; for reg in reg_uses { if spills . contains_key ( & reg ) { let val_reg = func . context . get_value ( reg ) . unwrap ( ) . value ( ) . clone ( ) ; // a register used here is spilled let spill_mem = spills . get ( & reg ) . unwrap ( ) ; // generate a random new temporary let temp_ty = val_reg . ty . clone ( ) ; let temp = func . new_ssa ( MuEntityHeader :: unnamed ( vm . next_id ( ) ) , temp_ty . clone ( ) ) . clone_value ( ) ; // maintain mapping trace ! ( " " val_reg id ( ) i temp ) ; spilled_scratch_temps . insert ( temp . id ( ) , reg ) ; // generate a load let code = { let mut codegen = ASMCodeGen :: new ( ) ; codegen . start_code_sequence ( ) ; if RegGroup :: get_from_ty ( & temp_ty ) == RegGroup :: FPR { codegen . emit_spill_load_fpr ( & temp , spill_mem ) ; } else if RegGroup :: get_from_ty ( & temp_ty ) == RegGroup :: GPR { codegen . emit_spill_load_gpr ( & temp , spill_mem ) ; } else { panic ! ( " " temp_ty ) ; } codegen . finish_code_sequence_asm ( ) } ; // record that this load will be inserted at i trace ! ( " " i ) ; if spill_code_before . contains_key ( & i ) { spill_code_before . get_mut ( & i ) . unwrap ( ) . push ( code ) ; } else { spill_code_before . insert ( i , vec ! [ code ] ) ; } // replace register reg with temp cf . mc_mut ( ) . replace_use_tmp_for_inst ( reg , temp . id ( ) , i ) ; temp_for_cur_inst . insert ( reg , temp . clone ( ) ) ; } } } // find define of any register that gets spilled { let reg_defines = cf . mc ( ) . get_inst_reg_defines ( i ) . to_vec ( ) ; for reg in reg_defines { if spills . contains_key ( & reg ) { let val_reg = func . context . get_value ( reg ) . unwrap ( ) . value ( ) . clone ( ) ; let spill_mem = spills . get ( & reg ) . unwrap ( ) ; let temp = if temp_for_cur_inst . contains_key ( & reg ) { temp_for_cur_inst . get ( & reg ) . unwrap ( ) . clone ( ) } else { let temp_ty = val_reg . ty . clone ( ) ; let temp = func . new_ssa ( MuEntityHeader :: unnamed ( vm . next_id ( ) ) , temp_ty . clone ( ) ) . clone_value ( ) ; spilled_scratch_temps . insert ( temp . id ( ) , reg ) ; temp } ; trace ! ( " " val_reg id ( ) i temp ) ; let code = { let mut codegen = ASMCodeGen :: new ( ) ; codegen . start_code_sequence ( ) ; if RegGroup :: get_from_ty ( & temp . ty ) == RegGroup :: FPR { codegen . emit_spill_store_fpr ( spill_mem , & temp ) ; } else if RegGroup :: get_from_ty ( & temp . ty ) == RegGroup :: GPR { codegen . emit_spill_store_gpr ( spill_mem , & temp ) ; } else { panic ! ( " " temp ty ) ; } codegen . finish_code_sequence_asm ( ) } ; trace ! ( " " i ) ; if spill_code_after . contains_key ( & i ) { spill_code_after . get_mut ( & i ) . unwrap ( ) . push ( code ) ; } else { spill_code_after . insert ( i , vec ! [ code ] ) ; } cf . mc_mut ( ) . replace_define_tmp_for_inst ( reg , temp . id ( ) , i ) ; } } } } // copy and insert the code let new_mc = { let old_mc = cf . mc . take ( ) . unwrap ( ) ; let old_mc_ref : & ASMCode = old_mc . as_any ( ) . downcast_ref ( ) . unwrap ( ) ; old_mc_ref . rewrite_insert ( spill_code_before , spill_code_after ) } ; cf . mc = Some ( new_mc ) ; trace ! ( " " ) ; trace ! ( " " ) ; cf . mc ( ) . trace_mc ( ) ; spilled_scratch_temps }
rewrites the machine code of a function version for spilling.
rewrites the machine code of a function version for spilling .
spills
&LinkedHashMap<MuID, P<Value>>
func
&mut MuFunctionVersion
cf
&mut CompiledFunction
vm
&VM
spills
&LinkedHashMap<MuID, P<Value>>
func
&mut MuFunctionVersion
cf
&mut CompiledFunction
vm
&VM