# spill-instruction-generation-intel32-g.pkg
#
# Intel32 spilling is complicated business.
# Allen: and it just got more complicated; now we have to recognize the regmap.
# I've also improved the spilling code so that more instructions are
# recognized. Addressing modes are now folded into the existing instruction
# whenever possible. This eliminates some redundant temporaries which were
# introduced before.
# Compiled by:
#
src/lib/compiler/back/low/intel32/backend-intel32.lib### "No, no, you're not thinking;
### you're just being logical."
###
### -- Niels Bohr
# We are invoked from:
#
#
src/lib/compiler/back/low/intel32/regor/regor-intel32-g.pkgstipulate
package lem = lowhalf_error_message; # lowhalf_error_message is from
src/lib/compiler/back/low/control/lowhalf-error-message.pkg package rkj = registerkinds_junk; # registerkinds_junk is from
src/lib/compiler/back/low/code/registerkinds-junk.pkgherein
generic package spill_instruction_generation_intel32_g (
# ======================================
#
package mcf: Machcode_Intel32; # Machcode_Intel32 is from
src/lib/compiler/back/low/intel32/code/machcode-intel32.codemade.api package mu: Machcode_Universals # Machcode_Universals is from
src/lib/compiler/back/low/code/machcode-universals.api where
mcf == mcf; # "mcf" == "machcode_form" (abstract machine code).
)
: (weak) Architecture_Specific_Spill_Instructions # Architecture_Specific_Spill_Instructions is from
src/lib/compiler/back/low/regor/arch-spill-instruction.api {
# Export to client packages:
#
package mcf = mcf; # "mcf" == "machcode_form" (abstract machine code).
stipulate
package rgk = mcf::rgk; # "rgk" == "registerkinds".
herein
fun error msg
=
lem::impossible("INTEL32Spill: " + msg);
fun immed (mcf::IMMED _) => TRUE;
immed (mcf::IMMED_LABEL _) => TRUE;
#
immed _ => FALSE;
end;
fun immed_or_reg (mcf::DIRECT r) => TRUE;
immed_or_reg (mcf::IMMED _) => TRUE;
immed_or_reg (mcf::IMMED_LABEL _) => TRUE;
#
immed_or_reg _ => FALSE;
end;
fun is_memory (mcf::RAMREG _) => TRUE;
is_memory (mcf::DISPLACE _) => TRUE;
is_memory (mcf::INDEXED _) => TRUE;
is_memory (mcf::LABEL_EA _) => TRUE;
#
is_memory _ => FALSE;
end;
# Annotate instruction:
#
fun annotate (op, []) => op;
annotate (op, note ! notes) => annotate (mcf::NOTE { op, note }, notes);
end;
fun mark (instruction, an)
=
annotate (mcf::BASE_OP instruction, an);
fun live_dead (add, rmv) ( { regs, spilled }, reg)
=
{ regs => rmv (reg, regs),
spilled => add (reg, spilled)
};
f_live_dead = live_dead (rgk::add_codetemp_info_to_appropriate_kindlist, rgk::drop_codetemp_info_from_codetemplists);
r_live_dead = live_dead (rgk::add_codetemp_info_to_appropriate_kindlist, rgk::drop_codetemp_info_from_codetemplists);
make_int_codetemp_info = rgk::make_int_codetemp_info;
fun spill_r (instruction, reg, spill_loc)
=
{ fun intel32spill (instruction, an)
=
{
fun done (instruction, an)
=
{ code => [mark (instruction, an)], prohibitions => [], make_reg=>NULL };
case instruction
#
mcf::CALL { operand=>address, defs, uses, return, cuts_to, ramregion, pops }
=>
done (mcf::CALL { operand=>address, defs=>rgk::drop_codetemp_info_from_codetemplists (reg, defs),
return, uses,
cuts_to, ramregion, pops }, an);
mcf::MOVE { mv_op as (mcf::MOVZBL
|mcf::MOVSBL|mcf::MOVZWL|mcf::MOVSWL), src, dst }
=>
{ tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ prohibitions => [tmp_r], make_reg=>THE tmp_r,
code => [mark (mcf::MOVE { mv_op, src, dst=>tmp }, an),
mcf::move { mv_op=>mcf::MOVL, src=>tmp, dst=>spill_loc } ]
};
};
mcf::MOVE { mv_op, src as mcf::DIRECT rs, dst }
=>
if (rkj::codetemps_are_same_color (rs, reg) ) { code => [], prohibitions => [], make_reg=>NULL };
else done (mcf::MOVE { mv_op, src, dst=>spill_loc }, an);
fi;
mcf::MOVE { mv_op, src, dst=>mcf::DIRECT _}
=>
if (mu::eq_operand (src, spill_loc) )
{ code => [], prohibitions => [], make_reg=>NULL };
elif (immed src)
done (mcf::MOVE { mv_op, src, dst=>spill_loc }, an);
else
tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ prohibitions => [tmp_r],
make_reg=>THE tmp_r,
code => [ mark (mcf::MOVE { mv_op, src, dst=>tmp }, an),
mcf::move { mv_op, src=>tmp, dst=>spill_loc }
]
};
fi;
mcf::LEA { address, r32 }
=>
{ tmp_r = make_int_codetemp_info ();
{ prohibitions => [tmp_r],
make_reg=>THE tmp_r,
code => [mark (mcf::LEA { address, r32=>tmp_r }, an),
mcf::move { mv_op=>mcf::MOVL, src=>mcf::DIRECT tmp_r, dst=>spill_loc } ]
};
};
mcf::BINARY { bin_op=>mcf::XORL, src as mcf::DIRECT rs, dst=>mcf::DIRECT rd }
=>
if (rkj::codetemps_are_same_color (rs, rd) )
#
{ prohibitions => [],
code => [mark (mcf::MOVE { mv_op=>mcf::MOVL, src=>mcf::IMMED 0, dst=>spill_loc }, an)],
make_reg => NULL
};
else
{ prohibitions => [],
code => [mark (mcf::BINARY { bin_op=>mcf::XORL, src, dst=>spill_loc }, an)],
make_reg=>NULL
};
fi;
mcf::BINARY { bin_op, src, dst }
=>
{ # Note: dst = reg
fun mult_bin_op (mcf::MULL
|mcf::MULW|mcf::MULB|mcf::IMULL|mcf::IMULW|mcf::IMULB) => TRUE;
mult_bin_op _ => FALSE;
end;
if (mult_bin_op bin_op )
# Destination must remain a register
tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ prohibitions => [tmp_r],
code=> [mcf::move { mv_op=>mcf::MOVL, src=>spill_loc, dst=>tmp },
mcf::binary { bin_op, src, dst=>tmp },
mcf::move { mv_op=>mcf::MOVL, src=>tmp, dst=>spill_loc } ],
make_reg=>THE tmp_r
};
elif (immed_or_reg src )
# Can replace the destination directly
done (mcf::BINARY { bin_op, src, dst=>spill_loc }, an);
else
# A memory src and non mult_bin_op
# --- cannot have two memory operands
tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ prohibitions => [tmp_r],
code => [ mcf::move { mv_op=>mcf::MOVL, src, dst=>tmp },
mcf::binary { bin_op, src=>tmp, dst=>spill_loc } ],
make_reg=>NULL
};
fi;
};
mcf::SHIFT { shift_op, count, src, dst }
=>
error "go and implement SHIFT";
mcf::CMOV { cond, src, dst }
=>
# note: dst must be a register
case spill_loc
#
mcf::DIRECT r
=>
{ prohibitions => [],
make_reg=>NULL,
code => [mark (mcf::CMOV { cond, src, dst=>r }, an)]
};
_ =>
{ tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ prohibitions => [tmp_r],
make_reg=>THE tmp_r,
code => [mcf::move { mv_op=>mcf::MOVL, src=>spill_loc, dst=>tmp },
mark (mcf::CMOV { cond, src, dst=>tmp_r }, an),
mcf::move { mv_op=>mcf::MOVL, src=>tmp, dst=>spill_loc } ]
};
};
esac;
mcf::CMPXCHG { lock, size, src, dst }
=>
if (immed_or_reg src)
#
{ prohibitions => [],
code => [mark (mcf::CMPXCHG { lock, size, src, dst=>spill_loc }, an)],
make_reg=>NULL
};
else
tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ prohibitions => [],
code => [mcf::move { mv_op=>mcf::MOVL, src, dst=>tmp },
mark (mcf::CMPXCHG { lock, size, src=>tmp, dst=>spill_loc }, an)],
make_reg=>NULL
};
fi;
mcf::MULTDIV _ => error "spill: MULTDIV";
mcf::MUL3 { src1, src2, dst }
=>
{ tmp_r = make_int_codetemp_info ();
{ prohibitions => [tmp_r], make_reg=>THE tmp_r,
code => [mark (mcf::MUL3 { src1, src2, dst=>tmp_r }, an),
mcf::move { mv_op=>mcf::MOVL, src=>mcf::DIRECT tmp_r, dst=>spill_loc } ]
};
};
mcf::UNARY { un_op, operand } => done (mcf::UNARY { un_op, operand=>spill_loc }, an);
mcf::SET { cond, operand } => done (mcf::SET { cond, operand=>spill_loc }, an);
mcf::POP _ => done (mcf::POP spill_loc, an);
mcf::FNSTSW => error "spill: FNSTSW";
_ => error "spill";
esac;
}; # fun intel32spill
fun f (mcf::BASE_OP instruction, an)
=>
intel32spill (instruction, an);
f (mcf::NOTE { note, op }, notes)
=>
f (op, note ! notes);
f (mcf::DEAD lk, an)
=>
{ code => [annotate (mcf::DEAD (r_live_dead (lk, reg)), an)],
prohibitions => [],
make_reg=>NULL
};
f _ => error "spill: f";
end;
f (instruction, []);
};
fun reload_r (instruction, reg, spill_loc)
=
{
fun reload_intel32 (instruction, reg, spill_loc, an)
=
{
fun do_operand (rt, operand)
=
case operand
#
mcf::DIRECT r
=>
if (rkj::codetemps_are_same_color (r, reg)) mcf::DIRECT rt;
else operand;
fi;
mcf::DISPLACE { base, disp, ramregion }
=>
if (rkj::codetemps_are_same_color (base, reg)) mcf::DISPLACE { base=>rt, disp, ramregion };
else operand;
fi;
mcf::INDEXED { base=>NULL, index, scale, disp, ramregion }
=>
if (rkj::codetemps_are_same_color (index, reg)) mcf::INDEXED { base=>NULL, index=>rt, scale, disp, ramregion };
else operand;
fi;
mcf::INDEXED { base as THE b, index, scale, disp, ramregion }
=>
if (rkj::codetemps_are_same_color (b, reg)) do_operand (rt, mcf::INDEXED { base=>THE rt, index, scale, disp, ramregion } );
elif (rkj::codetemps_are_same_color (index, reg)) mcf::INDEXED { base, index=>rt, scale, disp, ramregion };
else operand;
fi;
operand => operand;
esac;
fun done (instruction, an)
=
{ code => [mark (instruction, an)],
prohibitions => [],
make_reg=>NULL
};
fun is_reloading (mcf::DIRECT r) => rkj::codetemps_are_same_color (r, reg);
is_reloading _ => FALSE;
end;
# This version assumes that the value of tmpR is killed
#
fun with_tmp (f, an)
=
case spill_loc
#
mcf::DIRECT tmp_r
=>
{ make_reg=>NULL,
prohibitions => [],
code => [mark (f tmp_r, an)]
};
_ =>
{ tmp_r = make_int_codetemp_info ();
{ make_reg=>NULL,
prohibitions => [tmp_r],
code => [ mcf::move { mv_op=>mcf::MOVL, src=>spill_loc, dst=>mcf::DIRECT tmp_r },
mark (f tmp_r, an)
]
};
};
esac;
# This version assumes that the
# value of tmp_r is available afterwards
#
fun with_tmp_avail (f, an)
=
case spill_loc
#
mcf::DIRECT tmp_r
=>
{ make_reg => THE tmp_r,
prohibitions => [tmp_r],
code => [mark (f tmp_r, an)]
};
_ =>
{ tmp_r = make_int_codetemp_info ();
tmp = mcf::DIRECT tmp_r;
{ make_reg=>THE tmp_r,
prohibitions => [tmp_r],
code => [mcf::move { mv_op=>mcf::MOVL, src=>spill_loc, dst=>mcf::DIRECT tmp_r },
mark (f tmp_r, an)
]
};
};
esac;
fun replace (opn as mcf::DIRECT r)
=>
if (rkj::codetemps_are_same_color (r, reg)) spill_loc;
else opn;
fi;
replace opn
=>
opn;
end;
# Fold in a memory operand if possible.
# Make sure that both operands are
# not in memory. lsrc cannot be immediate.
#
fun reload_cmp (cmp, lsrc, rsrc, an)
=
{ fun reload_it ()
=
with_tmp ( \\ tmp_r = cmp { lsrc=>do_operand (tmp_r, lsrc), rsrc=>do_operand (tmp_r, rsrc) },
an
);
if (immed_or_reg lsrc and immed_or_reg rsrc )
lsrc' = replace lsrc;
rsrc' = replace rsrc;
if (is_memory lsrc' and is_memory rsrc') reload_it ();
else done (cmp { lsrc=>lsrc', rsrc=>rsrc'}, an);
fi;
else
reload_it();
fi;
};
fun reload_bt (bit_op, lsrc, rsrc, an)
=
reload_cmp
( \\ { lsrc, rsrc } = mcf::BITOP { bit_op, lsrc, rsrc },
lsrc,
rsrc,
an
);
# Fold in a memory operand if possible. Makes sure that the right
# operand is not in memory and left operand is not an immediate.
# lsrc rsrc
# AL, imm8 opc1 A8
# EAX, imm32 opc1 A9
# r/m8, imm8 opc2 F6/0 ib
# r/m32, imm32 opc2 F7/0 id
# r/m32, r32 opc3 85/r
#
fun reload_test (test, lsrc, rsrc, an)
=
{ fun reload_it ()
=
with_tmp ( \\ tmp_r = test { lsrc=>do_operand (tmp_r, lsrc), rsrc=>do_operand (tmp_r, rsrc) },
an
);
if (immed_or_reg lsrc and immed_or_reg rsrc)
lsrc = replace lsrc;
rsrc = replace rsrc;
if (is_memory rsrc)
if (is_memory lsrc)
reload_it();
else
# It is commutative:
done (test { lsrc=>rsrc, rsrc=>lsrc }, an);
fi;
else
done (test { lsrc, rsrc }, an);
fi;
else
reload_it ();
fi;
};
fun reload_push (push, arg as mcf::DIRECT _, an)
=>
done (push (replace arg), an);
reload_push (push, arg, an)
=>
with_tmp_avail (\\ tmp_r = push (do_operand (tmp_r, arg)), an);
end;
fun reload_real (real_op, operand, an)
=
with_tmp_avail (\\ tmp_r = real_op (do_operand (tmp_r, operand)), an);
case instruction
#
mcf::JMP (mcf::DIRECT _, labs) => done (mcf::JMP (spill_loc, labs), an);
mcf::JMP (operand, labs) => with_tmp (\\ t => mcf::JMP (do_operand (t, operand), labs); end, an);
mcf::JCC { operand=>mcf::DIRECT _, cond } => done (mcf::JCC { operand=>spill_loc, cond }, an);
mcf::JCC { operand, cond }
=>
with_tmp (\\ t => mcf::JCC { operand=>do_operand (t, operand), cond }; end, an);
mcf::CALL { operand, defs, uses, return, cuts_to, ramregion, pops }
=>
with_tmp
( \\ t = mcf::CALL { operand=>do_operand (t, operand), defs, return, pops,
uses=>rgk::drop_codetemp_info_from_codetemplists (reg, uses), cuts_to, ramregion
},
an
);
mcf::MOVE { mv_op, src as mcf::DIRECT _, dst as mcf::DIRECT _}
=>
done (mcf::MOVE { mv_op, src=>replace src, dst }, an);
mcf::MOVE { mv_op, src, dst as mcf::DIRECT _}
=>
with_tmp_avail (\\ t =>mcf::MOVE { mv_op, src=>do_operand (t, src), dst }; end, an);
mcf::MOVE { mv_op, src as mcf::DIRECT _, dst }
=>
if (mu::eq_operand (dst, spill_loc))
{ code => [], prohibitions => [], make_reg=>NULL };
else
# Dst is not the spill reg
with_tmp_avail
(\\ t = mcf::MOVE { mv_op, src=>do_operand (t, src), dst=>do_operand (t, dst) }, an);
fi;
mcf::MOVE { mv_op, src, dst }
=>
with_tmp_avail # Dst is not the spill reg
(\\ t = mcf::MOVE { mv_op, src=>do_operand (t, src), dst=>do_operand (t, dst) }, an);
mcf::LEA { r32, address }
=>
with_tmp_avail (\\ tmp_r = mcf::LEA { r32, address=>do_operand (tmp_r, address) }, an);
mcf::CMPL { lsrc, rsrc } => reload_cmp (mcf::CMPL, lsrc, rsrc, an);
mcf::CMPW { lsrc, rsrc } => reload_cmp (mcf::CMPW, lsrc, rsrc, an);
mcf::CMPB { lsrc, rsrc } => reload_cmp (mcf::CMPB, lsrc, rsrc, an);
mcf::TESTL { lsrc, rsrc } => reload_test (mcf::TESTL, lsrc, rsrc, an);
mcf::TESTW { lsrc, rsrc } => reload_test (mcf::TESTW, lsrc, rsrc, an);
mcf::TESTB { lsrc, rsrc } => reload_test (mcf::TESTB, lsrc, rsrc, an);
mcf::BITOP { bit_op, lsrc, rsrc } => reload_bt (bit_op, lsrc, rsrc, an);
mcf::BINARY { bin_op, src, dst as mcf::DIRECT _}
=>
case src
#
mcf::DIRECT _
=>
done (mcf::BINARY { bin_op, src=>replace src, dst }, an);
_ =>
with_tmp
(\\ tmp_r = mcf::BINARY { bin_op, src=>do_operand (tmp_r, src), dst }, an);
esac;
mcf::BINARY { bin_op, src, dst }
=>
with_tmp
(\\ tmp_r = mcf::BINARY { bin_op, src=>do_operand (tmp_r, src), dst=>do_operand (tmp_r, dst) }, an);
mcf::CMOV { cond, src, dst }
=>
if (rkj::codetemps_are_same_color (dst, reg)) error "CMOV";
else done (mcf::CMOV { cond, src=>spill_loc, dst }, an);
fi;
mcf::SHIFT { shift_op, count, src, dst }
=>
error "go and implement SHIFT";
mcf::CMPXCHG { lock, size, src, dst }
=>
with_tmp (\\ tmp_r = mcf::CMPXCHG { lock, size,
src=>do_operand (tmp_r, src),
dst=>do_operand (tmp_r, dst) }, an);
mcf::MULTDIV { mult_div_op, src as mcf::DIRECT _}
=>
done (mcf::MULTDIV { mult_div_op, src=>replace src }, an);
mcf::MULTDIV { mult_div_op, src }
=>
with_tmp (\\ tmp_r =
mcf::MULTDIV { mult_div_op, src=>do_operand (tmp_r, src) }, an);
mcf::MUL3 { src1, src2, dst }
=>
with_tmp ( \\ tmp_r = mcf::MUL3 { src1 => do_operand (tmp_r, src1), src2,
dst => if (rkj::codetemps_are_same_color (dst, reg) )
error "reload: MUL3";
else dst;fi
},
an
);
mcf::UNARY { un_op, operand }
=>
with_tmp_avail
(\\ tmp_r = mcf::UNARY { un_op, operand=>do_operand (tmp_r, operand) }, an);
mcf::SET { cond, operand }
=>
with_tmp_avail (\\ tmp_r = mcf::SET { cond, operand=>do_operand (tmp_r, operand) }, an);
mcf::PUSHL arg => reload_push (mcf::PUSHL, arg, an);
mcf::PUSHW arg => reload_push (mcf::PUSHW, arg, an);
mcf::PUSHB arg => reload_push (mcf::PUSHB, arg, an);
mcf::FILD operand => reload_real (mcf::FILD, operand, an);
mcf::FILDL operand => reload_real (mcf::FILDL, operand, an);
mcf::FILDLL operand => reload_real (mcf::FILDLL, operand, an);
mcf::FLDT operand => reload_real (mcf::FLDT, operand, an);
mcf::FLDL operand => reload_real (mcf::FLDL, operand, an);
mcf::FLDS operand => reload_real (mcf::FLDS, operand, an);
mcf::FSTPT operand => reload_real (mcf::FSTPT, operand, an);
mcf::FSTPL operand => reload_real (mcf::FSTPL, operand, an);
mcf::FSTPS operand => reload_real (mcf::FSTPS, operand, an);
mcf::FSTL operand => reload_real (mcf::FSTL, operand, an);
mcf::FSTS operand => reload_real (mcf::FSTS, operand, an);
mcf::FUCOM operand => reload_real (mcf::FUCOM, operand, an);
mcf::FUCOMP operand => reload_real (mcf::FUCOMP, operand, an);
mcf::FCOMI operand => reload_real (mcf::FCOMI, operand, an);
mcf::FCOMIP operand => reload_real (mcf::FCOMIP, operand, an);
mcf::FUCOMI operand => reload_real (mcf::FUCOMI, operand, an);
mcf::FUCOMIP operand => reload_real (mcf::FUCOMIP, operand, an);
mcf::FENV { fenv_op, operand }
=>
reload_real (\\ operand = mcf::FENV { fenv_op, operand }, operand, an);
mcf::FBINARY { bin_op, src, dst }
=>
with_tmp_avail (\\ tmp_r = mcf::FBINARY { bin_op, src=>do_operand (tmp_r, src), dst }, an);
mcf::FIBINARY { bin_op, src }
=>
with_tmp_avail (\\ tmp_r = mcf::FIBINARY { bin_op, src=>do_operand (tmp_r, src) }, an);
# Pseudo fp instrctions
mcf::FMOVE { fsize, src, dst }
=>
with_tmp_avail (\\ tmp_r = mcf::FMOVE { fsize, src=>do_operand (tmp_r, src),
dst=>do_operand (tmp_r, dst) }, an);
mcf::FILOAD { isize, ea, dst }
=>
with_tmp_avail (\\ tmp_r = mcf::FILOAD { isize, ea=>do_operand (tmp_r, ea),
dst=>do_operand (tmp_r, dst) }, an);
mcf::FBINOP { fsize, bin_op, lsrc, rsrc, dst }
=>
with_tmp_avail (\\ tmp_r = mcf::FBINOP { fsize, bin_op, lsrc=>do_operand (tmp_r, lsrc),
rsrc=>do_operand (tmp_r, rsrc), dst=>do_operand (tmp_r, dst) }, an);
mcf::FIBINOP { isize, bin_op, lsrc, rsrc, dst }
=>
with_tmp_avail (\\ tmp_r = mcf::FIBINOP { isize, bin_op, lsrc=>do_operand (tmp_r, lsrc),
rsrc=>do_operand (tmp_r, rsrc), dst=>do_operand (tmp_r, dst) }, an);
mcf::FUNOP { fsize, un_op, src, dst }
=>
with_tmp_avail (\\ tmp_r = mcf::FUNOP { fsize, un_op, src=>do_operand (tmp_r, src),
dst=>do_operand (tmp_r, dst) }, an);
mcf::FCMP { i, fsize, lsrc, rsrc }
=>
with_tmp_avail (\\ tmp_r = mcf::FCMP { i, fsize,
lsrc=>do_operand (tmp_r, lsrc), rsrc=>do_operand (tmp_r, rsrc)
}, an);
_ => error "reload";
esac;
}; # fun reload_intel32
fun f (mcf::NOTE { note, op }, notes)
=>
f (op, note ! notes);
f (mcf::BASE_OP i, an)
=>
reload_intel32 (i, reg, spill_loc, an);
f (mcf::LIVE lk, an)
=>
{ code => [annotate (mcf::LIVE (r_live_dead (lk, reg)), an)],
prohibitions => [],
make_reg=>NULL
};
f _ => error "reload: f";
end;
f (instruction, []);
}; # fun reload
fun spill_f (instruction, reg, spill_loc)
=
{
fun intel32fspill (instruction, reg, spill_loc, an)
=
{
fun with_tmp (f, fsize, an)
=
{ tmp_r = rgk::make_float_codetemp_info ();
tmp = mcf::FPR tmp_r;
{ prohibitions => [tmp_r],
code => [mark (f tmp, an),
mcf::fmove { fsize, src=>tmp, dst=>spill_loc } ],
make_reg=>THE tmp_r # XXX Should we propagate the definition?
};
};
case instruction
mcf::FSTPL _ => { prohibitions => [], code => [mark (mcf::FSTPL spill_loc, an)], make_reg=>NULL };
mcf::FSTPS _ => { prohibitions => [], code => [mark (mcf::FSTPS spill_loc, an)], make_reg=>NULL };
mcf::FSTPT _ => { prohibitions => [], code => [mark (mcf::FSTPT spill_loc, an)], make_reg=>NULL };
mcf::FSTL _ => { prohibitions => [], code => [mark (mcf::FSTL spill_loc, an)], make_reg=>NULL };
mcf::FSTS _ => { prohibitions => [], code => [mark (mcf::FSTS spill_loc, an)], make_reg=>NULL };
mcf::CALL { operand, defs, uses, return, cuts_to, ramregion, pops }
=>
{ prohibitions => [],
code => [mark (mcf::CALL { operand, defs=>rgk::drop_codetemp_info_from_codetemplists (reg, defs),
return, uses,
cuts_to, ramregion, pops }, an)],
make_reg=>NULL
};
# Pseudo fp instrctions
mcf::FMOVE { fsize, src, dst }
=>
if (mu::eq_operand (src, spill_loc) )
#
{ prohibitions => [], code => [], make_reg=>NULL };
else
{ prohibitions => [], code => [mark (mcf::FMOVE { fsize, src, dst=>spill_loc }, an)],
make_reg=>NULL };
fi;
mcf::FILOAD { isize, ea, dst }
=>
{ prohibitions => [], code => [mark (mcf::FILOAD { isize, ea, dst=>spill_loc }, an)],
make_reg=>NULL }; # XXX bad for single precision
mcf::FBINOP { fsize as mcf::FP64, bin_op, lsrc, rsrc, dst }
=>
{ prohibitions => [], code => [mark (mcf::FBINOP { fsize, bin_op,
lsrc, rsrc,
dst=>spill_loc }, an)],
make_reg=>NULL };
mcf::FBINOP { fsize, bin_op, lsrc, rsrc, dst }
=>
with_tmp (\\ tmp_r =
mcf::FBINOP { fsize, bin_op,
lsrc, rsrc, dst=>tmp_r },
fsize, an);
mcf::FIBINOP { isize, bin_op, lsrc, rsrc, dst }
=>
with_tmp (\\ tmp_r =
mcf::FIBINOP { isize, bin_op,
lsrc, rsrc, dst=>tmp_r },
mcf::FP64, an); # XXX
mcf::FUNOP { fsize, un_op, src, dst }
=>
{ prohibitions => [], code => [mark (mcf::FUNOP { fsize, un_op,
src, dst=>spill_loc }, an)],
make_reg=>NULL };
_ => error "fspill";
esac;
}; # fun intel32fspill
fun f (mcf::NOTE { note, op }, notes)
=>
f (op, note ! notes);
f (mcf::BASE_OP (i), an)
=>
intel32fspill (i, reg, spill_loc, an);
f (mcf::DEAD lk, an)
=>
{ code => [annotate (mcf::DEAD (f_live_dead (lk, reg)), an)],
prohibitions => [],
make_reg=>NULL
};
f _ =>
error "fspill: f";
end;
f (instruction, []);
};
fun reload_f (instruction, reg, spill_loc)
=
f (instruction, [])
where
fun intel32freload (instruction, reg, spill_loc, an)
=
{ fun rename (src as mcf::FDIRECT f)
=>
if (rkj::codetemps_are_same_color (f, reg)) spill_loc;
else src;
fi;
rename (src as mcf::FPR f)
=>
if (rkj::codetemps_are_same_color (f, reg)) spill_loc;
else src;
fi;
rename src
=>
src;
end;
fun with_tmp (fsize, f, an)
=
case spill_loc
#
mcf::FDIRECT _ => { make_reg=>NULL, prohibitions => [], code => [mark (f spill_loc, an)] };
mcf::FPR _ => { make_reg=>NULL, prohibitions => [], code => [mark (f spill_loc, an)] };
_ =>
{ ftmp_r = rgk::make_float_codetemp_info ();
#
ftmp = mcf::FPR (ftmp_r);
{ make_reg=>NULL,
prohibitions => [ftmp_r],
code => [ mcf::fmove { fsize, src=>spill_loc, dst=>ftmp },
mark (f ftmp, an)
]
};
};
esac;
case instruction
#
mcf::FLDT operand => { code => [mark (mcf::FLDT spill_loc, an)], prohibitions => [], make_reg=>NULL };
mcf::FLDL operand => { code => [mark (mcf::FLDL spill_loc, an)], prohibitions => [], make_reg=>NULL };
mcf::FLDS operand => { code => [mark (mcf::FLDS spill_loc, an)], prohibitions => [], make_reg=>NULL };
#
mcf::FUCOM operand => { code => [mark (mcf::FUCOM spill_loc, an)], prohibitions => [], make_reg=>NULL };
mcf::FUCOMP operand => { code => [mark (mcf::FUCOMP spill_loc, an)], prohibitions => [], make_reg=>NULL };
#
mcf::FCOMI operand => { code => [mark (mcf::FCOMI spill_loc, an)], prohibitions => [], make_reg=>NULL };
mcf::FCOMIP operand => { code => [mark (mcf::FCOMIP spill_loc, an)], prohibitions => [], make_reg=>NULL };
#
mcf::FUCOMI operand => { code => [mark (mcf::FUCOMI spill_loc, an)], prohibitions => [], make_reg=>NULL };
mcf::FUCOMIP operand => { code => [mark (mcf::FUCOMIP spill_loc, an)], prohibitions => [], make_reg=>NULL };
mcf::FBINARY { bin_op, src=>mcf::FDIRECT f, dst }
=>
if (rkj::codetemps_are_same_color (f, reg))
#
{ code => [mark (mcf::FBINARY { bin_op, src=>spill_loc, dst }, an)],
prohibitions => [],
make_reg => NULL
};
else
error "reloadF: FBINARY";
fi;
# Pseudo fp instructions.
mcf::FMOVE { fsize, src, dst }
=>
if (mu::eq_operand (dst, spill_loc)) { code => [], prohibitions => [], make_reg=>NULL };
else { code => [mark (mcf::FMOVE { fsize, src=>spill_loc, dst }, an)], prohibitions => [], make_reg=>NULL };
fi;
mcf::FBINOP { fsize, bin_op, lsrc, rsrc, dst }
=>
{ code => [mark (mcf::FBINOP { fsize, bin_op, lsrc=>rename lsrc, rsrc=>rename rsrc, dst }, an)],
prohibitions => [],
make_reg=>NULL
};
mcf::FIBINOP { isize, bin_op, lsrc, rsrc, dst }
=>
{ code => [mark (mcf::FIBINOP { isize, bin_op, lsrc=>rename lsrc, rsrc=>rename rsrc, dst }, an)],
prohibitions => [],
make_reg=>NULL
};
mcf::FUNOP { fsize, un_op, src, dst }
=>
{ code => [mark (mcf::FUNOP { fsize, un_op,
src=>rename src, dst }, an)],
prohibitions => [],
make_reg=>NULL
};
mcf::FCMP { i, fsize, lsrc, rsrc }
=>
# Make sure that the lsrc and
# rsrc cannot both be in memory:
#
case (lsrc, rsrc)
#
(mcf::FPR fs1, mcf::FPR fs2)
=>
case ( rkj::codetemps_are_same_color (fs1, reg),
rkj::codetemps_are_same_color (fs2, reg)
)
#
(TRUE, TRUE)
=>
with_tmp (fsize,
\\ tmp = mcf::FCMP { i, fsize, lsrc=>tmp, rsrc=>tmp }, an);
(TRUE, FALSE)
=>
{ code => [mark (mcf::FCMP { i, fsize, lsrc=>spill_loc, rsrc }, an)],
prohibitions => [], make_reg=>NULL };
(FALSE, TRUE)
=>
{ code => [mark (mcf::FCMP { i, fsize, lsrc, rsrc=>spill_loc }, an)],
prohibitions => [], make_reg=>NULL };
_ => error "fcmp.1";
esac;
(mcf::FPR _, _)
=>
with_tmp (fsize,
\\ tmp = mcf::FCMP { i, fsize, lsrc=>tmp, rsrc }, an);
(_, mcf::FPR _)
=>
with_tmp ( fsize,
\\ tmp = mcf::FCMP { i, fsize, lsrc, rsrc=>tmp }, an);
_ => error "fcmp.2";
esac;
mcf::CALL { operand, defs, uses, return, cuts_to, ramregion, pops }
=>
{ prohibitions => [],
code => [mark (mcf::CALL { operand, defs=>rgk::drop_codetemp_info_from_codetemplists (reg, defs),
return, pops,
uses, cuts_to, ramregion }, an)],
make_reg=>NULL
};
_ => error "reloadF";
esac;
}; # fun intel32freload
fun f (mcf::NOTE { note, op }, notes)
=>
f (op, note ! notes);
f (mcf::BASE_OP i, an)
=>
intel32freload (i, reg, spill_loc, an);
f (mcf::LIVE lk, an)
=>
{ code => [annotate (mcf::LIVE (f_live_dead (lk, reg)), an)],
prohibitions => [],
make_reg=>NULL
};
f _ => error "freload::f";
end;
end;
fun spill_to_ea rkj::INT_REGISTER (reg, ea)
=>
{ fun return_move ()
=
{ code => [mcf::move { mv_op=>mcf::MOVL, src=>mcf::DIRECT reg, dst=>ea } ],
prohibitions => [], make_reg=>NULL
};
case ea
#
mcf::RAMREG _ => return_move ();
mcf::DISPLACE _ => return_move ();
mcf::INDEXED _ => return_move ();
_ => error "spillToEA: GP";
esac;
};
spill_to_ea rkj::FLOAT_REGISTER (freg, ea) => error "spillToEA: FP";
spill_to_ea _ _ => error "spillToEA";
end;
fun reload_from_ea rkj::INT_REGISTER (reg, ea)
=>
case ea
#
mcf::RAMREG _ => return_move ();
mcf::DISPLACE _ => return_move ();
mcf::INDEXED _ => return_move ();
#
_ => error "reloadFromEA: GP";
esac
where
fun return_move ()
=
{ code => [mcf::move { mv_op=>mcf::MOVL, dst=>mcf::DIRECT reg, src=>ea } ],
prohibitions => [],
make_reg=>NULL
};
end;
reload_from_ea rkj::FLOAT_REGISTER (freg, ea) => error "spillToEA: FP";
reload_from_ea _ _ => error "spillToEA";
end;
fun reload rkj::INT_REGISTER => reload_r;
reload rkj::FLOAT_REGISTER => reload_f;
reload _ => error "reload";
end;
fun spill rkj::INT_REGISTER => spill_r;
spill rkj::FLOAT_REGISTER => spill_f;
spill _ => error "spill";
end;
end;
};
end;