Module Tailrec
Require Import Coqlib Wfsimpl Maps Errors Integers Values.
Require Import AST Linking Globalenvs.
Require Import Op Registers RTL.
Fixpoint copy_to_temps srcregs tmpreg pc (
prec_code :
code) : (
node *
code) :=
match srcregs with
|
nil => (
pc,
prec_code)
|
h::
t =>
copy_to_temps t (
Pos.succ tmpreg) (
Pos.succ pc)
(
PTree.set pc (
Iop Omove (
h::
nil)
tmpreg (
Pos.succ pc))
prec_code)
end.
Fixpoint copy_from_temps dstregs tmpreg pc (
prec_code :
code) : (
node *
code):=
match dstregs with
|
nil => (
pc,
prec_code)
|
h::
t =>
copy_from_temps t (
Pos.succ tmpreg) (
Pos.succ pc)
(
PTree.set pc (
Iop Omove (
tmpreg::
nil)
h (
Pos.succ pc))
prec_code)
end.
Definition build_jump start tmpreg srcregs dstregs pc0
(
code0 :
code): (
node *
code) :=
let (
pc1,
code1) :=
copy_to_temps (
List.rev srcregs)
tmpreg pc0 code0 in
let (
pc2,
code2) :=
copy_from_temps (
List.rev dstregs)
tmpreg pc1 code1 in
((
Pos.succ pc2), (
PTree.set pc2 (
Inop start)
code2)).
Definition process_instr id start params tmpreg new_pc new_code pc instr :=
match instr with
|
Itailcall sig (
inr id')
srcregs =>
if (
QualIdent.eq id id') &&
(
Nat.eq_dec (
List.length srcregs) (
List.length params))
then build_jump start tmpreg srcregs params new_pc
(
PTree.set pc (
Inop new_pc)
new_code)
else (
new_pc,
new_code)
| _ => (
new_pc,
new_code)
end.
Definition successors_inside f :=
let limit :=
max_pc_function f in
List.forallb (
fun (
pc_instr :
node*
instruction) =>
let (
pc,
instr) :=
pc_instr in
List.forallb (
fun x =>
Pos.leb x limit)
(
successors_instr instr))
(
PTree.elements (
fn_code f)).
Definition transf_function' (
id:
qualident) (
f:
function) :=
(
let start :=
fn_entrypoint f in
let tmpreg :=
Pos.succ (
RTL.max_reg_function f)
in
let params :=
fn_params f in
let code' :=
snd
(
PTree.fold
(
fun (
new_pc_code :
node *
code) (
pc :
node)
instr =>
let (
new_pc,
new_code) :=
new_pc_code in
process_instr id start params tmpreg new_pc new_code pc instr)
(
fn_code f)
((
Pos.succ (
RTL.max_pc_function f)), (
fn_code f)))
in
OK (
mkfunction f.(
fn_sig)
params
f.(
fn_stacksize)
code'
start)).
Definition transf_function (
ge:
Genv.t fundef unit) (
id :
qualident) (
f :
function) :=
if option_eq_dec eq_fundef (
find_function ge (
inr id) (
Regmap.init Vundef)) (
Some (
Internal f))
then
if successors_inside f
then transf_function' id f
else Error (
msg "Tailrec: successor points outside")
else Error (
msg "Tailrec: functions don't match; report and pass -fno-tailrec until fixed").
Definition transf_fundef (
ge:
Genv.t fundef unit) (
id:
qualident) (
fd:
fundef) :
Errors.res fundef :=
AST.transf_partial_fundef (
transf_function ge id)
fd.
Definition transf_program (
p:
program):
Errors.res program :=
AST.transform_partial_program2 (
transf_fundef (
Genv.globalenv p)) (
fun i v =>
OK v)
p.