Require Import Coqlib.
Require Import Maps.
Require Import Ast.
Require Import Integers.
Require Import Pointers.
Require Import Floats.
Require Import Values.
Require Import Mem.
Require Import Globalenvs.
Require Import Op.
Require Import Registers.
Require Import RTL.
Require Import Kildall.
Require Import Lattice.
We perform PRE specialised for fenceelim2
Analysis A
TOP (true) means that along SOME path after the current program
point there is an atomic instruction with no intervening reads
Definition transfer_A (
f:
function) (
pc:
node) (
after:
LBoolean.t) :=
match f.(
fn_code)!
pc with
|
None =>
after
|
Some i =>
match i with
|
Inop s =>
after
|
Iop op args res s =>
after
|
Iload chunk addr args dst s =>
LBoolean.bot
|
Istore chunk addr args src s =>
after
|
Icall sig ros args res s =>
LBoolean.bot
|
Icond cond args ifso ifnot =>
after
|
Ireturn optarg =>
LBoolean.bot
|
Ithreadcreate _ _ _ =>
LBoolean.bot
|
Iatomic _ _ _ _ =>
LBoolean.top
|
Ifence _ =>
LBoolean.top
end
end.
Module DA :=
LBoolean.
Module DSA :=
Backward_Dataflow_Solver(
DA)(
NodeSetBackward).
Definition analyze_A (
f:
RTL.function):
PMap.t DA.t :=
match DSA.fixpoint (
successors f) (
transfer_A f)
((
f.(
fn_entrypoint),
DA.bot) ::
nil)
with
|
None =>
PMap.init DA.bot
|
Some res =>
res
end.
Analysis B
bot (false) means that along _all_ paths to the current program
point there is a fence with no later reads or atomic instructions.
Definition transfer_B (
f:
function) (
pc:
node) (
before:
LBoolean.t) :=
match f.(
fn_code)!
pc with
|
None =>
before
|
Some i =>
match i with
|
Inop s =>
before
|
Iop op args res s =>
before
|
Iload chunk addr args dst s =>
LBoolean.top
|
Istore chunk addr args src s =>
before
|
Icall sig ros args res s =>
LBoolean.top
|
Icond cond args ifso ifnot =>
before
|
Ireturn optarg =>
LBoolean.top
|
Ithreadcreate _ _ _ =>
LBoolean.top
|
Iatomic _ _ _ _ =>
LBoolean.top
|
Ifence _ =>
LBoolean.bot
end
end.
Module DB :=
LBoolean.
Module DSB :=
Dataflow_Solver(
DB)(
NodeSetForward).
Definition analyze_B (
f:
RTL.function):
PMap.t DB.t :=
match DSB.fixpoint (
successors f) (
transfer_B f)
((
f.(
fn_entrypoint),
DB.top) ::
nil)
with
|
None =>
PMap.init DB.top
|
Some res =>
res
end.
Code transformation
Fixpoint in_inops pc inops :=
match inops with
| (
i1,
i2)::
l =>
if peq pc i1 then Some i2
else if peq pc i2 then Some i1
else in_inops pc l
|
nil =>
None
end.
Definition transf_instr (
appsA:
PMap.t DA.t) (
appsB:
PMap.t DB.t)
inops pc (
instr:
instruction) :=
match instr with
|
Inop s =>
match in_inops pc inops with
|
None =>
Inop s
|
Some pcb =>
match appsA!!
pc,
appsB!!
pc,
appsA!!
pcb with
|
false,
false,
true =>
Ifence s
|
_,
_,
_ =>
Inop s
end
end
|
_ =>
instr
end.
Definition transf_code (
appsA:
PMap.t DA.t) (
appsB:
PMap.t DB.t)
inops instrs :
code :=
PTree.map (
fun pc instr =>
transf_instr appsA appsB inops pc instr)
instrs.
Fixpoint my_option_map A B (
f:
A ->
option B)
l :=
match l with
|
nil =>
nil
|
a::
l =>
match f a with
|
Some e =>
e ::
my_option_map A B f l
|
None =>
my_option_map A B f l
end
end.
Implicit Arguments my_option_map [
A B].
Definition transf_function (
f:
function) :
function :=
let appsA :=
analyze_A f in
let appsB :=
analyze_B f in
let inops :=
my_option_map (
fun x =>
match snd x with
|
Icond _ _ ifso ifnot =>
Some (
ifso,
ifnot)
|
_ =>
None
end )
(
PTree.elements f.(
fn_code))
in
mkfunction
f.(
fn_sig)
f.(
fn_params)
f.(
fn_stacksize)
(
transf_code appsA appsB inops f.(
fn_code))
f.(
fn_entrypoint).
Definition transf_fundef (
fd:
fundef) :
fundef :=
Ast.transf_fundef transf_function fd.
Definition transf_program (
p:
program) :
program :=
transform_program transf_fundef p.