Library liblayers.compat.CompatExternalCalls

Require Import compcert.lib.Coqlib.
Require Import compcert.common.Errors.
Require Import compcert.common.AST.
Require Import compcert.common.Events.
Require Import liblayers.lib.Decision.
Require Import liblayers.compat.CompatLayers.
Require Import compcertx.driver.CompCertBuiltins.

Section WITH_MEMORY_MODEL.
Context `{Hstencil: Stencil}.
Context `{Hmem: Mem.MemoryModel}.
Context `{Hmwd: UseMemWithData mem}.

We cannot use Inductive here, because Events.extcall_sem introduces dependency on the type of ge, which cannot be inverted properly.

Definition compatsem_extcall {D: compatdata}:
  compatsem DsignatureEvents.extcall_sem (mem := mwd D) :=
  fun f sg WB F V ge vargs m t vres
     s (σ: sextcall_primsem D),
      stencil_matches s ge
      sextcall_step σ s WB vargs m vres
      f = inl σ
      sg = sextcall_sig σ
      t = E0.

Lemma compatsem_extcall_intro {D: compatdata}
      (σ: sextcall_primsem D) s WB F V ge vargs m vres :
        stencil_matches s ge
        sextcall_step σ s WB vargs m vres
        compatsem_extcall (inl σ) (sextcall_sig σ) WB F V ge vargs m E0 vres .
Proof.
  unfold compatsem_extcall; eauto 7.
Qed.

Lemma compatsem_extcall_le {D: compatdata}
      (σ1 σ2: compatsem D)
      (LE: σ1 σ2)
      sg WB F V ge vargs m t vres
      (Hsem: compatsem_extcall σ1 sg WB F V ge vargs m t vres )
      (Hvalid_ge: s, stencil_matches s ge
                         match σ2 with
                           | inl s2sextcall_valid s2 s = true
                           | _True
                         end)
:
  compatsem_extcall σ2 sg WB F V ge vargs m t vres .
Proof.
  destruct Hsem as (s & σ & Hmatch & Hstep & ? & ? & ?); subst.
  inversion LE; subst; clear LE.
  destruct H0 as [[Hstep´ Hsig Hvalid] Hinvs].
  destruct σ as [sem1 csig1 valid1]; subst; simpl in ×.
  destruct y as [sem2 csig2 valid2]; subst; simpl in ×.
  subst; simpl in ×.
  repeat (econstructor; eauto).
XXX only true if σ2 valid for all stencils; fortunately only used in I64Layers where it's probably true.
  × simpl; eauto.
    intros. eapply Hstep´; eauto.
  × simpl; unfold sextcall_sig; congruence.
Qed.

Local Instance compatlayer_extcall_ops_x {D} (L: compatlayer D):
  ExternalCallsOpsX (mwd D) :=
  {|
    external_functions_sem i sg WB F V ge vargs m t vres :=
       σ,
        get_layer_primitive i L = Errors.OK (Some σ)
        compatsem_extcall σ sg WB _ _ ge vargs m t vres
  |}.

Local Instance compatlayer_extcall_ops {D} (L: compatlayer D):
  ExternalCallsOps (mwd D) :=
  external_calls_ops_x_to_external_calls_ops (mwd D) (external_calls_ops_x := compatlayer_extcall_ops_x L).

Local Instance compatlayer_compiler_config_ops {D} (L: compatlayer D):
  CompilerConfigOps _
      (external_calls_ops := compatlayer_extcall_ops L)
 :=
  {|
    
We want to follow the calling conventions when calling an external function which will be replaced later with code. This is not possible if EF_extcall are enabled at builtin call sites.
To prove that a layer can provide external function properties suitable to CompCert, we need a "strong layer" premise.

Definition sextcall_props_defined {D} (σ: res (option (compatsem D))): bool :=
  match σ with
    | OK (Some (inl f)) ⇒
      match sextcall_props _ f with
        | Error _false
        | _true
      end
    | _true
  end.

Definition ExternalCallsXDefined {D} (L: compatlayer D): Prop :=
   i, (fun fsextcall_props_defined f = true) (get_layer_primitive i L).

Global Instance external_calls_x_defined_dec: {D} (L: _ D), Decision (ExternalCallsXDefined L) := _.

Existing Class ExternalCallsXDefined.

Local Instance compatlayer_extcall_x_strong:
   {D} (L: compatlayer D),
   (DEF: ExternalCallsXDefined L),
    ExternalCallsX _
                   (external_calls_ops_x := compatlayer_extcall_ops_x L).
Proof.

Ltac t DEF id H :=
  let σ := fresh "σ" in
  let Hget := fresh "Hget" in
  let Hsem := fresh "Hsem" in
  let s := fresh "s" in
  let σf := fresh "σf" in
  let Hmatch := fresh "Hmatch" in
  let Hdef := fresh "Hdef" in
  let Hprop := fresh "Hprop" in
  destruct H as (σ & Hget & Hsem);
    destruct Hsem as (s & σf & Hmatch & Hsem & ? & ? & ?);
    subst;
    generalize (DEF id); rewrite Hget; intro Hdef; simpl in Hdef;
    destruct (sextcall_props _ σf) as [Hprop | ]; try discriminate
.

  intros.
  constructor.
  constructor;
    intros; try (t DEF id H).
  × replace (proj_sig_res (sextcall_sig σf)) with (Ctypes.typ_of_type (sextcall_res σf)).
    + eapply external_call_well_typed; eauto.
    + unfold proj_sig_res, sextcall_sig, sextcall_res.
      destruct (sextcall_csig σf); simpl.
      destruct csig_res; simpl; try reflexivity.
      destruct f; reflexivity.
  × t DEF id H1.
    econstructor. split; eauto.
    esplit. esplit.
    split; eauto.
    eapply stencil_matches_preserves_symbols.
      - symmetry; eauto.
      - auto.
      - auto.
      - eassumption.
  × eapply external_call_valid_block; eauto.
  × eapply external_call_max_perm; eauto.
  × eapply external_call_readonly; eauto.
  × exploit external_call_mem_extends; eauto.
    destruct 1 as (? & ? & ? & ?).
    esplit. esplit.
    split; eauto.
    econstructor.
    split; eauto.
    esplit. esplit; eauto.
  × t DEF id H0.
    exploit external_call_mem_inject; eauto.
    {
      destruct H. unfold meminj_preserves_stencil.
      intro; erewrite <- stencil_matches_symbols; eauto.
    }
    destruct 1 as (? & ? & ? & ? & ?).
    esplit. esplit. esplit.
    split; eauto.
    econstructor; eauto.
    split; eauto.
    esplit. esplit; eauto.
  × simpl; omega.
  × inversion H0; subst.
    esplit. esplit. econstructor; eauto. split; eauto.
    esplit. esplit; eauto.
  × t DEF id H0.
    split.
    + constructor.
    + replace s0 with s in × by (eapply stencil_matches_unique; eauto).
      replace σf0 with σf in × by congruence.
      intro; eapply external_call_determ; eauto.
  × econstructor; eauto.
    split; eauto.
    esplit. esplit.
    eauto 6 using external_call_writable_block_weak.
  × eapply external_call_not_writable; eauto.
Qed.

Local Instance compatlayer_extcall_strong :
   `{builtin_norepet: BuiltinIdentsNorepet},
   {D} (L: compatlayer D),
     (DEF: ExternalCallsXDefined L),
    ExternalCalls _
      (external_calls_ops := compatlayer_extcall_ops L)
  := _.

Local Instance compatlayer_compiler_config :
   `{builtin_norepet: BuiltinIdentsNorepet},
   {D} (L: compatlayer D),
     (DEF: ExternalCallsXDefined L),
    CompilerConfiguration _
      (external_calls_ops := compatlayer_extcall_ops L).
Proof.
  constructor.
  typeclasses eauto.
  apply compatlayer_extcall_strong.
  assumption.
Qed.

End WITH_MEMORY_MODEL.