From 74487f079dd56663f97f9731cea328931857495c Mon Sep 17 00:00:00 2001
From: xleroy <xleroy@fca1b0fc-160b-0410-b1d3-a4f43f01ea2e>
Date: Tue, 10 Nov 2009 12:50:57 +0000
Subject: [PATCH] Added support for jump tables in back end.

git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1171 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e
---
 .depend                   |   9 ++-
 backend/Allocation.v      |   4 ++
 backend/Allocproof.v      |   6 ++
 backend/Alloctyping.v     |   2 +
 backend/Bounds.v          |   1 +
 backend/CSE.v             |   2 +
 backend/CSEproof.v        |   7 ++
 backend/Constprop.v       |  23 +++---
 backend/Constpropproof.v  |  12 ++++
 backend/LTL.v             |   9 +++
 backend/LTLin.v           |   8 +++
 backend/LTLintyping.v     |   5 ++
 backend/LTLtyping.v       |   6 ++
 backend/Linear.v          |   8 +++
 backend/Linearize.v       |   2 +
 backend/Linearizeaux.ml   |   2 +
 backend/Linearizeproof.v  |  12 ++++
 backend/Linearizetyping.v |   1 +
 backend/Lineartyping.v    |   4 ++
 backend/Mach.v            |   1 +
 backend/Machabstr.v       |   7 ++
 backend/Machabstr2concr.v |   5 ++
 backend/Machconcr.v       |   8 +++
 backend/Machtyping.v      |   5 ++
 backend/RTL.v             |  30 ++++----
 backend/RTLgen.v          |  17 +++++
 backend/RTLgenaux.ml      |  50 ++++++++++---
 backend/RTLgenproof.v     |  83 ++++++++++++++--------
 backend/RTLgenspec.v      |  75 +++++++++++++++-----
 backend/RTLtyping.v       |  14 ++++
 backend/RTLtypingaux.ml   |   2 +
 backend/Reload.v          |   3 +
 backend/Reloadproof.v     |  14 ++++
 backend/Reloadtyping.v    |   6 +-
 backend/Stacking.v        |   2 +
 backend/Stackingproof.v   |   9 +++
 backend/Stackingtyping.v  |   3 +
 backend/Tailcallproof.v   |   7 ++
 backend/Tunneling.v       |   2 +
 backend/Tunnelingproof.v  |   7 ++
 backend/Tunnelingtyping.v |   4 +-
 common/Switch.v           | 143 ++++++++++++++++++++++++++++++++++----
 lib/Coqlib.v              |  74 ++++++++++++++++++++
 lib/Integers.v            |  25 +++++++
 lib/Ordered.v             |  41 ++++++++++-
 powerpc/Asm.v             |  50 +++++++++----
 powerpc/Asmgen.v          |  10 +--
 powerpc/Asmgenproof.v     |  67 ++++++++++++++----
 powerpc/PrintAsm.ml       |  25 +++++--
 49 files changed, 767 insertions(+), 145 deletions(-)

diff --git a/.depend b/.depend
index 9edeabd67..a0539b0b7 100644
--- a/.depend
+++ b/.depend
@@ -5,18 +5,17 @@ lib/Integers.vo: lib/Integers.v lib/Coqlib.vo
 lib/Iteration.vo: lib/Iteration.v lib/Coqlib.vo
 lib/Lattice.vo: lib/Lattice.v lib/Coqlib.vo lib/Maps.vo
 lib/Maps.vo: lib/Maps.v lib/Coqlib.vo
-lib/Ordered.vo: lib/Ordered.v lib/Coqlib.vo lib/Maps.vo
+lib/Ordered.vo: lib/Ordered.v lib/Coqlib.vo lib/Maps.vo lib/Integers.vo
 lib/Parmov.vo: lib/Parmov.v lib/Coqlib.vo
 lib/UnionFind.vo: lib/UnionFind.v lib/Coqlib.vo
 common/AST.vo: common/AST.v lib/Coqlib.vo common/Errors.vo lib/Integers.vo lib/Floats.vo
-common/Determinism2.vo: common/Determinism2.v lib/Coqlib.vo common/AST.vo lib/Integers.vo common/Values.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo
 common/Determinism.vo: common/Determinism.v lib/Coqlib.vo common/AST.vo lib/Integers.vo common/Values.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo
 common/Errors.vo: common/Errors.v lib/Coqlib.vo
 common/Events.vo: common/Events.v lib/Coqlib.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/Mem.vo
 common/Globalenvs.vo: common/Globalenvs.v lib/Coqlib.vo common/Errors.vo lib/Maps.vo common/AST.vo lib/Integers.vo common/Values.vo common/Mem.vo
 common/Mem.vo: common/Mem.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo
 common/Smallstep.vo: common/Smallstep.v lib/Coqlib.vo common/AST.vo common/Events.vo common/Globalenvs.vo lib/Integers.vo
-common/Switch.vo: common/Switch.v lib/Coqlib.vo lib/Integers.vo
+common/Switch.vo: common/Switch.v lib/Coqlib.vo lib/Integers.vo lib/Ordered.vo
 common/Values.vo: common/Values.v lib/Coqlib.vo common/AST.vo lib/Integers.vo lib/Floats.vo
 $(ARCH)/$(VARIANT)/Conventions.vo: $(ARCH)/$(VARIANT)/Conventions.v lib/Coqlib.vo common/AST.vo backend/Locations.vo
 $(ARCH)/$(VARIANT)/Stacklayout.vo: $(ARCH)/$(VARIANT)/Stacklayout.v lib/Coqlib.vo backend/Bounds.vo
@@ -27,6 +26,7 @@ $(ARCH)/Asmgen.vo: $(ARCH)/Asmgen.v lib/Coqlib.vo lib/Maps.vo common/Errors.vo c
 $(ARCH)/Asm.vo: $(ARCH)/Asm.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo backend/Locations.vo $(ARCH)/$(VARIANT)/Stacklayout.vo $(ARCH)/$(VARIANT)/Conventions.vo
 $(ARCH)/ConstpropOpproof.vo: $(ARCH)/ConstpropOpproof.v lib/Coqlib.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/Mem.vo common/Globalenvs.vo $(ARCH)/Op.vo backend/Registers.vo backend/RTL.vo $(ARCH)/ConstpropOp.vo backend/Constprop.vo
 $(ARCH)/ConstpropOp.vo: $(ARCH)/ConstpropOp.v lib/Coqlib.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo $(ARCH)/Op.vo backend/Registers.vo
+$(ARCH)/extractionMachdep.vo: $(ARCH)/extractionMachdep.v
 $(ARCH)/Machregs.vo: $(ARCH)/Machregs.v lib/Coqlib.vo lib/Maps.vo common/AST.vo
 $(ARCH)/Op.vo: $(ARCH)/Op.v lib/Coqlib.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/Mem.vo common/Globalenvs.vo
 $(ARCH)/SelectOpproof.vo: $(ARCH)/SelectOpproof.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo backend/Cminor.vo $(ARCH)/Op.vo backend/CminorSel.vo $(ARCH)/SelectOp.vo
@@ -56,6 +56,7 @@ backend/LTLin.vo: backend/LTLin.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/In
 backend/LTLtyping.vo: backend/LTLtyping.v lib/Coqlib.vo lib/Maps.vo common/AST.vo $(ARCH)/Op.vo backend/RTL.vo backend/Locations.vo backend/LTL.vo $(ARCH)/$(VARIANT)/Conventions.vo
 backend/LTL.vo: backend/LTL.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/Integers.vo common/Values.vo common/Events.vo common/Mem.vo common/Globalenvs.vo common/Smallstep.vo $(ARCH)/Op.vo backend/Locations.vo $(ARCH)/$(VARIANT)/Conventions.vo
 backend/Machabstr2concr.vo: backend/Machabstr2concr.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/Integers.vo common/Values.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo $(ARCH)/Op.vo backend/Locations.vo backend/Mach.vo backend/Machtyping.vo backend/Machabstr.vo backend/Machconcr.vo $(ARCH)/Asmgenretaddr.vo
+backend/Machabstrblock.vo: backend/Machabstrblock.v lib/Coqlib.vo lib/Maps.vo common/AST.vo common/Mem.vo lib/Integers.vo common/Values.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo $(ARCH)/Op.vo backend/Locations.vo $(ARCH)/$(VARIANT)/Conventions.vo backend/Mach.vo backend/Machabstr.vo $(ARCH)/$(VARIANT)/Stacklayout.vo
 backend/Machabstr.vo: backend/Machabstr.v lib/Coqlib.vo lib/Maps.vo common/AST.vo common/Mem.vo lib/Integers.vo common/Values.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo $(ARCH)/Op.vo backend/Locations.vo $(ARCH)/$(VARIANT)/Conventions.vo backend/Mach.vo $(ARCH)/$(VARIANT)/Stacklayout.vo
 backend/Machconcr.vo: backend/Machconcr.v lib/Coqlib.vo lib/Maps.vo common/AST.vo lib/Integers.vo common/Values.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo $(ARCH)/Op.vo backend/Locations.vo $(ARCH)/$(VARIANT)/Conventions.vo backend/Mach.vo $(ARCH)/$(VARIANT)/Stacklayout.vo $(ARCH)/Asmgenretaddr.vo
 backend/Machtyping.vo: backend/Machtyping.v lib/Coqlib.vo lib/Maps.vo common/AST.vo common/Mem.vo lib/Integers.vo common/Values.vo common/Events.vo common/Globalenvs.vo $(ARCH)/Op.vo backend/Locations.vo $(ARCH)/$(VARIANT)/Conventions.vo backend/Mach.vo backend/Machabstr.vo
@@ -80,6 +81,8 @@ backend/Tailcall.vo: backend/Tailcall.v lib/Coqlib.vo lib/Maps.vo common/AST.vo
 backend/Tunnelingproof.vo: backend/Tunnelingproof.v lib/Coqlib.vo lib/Maps.vo lib/UnionFind.vo common/AST.vo common/Values.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo $(ARCH)/Op.vo backend/Locations.vo backend/LTL.vo backend/Tunneling.vo
 backend/Tunnelingtyping.vo: backend/Tunnelingtyping.v lib/Coqlib.vo lib/Maps.vo lib/UnionFind.vo common/AST.vo common/Values.vo common/Mem.vo common/Globalenvs.vo $(ARCH)/Op.vo backend/Locations.vo backend/LTL.vo backend/LTLtyping.vo backend/Tunneling.vo backend/Tunnelingproof.vo
 backend/Tunneling.vo: backend/Tunneling.v lib/Coqlib.vo lib/Maps.vo lib/UnionFind.vo common/AST.vo common/Values.vo common/Globalenvs.vo $(ARCH)/Op.vo backend/Locations.vo backend/LTL.vo
+cfrontend/Cmedium.saved.vo: cfrontend/Cmedium.saved.v lib/Coqlib.vo common/Errors.vo lib/Maps.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/AST.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo cfrontend/Csyntax.vo cfrontend/Csem.vo
+cfrontend/Cmedium.vo: cfrontend/Cmedium.v lib/Coqlib.vo common/Errors.vo lib/Maps.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/AST.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo cfrontend/Csyntax.vo cfrontend/Csem.vo
 cfrontend/Cminorgenproof.vo: cfrontend/Cminorgenproof.v lib/Coqlib.vo common/Errors.vo lib/Maps.vo common/AST.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/Mem.vo common/Events.vo common/Globalenvs.vo common/Smallstep.vo cfrontend/Csharpminor.vo $(ARCH)/Op.vo backend/Cminor.vo cfrontend/Cminorgen.vo common/Switch.vo
 cfrontend/Cminorgen.vo: cfrontend/Cminorgen.v lib/Coqlib.vo common/Errors.vo lib/Maps.vo lib/Ordered.vo common/AST.vo lib/Integers.vo common/Mem.vo cfrontend/Csharpminor.vo $(ARCH)/Op.vo backend/Cminor.vo
 cfrontend/Csem.vo: cfrontend/Csem.v lib/Coqlib.vo common/Errors.vo lib/Maps.vo lib/Integers.vo lib/Floats.vo common/Values.vo common/AST.vo common/Mem.vo common/Events.vo common/Globalenvs.vo cfrontend/Csyntax.vo common/Smallstep.vo
diff --git a/backend/Allocation.v b/backend/Allocation.v
index 7d843e579..b802f4ac7 100644
--- a/backend/Allocation.v
+++ b/backend/Allocation.v
@@ -103,6 +103,8 @@ Definition transfer
 	  reg_list_live args (reg_sum_live ros Regset.empty)
       | Icond cond args ifso ifnot =>
           reg_list_live args after
+      | Ijumptable arg tbl =>
+          reg_live arg after
       | Ireturn optarg =>
           reg_option_live optarg Regset.empty
       end
@@ -167,6 +169,8 @@ Definition transf_instr
       Ltailcall sig (sum_left_map assign ros) (List.map assign args)
   | Icond cond args ifso ifnot =>
       Lcond cond (List.map assign args) ifso ifnot
+  | Ijumptable arg tbl =>
+      Ljumptable (assign arg) tbl
   | Ireturn optarg =>
       Lreturn (option_map assign optarg)
   end.
diff --git a/backend/Allocproof.v b/backend/Allocproof.v
index fc0a0f3c6..10eaa5b1a 100644
--- a/backend/Allocproof.v
+++ b/backend/Allocproof.v
@@ -683,6 +683,12 @@ Proof.
   eapply exec_Lcond_false; eauto. TranslInstr.
   MatchStates. eapply agree_reg_list_live. eauto.
 
+  (* Ijumptable *)
+  assert (rs#arg = ls (assign arg)). apply AG. apply Regset.add_1. auto. 
+  econstructor; split.
+  eapply exec_Ljumptable; eauto. TranslInstr. congruence. 
+  MatchStates. eapply list_nth_z_in; eauto. eapply agree_reg_live; eauto. 
+
   (* Ireturn *)
   econstructor; split.
   eapply exec_Lreturn; eauto. TranslInstr; eauto.
diff --git a/backend/Alloctyping.v b/backend/Alloctyping.v
index aba966010..260297f2c 100644
--- a/backend/Alloctyping.v
+++ b/backend/Alloctyping.v
@@ -141,6 +141,8 @@ Proof.
   rewrite transf_unroll; auto.
   (* cond *)
   WT.
+  (* jumptable *)
+  WT. 
   (* return *)
   WT.
   rewrite transf_unroll; simpl. 
diff --git a/backend/Bounds.v b/backend/Bounds.v
index 8c5f536da..15468c574 100644
--- a/backend/Bounds.v
+++ b/backend/Bounds.v
@@ -106,6 +106,7 @@ Definition regs_of_instr (i: instruction) : list mreg :=
   | Llabel lbl => nil
   | Lgoto lbl => nil
   | Lcond cond args lbl => nil
+  | Ljumptable arg tbl => nil
   | Lreturn => nil
   end.
 
diff --git a/backend/CSE.v b/backend/CSE.v
index ff8d41aa4..98b7bbf58 100644
--- a/backend/CSE.v
+++ b/backend/CSE.v
@@ -350,6 +350,8 @@ Definition transfer (f: function) (pc: node) (before: numbering) :=
           empty_numbering
       | Icond cond args ifso ifnot =>
           before
+      | Ijumptable arg tbl =>
+          before
       | Ireturn optarg =>
           before
       end
diff --git a/backend/CSEproof.v b/backend/CSEproof.v
index 14027bf09..7f9424647 100644
--- a/backend/CSEproof.v
+++ b/backend/CSEproof.v
@@ -916,6 +916,13 @@ Proof.
   eapply analysis_correct_1; eauto. simpl; auto.
   unfold transfer; rewrite H; auto.
 
+  (* Icond false *)
+  econstructor; split.
+  eapply exec_Ijumptable; eauto. 
+  econstructor; eauto.
+  eapply analysis_correct_1; eauto. simpl. eapply list_nth_z_in; eauto.
+  unfold transfer; rewrite H; auto.
+
   (* Ireturn *)
   econstructor; split.
   eapply exec_Ireturn; eauto.
diff --git a/backend/Constprop.v b/backend/Constprop.v
index cccce9a3e..e1ab2e9c0 100644
--- a/backend/Constprop.v
+++ b/backend/Constprop.v
@@ -121,26 +121,14 @@ Definition transfer (f: function) (pc: node) (before: D.t) :=
   | None => before
   | Some i =>
       match i with
-      | Inop s =>
-          before
       | Iop op args res s =>
           let a := eval_static_operation op (approx_regs before args) in
           D.set res a before
       | Iload chunk addr args dst s =>
           D.set dst Unknown before
-      | Istore chunk addr args src s =>
-          before
       | Icall sig ros args res s =>
           D.set res Unknown before
-      | Itailcall sig ros args =>
-          before
-(*
-      | Ialloc arg res s =>
-          D.set res Unknown before
-*)
-      | Icond cond args ifso ifnot =>
-          before
-      | Ireturn optarg =>
+      | _ =>
           before
       end
   end.
@@ -212,6 +200,15 @@ Definition transf_instr (app: D.t) (instr: instruction) :=
           let (cond', args') := cond_strength_reduction (approx_reg app) cond args in
           Icond cond' args' s1 s2
       end
+  | Ijumptable arg tbl =>
+      match intval (approx_reg app) arg with
+      | Some n =>
+          match list_nth_z tbl (Int.signed n) with
+          | Some s => Inop s
+          | None => instr
+          end
+      | None => instr
+      end
   | _ =>
       instr
   end.
diff --git a/backend/Constpropproof.v b/backend/Constpropproof.v
index dadb192fe..fff9a60da 100644
--- a/backend/Constpropproof.v
+++ b/backend/Constpropproof.v
@@ -390,6 +390,18 @@ Proof.
   simpl; auto.
   unfold transfer; rewrite H; auto.
 
+  (* Ijumptable *)
+  exists (State s' (transf_code (analyze f) (fn_code f)) sp pc' rs m); split.
+  caseEq (intval (approx_reg (analyze f)!!pc) arg); intros.
+  exploit intval_correct; eauto. eexact MATCH. intro VRS.
+  eapply exec_Inop; eauto. TransfInstr. rewrite H2. 
+  replace i with n by congruence. rewrite H1. auto.
+  eapply exec_Ijumptable; eauto. TransfInstr. rewrite H2. auto.
+  constructor; auto.
+  eapply analyze_correct_1; eauto.
+  simpl. eapply list_nth_z_in; eauto.
+  unfold transfer; rewrite  H; auto.
+
   (* Ireturn *)
   exists (Returnstate s' (regmap_optget or Vundef rs) (free m stk)); split.
   eapply exec_Ireturn; eauto. TransfInstr; auto.
diff --git a/backend/LTL.v b/backend/LTL.v
index 2505566fa..6a693361b 100644
--- a/backend/LTL.v
+++ b/backend/LTL.v
@@ -42,6 +42,7 @@ Inductive instruction: Type :=
   | Lcall: signature -> loc + ident -> list loc -> loc -> node -> instruction
   | Ltailcall: signature -> loc + ident -> list loc -> instruction
   | Lcond: condition -> list loc -> node -> node -> instruction
+  | Ljumptable: loc -> list node -> instruction
   | Lreturn: option loc -> instruction.
 
 Definition code: Type := PTree.t instruction.
@@ -206,6 +207,13 @@ Inductive step: state -> trace -> state -> Prop :=
       eval_condition cond (map rs args) = Some false ->
       step (State s f sp pc rs m)
         E0 (State s f sp ifnot rs m)
+  | exec_Ljumptable:
+      forall s f sp pc rs m arg tbl n pc',
+      (fn_code f)!pc = Some(Ljumptable arg tbl) ->
+      rs arg = Vint n ->
+      list_nth_z tbl (Int.signed n) = Some pc' ->
+      step (State s f sp pc rs m)
+        E0 (State s f sp pc' rs m)
   | exec_Lreturn:
       forall s f stk pc rs m or,
       (fn_code f)!pc = Some(Lreturn or) ->
@@ -263,6 +271,7 @@ Definition successors_instr (i: instruction) : list node :=
   | Lcall sig ros args res s => s :: nil
   | Ltailcall sig ros args => nil
   | Lcond cond args ifso ifnot => ifso :: ifnot :: nil
+  | Ljumptable arg tbl => tbl
   | Lreturn optarg => nil
   end.
 
diff --git a/backend/LTLin.v b/backend/LTLin.v
index 10b7d8323..e3533388e 100644
--- a/backend/LTLin.v
+++ b/backend/LTLin.v
@@ -50,6 +50,7 @@ Inductive instruction: Type :=
   | Llabel: label -> instruction
   | Lgoto: label -> instruction
   | Lcond: condition -> list loc -> label -> instruction
+  | Ljumptable: loc -> list label -> instruction
   | Lreturn: option loc -> instruction.
 
 Definition code: Type := list instruction.
@@ -204,6 +205,13 @@ Inductive step: state -> trace -> state -> Prop :=
       eval_condition cond (map rs args) = Some false ->
       step (State s f sp (Lcond cond args lbl :: b) rs m)
         E0 (State s f sp b rs m)
+  | exec_Ljumptable:
+      forall s f sp arg tbl b rs m n lbl b',
+      rs arg = Vint n ->
+      list_nth_z tbl (Int.signed n) = Some lbl ->
+      find_label lbl f.(fn_code) = Some b' ->
+      step (State s f sp (Ljumptable arg tbl :: b) rs m)
+        E0 (State s f sp b' rs m)
   | exec_Lreturn:
       forall s f stk rs m or b,
       step (State s f (Vptr stk Int.zero) (Lreturn or :: b) rs m)
diff --git a/backend/LTLintyping.v b/backend/LTLintyping.v
index 9f3f5896b..6013a17df 100644
--- a/backend/LTLintyping.v
+++ b/backend/LTLintyping.v
@@ -76,6 +76,11 @@ Inductive wt_instr : instruction -> Prop :=
       List.map Loc.type args = type_of_condition cond ->
       locs_acceptable args ->
       wt_instr (Lcond cond args lbl)
+  | wt_Ljumptable:
+      forall arg tbl,
+      Loc.type arg = Tint ->
+      loc_acceptable arg ->
+      wt_instr (Ljumptable arg tbl)
   | wt_Lreturn: 
       forall optres,
       option_map Loc.type optres = funsig.(sig_res) ->
diff --git a/backend/LTLtyping.v b/backend/LTLtyping.v
index 0461c9af5..e62f9287f 100644
--- a/backend/LTLtyping.v
+++ b/backend/LTLtyping.v
@@ -94,6 +94,12 @@ Inductive wt_instr : instruction -> Prop :=
       locs_acceptable args ->
       valid_successor s1 -> valid_successor s2 ->
       wt_instr (Lcond cond args s1 s2)
+  | wt_Ljumptable:
+      forall arg tbl,
+      Loc.type arg = Tint ->
+      loc_acceptable arg ->
+      (forall lbl, In lbl tbl -> valid_successor lbl) ->
+      wt_instr (Ljumptable arg tbl)
   | wt_Lreturn: 
       forall optres,
       option_map Loc.type optres = funct.(fn_sig).(sig_res) ->
diff --git a/backend/Linear.v b/backend/Linear.v
index e025407a8..bf21cb7dc 100644
--- a/backend/Linear.v
+++ b/backend/Linear.v
@@ -46,6 +46,7 @@ Inductive instruction: Type :=
   | Llabel: label -> instruction
   | Lgoto: label -> instruction
   | Lcond: condition -> list mreg -> label -> instruction
+  | Ljumptable: mreg -> list label -> instruction
   | Lreturn: instruction.
 
 Definition code: Type := list instruction.
@@ -293,6 +294,13 @@ Inductive step: state -> trace -> state -> Prop :=
       eval_condition cond (reglist rs args) = Some false ->
       step (State s f sp (Lcond cond args lbl :: b) rs m)
         E0 (State s f sp b rs m)
+  | exec_Ljumptable:
+      forall s f sp arg tbl b rs m n lbl b',
+      rs (R arg) = Vint n ->
+      list_nth_z tbl (Int.signed n) = Some lbl ->
+      find_label lbl f.(fn_code) = Some b' ->
+      step (State s f sp (Ljumptable arg tbl :: b) rs m)
+        E0 (State s f sp b' rs m)
   | exec_Lreturn:
       forall s f stk b rs m,
       step (State s f (Vptr stk Int.zero) (Lreturn :: b) rs m)
diff --git a/backend/Linearize.v b/backend/Linearize.v
index 431fe1720..31d0318cc 100644
--- a/backend/Linearize.v
+++ b/backend/Linearize.v
@@ -190,6 +190,8 @@ Definition linearize_instr (b: LTL.instruction) (k: code) : code :=
         Lcond (negate_condition cond) args s2 :: add_branch s1 k
       else
         Lcond cond args s1 :: add_branch s2 k
+  | LTL.Ljumptable arg tbl =>
+      Ljumptable arg tbl :: k
   | LTL.Lreturn or =>
       Lreturn or :: k
   end.
diff --git a/backend/Linearizeaux.ml b/backend/Linearizeaux.ml
index b27386052..1f4e5fac5 100644
--- a/backend/Linearizeaux.ml
+++ b/backend/Linearizeaux.ml
@@ -96,6 +96,8 @@ let basic_blocks f joins =
          | Ltailcall (sig0, ros, args) -> end_block blk minpc
          | Lcond (cond, args, ifso, ifnot) ->
              end_block blk minpc; start_block ifso; start_block ifnot
+         | Ljumptable(arg, tbl) ->
+             end_block blk minpc; List.iter start_block tbl
          | Lreturn optarg -> end_block blk minpc
   (* next_in_block: check if join point and either extend block
      or start block *)
diff --git a/backend/Linearizeproof.v b/backend/Linearizeproof.v
index e35fb11be..c79908d67 100644
--- a/backend/Linearizeproof.v
+++ b/backend/Linearizeproof.v
@@ -639,6 +639,18 @@ Proof.
   traceEq.
   econstructor; eauto.
 
+  (* Ljumptable *)
+  destruct (find_label_lin_inv _ _ _ _ _ TRF H REACH AT) as [c' EQ].
+  simpl in EQ. subst c.
+  assert (REACH': (reachable f)!!pc' = true).
+  eapply reachable_successors; eauto. simpl. eapply list_nth_z_in; eauto.
+  exploit find_label_lin_succ; eauto.
+  inv WTI. apply H6. eapply list_nth_z_in; eauto. 
+  intros [c'' AT'].
+  econstructor; split.
+  apply plus_one. eapply exec_Ljumptable; eauto. 
+  econstructor; eauto.
+
   (* Lreturn *)
   destruct (find_label_lin_inv _ _ _ _ _ TRF H REACH AT) as [c' EQ].
   simpl in EQ. subst c.
diff --git a/backend/Linearizetyping.v b/backend/Linearizetyping.v
index 627c878f0..716b66f13 100644
--- a/backend/Linearizetyping.v
+++ b/backend/Linearizetyping.v
@@ -60,6 +60,7 @@ Proof.
   apply wt_add_branch; auto.
   constructor; auto. apply wt_add_branch; auto.
   apply wt_add_instr. constructor; auto. auto.
+  apply wt_add_instr. constructor; auto. auto.
 Qed.
 
 Lemma wt_linearize_body:
diff --git a/backend/Lineartyping.v b/backend/Lineartyping.v
index 33b570b91..ba4952bd5 100644
--- a/backend/Lineartyping.v
+++ b/backend/Lineartyping.v
@@ -95,6 +95,10 @@ Inductive wt_instr : instruction -> Prop :=
       forall cond args lbl,
       List.map mreg_type args = type_of_condition cond ->
       wt_instr (Lcond cond args lbl)
+  | wt_Ljumptable:
+      forall arg tbl,
+      mreg_type arg = Tint ->
+      wt_instr (Ljumptable arg tbl)
   | wt_Lreturn: 
       wt_instr (Lreturn).
 
diff --git a/backend/Mach.v b/backend/Mach.v
index 0bb24428c..f7e85c3ef 100644
--- a/backend/Mach.v
+++ b/backend/Mach.v
@@ -61,6 +61,7 @@ Inductive instruction: Type :=
   | Mlabel: label -> instruction
   | Mgoto: label -> instruction
   | Mcond: condition -> list mreg -> label -> instruction
+  | Mjumptable: mreg -> list label -> instruction
   | Mreturn: instruction.
 
 Definition code := list instruction.
diff --git a/backend/Machabstr.v b/backend/Machabstr.v
index aa17cd44b..a2630a2b8 100644
--- a/backend/Machabstr.v
+++ b/backend/Machabstr.v
@@ -282,6 +282,13 @@ Inductive step: state -> trace -> state -> Prop :=
       eval_condition cond rs##args = Some false ->
       step (State s f sp (Mcond cond args lbl :: c) rs fr m)
         E0 (State s f sp c rs fr m)
+  | exec_Mjumptable:
+      forall s f sp arg tbl c rs fr m n lbl c',
+      rs arg = Vint n ->
+      list_nth_z tbl (Int.signed n) = Some lbl ->
+      find_label lbl f.(fn_code) = Some c' ->
+      step (State s f sp (Mjumptable arg tbl :: c) rs fr m)
+        E0 (State s f sp c' rs fr m)
   | exec_Mreturn:
       forall s f stk soff c rs fr m,
       step (State s f (Vptr stk soff) (Mreturn :: c) rs fr m)
diff --git a/backend/Machabstr2concr.v b/backend/Machabstr2concr.v
index 139eac75c..89529fd4b 100644
--- a/backend/Machabstr2concr.v
+++ b/backend/Machabstr2concr.v
@@ -842,6 +842,11 @@ Proof.
   eapply exec_Mcond_false; eauto.
   econstructor; eauto.
 
+  (* Mjumptable *)
+  econstructor; split.
+  eapply exec_Mjumptable; eauto. 
+  econstructor; eauto.
+
   (* Mreturn *)
   assert (WTF: wt_function f) by (inv WTS; auto).
   econstructor; split.
diff --git a/backend/Machconcr.v b/backend/Machconcr.v
index 876f558c8..84ae0a4fd 100644
--- a/backend/Machconcr.v
+++ b/backend/Machconcr.v
@@ -204,6 +204,14 @@ Inductive step: state -> trace -> state -> Prop :=
       eval_condition cond rs##args = Some false ->
       step (State s f sp (Mcond cond args lbl :: c) rs m)
         E0 (State s f sp c rs m)
+  | exec_Mjumptable:
+      forall s fb f sp arg tbl c rs m n lbl c',
+      rs arg = Vint n ->
+      list_nth_z tbl (Int.signed n) = Some lbl ->
+      Genv.find_funct_ptr ge fb = Some (Internal f) ->
+      find_label lbl f.(fn_code) = Some c' ->
+      step (State s fb sp (Mjumptable arg tbl :: c) rs m)
+        E0 (State s fb sp c' rs m)
   | exec_Mreturn:
       forall s fb stk soff c rs m f,
       Genv.find_funct_ptr ge fb = Some (Internal f) ->
diff --git a/backend/Machtyping.v b/backend/Machtyping.v
index ef59e6f06..fe086cb4f 100644
--- a/backend/Machtyping.v
+++ b/backend/Machtyping.v
@@ -79,6 +79,10 @@ Inductive wt_instr : instruction -> Prop :=
       forall cond args lbl,
       List.map mreg_type args = type_of_condition cond ->
       wt_instr (Mcond cond args lbl)
+  | wt_Mjumptable:
+      forall arg tbl,
+      mreg_type arg = Tint ->
+      wt_instr (Mjumptable arg tbl)
   | wt_Mreturn: 
       wt_instr Mreturn.
 
@@ -280,6 +284,7 @@ Proof.
 
   apply is_tail_find_label with lbl; congruence.
   apply is_tail_find_label with lbl; congruence. 
+  apply is_tail_find_label with lbl; congruence. 
 
   econstructor; eauto.
 
diff --git a/backend/RTL.v b/backend/RTL.v
index 5de073ee5..b2ee80fc2 100644
--- a/backend/RTL.v
+++ b/backend/RTL.v
@@ -75,6 +75,10 @@ Inductive instruction: Type :=
           [cond] over the values of registers [args].  If the condition
           is true, it transitions to [ifso].  If the condition is false,
           it transitions to [ifnot]. *)
+  | Ijumptable: reg -> list node -> instruction
+      (** [Ijumptable arg tbl] transitions to the node that is the [n]-th
+          element of the list [tbl], where [n] is the signed integer
+          value of register [arg]. *)
   | Ireturn: option reg -> instruction.
       (** [Ireturn] terminates the execution of the current function
           (it has no successor).  It returns the value of the given
@@ -252,6 +256,13 @@ Inductive step: state -> trace -> state -> Prop :=
       eval_condition cond rs##args = Some false ->
       step (State s c sp pc rs m)
         E0 (State s c sp ifnot rs m)
+  | exec_Ijumptable:
+      forall s c sp pc rs m arg tbl n pc',
+      c!pc = Some(Ijumptable arg tbl) ->
+      rs#arg = Vint n ->
+      list_nth_z tbl (Int.signed n) = Some pc' ->
+      step (State s c sp pc rs m)
+        E0 (State s c sp pc' rs m)
   | exec_Ireturn:
       forall s c stk pc rs m or,
       c!pc = Some(Ireturn or) ->
@@ -339,30 +350,13 @@ Definition successors_instr (i: instruction) : list node :=
   | Icall sig ros args res s => s :: nil
   | Itailcall sig ros args => nil
   | Icond cond args ifso ifnot => ifso :: ifnot :: nil
+  | Ijumptable arg tbl => tbl
   | Ireturn optarg => nil
   end.
 
 Definition successors (f: function) : PTree.t (list node) :=
   PTree.map (fun pc i => successors_instr i) f.(fn_code).
 
-(*
-Definition successors (f: function) (pc: node) : list node :=
-  match f.(fn_code)!pc with
-  | None => nil
-  | Some i =>
-      match i with
-      | Inop s => s :: nil
-      | Iop op args res s => s :: nil
-      | Iload chunk addr args dst s => s :: nil
-      | Istore chunk addr args src s => s :: nil
-      | Icall sig ros args res s => s :: nil
-      | Itailcall sig ros args => nil
-      | Icond cond args ifso ifnot => ifso :: ifnot :: nil
-      | Ireturn optarg => nil
-      end
-  end.
-*)
-
 (** Transformation of a RTL function instruction by instruction.
   This applies a given transformation function to all instructions
   of a function and constructs a transformed function from that. *)
diff --git a/backend/RTLgen.v b/backend/RTLgen.v
index 39add9861..942dc50b6 100644
--- a/backend/RTLgen.v
+++ b/backend/RTLgen.v
@@ -474,6 +474,15 @@ Definition transl_exit (nexits: list node) (n: nat) : mon node :=
   | Some ne => ret ne
   end.
 
+Fixpoint transl_jumptable (nexits: list node) (tbl: list nat) : mon (list node) :=
+  match tbl with
+  | nil => ret nil
+  | t1 :: tl =>
+      do n1 <- transl_exit nexits t1;
+      do nl <- transl_jumptable nexits tl;
+      ret (n1 :: nl)
+  end.
+
 Fixpoint transl_switch (r: reg) (nexits: list node) (t: comptree)
                        {struct t} : mon node :=
   match t with
@@ -487,6 +496,14 @@ Fixpoint transl_switch (r: reg) (nexits: list node) (t: comptree)
       do n2 <- transl_switch r nexits t2;
       do n1 <- transl_switch r nexits t1;
       add_instr (Icond (Ccompuimm Clt key) (r :: nil) n1 n2)
+  | CTjumptable ofs sz tbl t' =>
+      do rt <- new_reg;
+      do ttbl <- transl_jumptable nexits tbl;
+      do n1 <- add_instr (Ijumptable rt ttbl);
+      do n2 <- transl_switch r nexits t';
+      do n3 <- add_instr (Icond (Ccompuimm Clt sz) (rt :: nil) n1 n2);
+      let op := if Int.eq ofs Int.zero then Omove else Oaddimm (Int.neg ofs) in
+      add_instr (Iop op (r :: nil) rt n3)
   end.
 
 (** Translation of statements.  [transl_stmt map s nd nexits nret rret]
diff --git a/backend/RTLgenaux.ml b/backend/RTLgenaux.ml
index 4c1fc05c0..7e42c80d1 100644
--- a/backend/RTLgenaux.ml
+++ b/backend/RTLgenaux.ml
@@ -27,16 +27,16 @@ module IntOrd =
 module IntSet = Set.Make(IntOrd)
 
 let normalize_table tbl =
-  let rec norm seen = function
-  | [] -> []
+  let rec norm keys accu = function
+  | [] -> (accu, keys)
   | Datatypes.Coq_pair(key, act) :: rem ->
-      if IntSet.mem key seen
-      then norm seen rem
-      else (key, act) :: norm (IntSet.add key seen) rem
-  in norm IntSet.empty tbl
+      if IntSet.mem key keys
+      then norm keys accu rem
+      else norm (IntSet.add key keys) ((key, act) :: accu) rem
+  in norm IntSet.empty [] tbl
 
-let compile_switch default table =
-  let sw = Array.of_list (normalize_table table) in
+let compile_switch_as_tree default tbl =
+  let sw = Array.of_list tbl in
   Array.stable_sort (fun (n1, _) (n2, _) -> IntOrd.compare n1 n2) sw;
   let rec build lo hi minval maxval =
     match hi - lo with
@@ -70,3 +70,37 @@ let compile_switch default table =
               build lo mid minval (Integers.Int.sub pivot Integers.Int.one),
               build mid hi pivot maxval)
   in build 0 (Array.length sw) Integers.Int.zero Integers.Int.max_unsigned
+
+let uint64_of_coqint n = (* force unsigned interpretation *)
+  Int64.logand (Int64.of_int32 (camlint_of_coqint n)) 0xFFFF_FFFFL
+
+let compile_switch_as_jumptable default cases minkey maxkey =
+  let tblsize = 1 + Int64.to_int (Int64.sub maxkey minkey) in
+  assert (tblsize >= 0 && tblsize <= Sys.max_array_length);
+  let tbl = Array.make tblsize default in
+  List.iter
+    (fun (key, act) ->
+       let pos = Int64.to_int (Int64.sub (uint64_of_coqint key) minkey) in
+       tbl.(pos) <- act)
+    cases;
+  CTjumptable(coqint_of_camlint (Int64.to_int32 minkey), 
+              coqint_of_camlint (Int32.of_int tblsize),
+              Array.to_list tbl,
+              CTaction default)
+
+let dense_enough (numcases: int) (minkey: int64) (maxkey: int64) =
+  let span = Int64.sub maxkey minkey in
+  assert (span >= 0L);
+  let tree_size = Int64.mul 4L (Int64.of_int numcases)
+  and table_size = Int64.add 8L span in
+  numcases >= 7           (* really small jump tables are less efficient *)
+  && span < Int64.of_int Sys.max_array_length
+  && table_size <= tree_size
+
+let compile_switch default table =
+  let (tbl, keys) = normalize_table table in
+  let minkey = uint64_of_coqint (IntSet.min_elt keys)
+  and maxkey = uint64_of_coqint (IntSet.max_elt keys) in
+  if dense_enough (List.length tbl) minkey maxkey
+  then compile_switch_as_jumptable default tbl minkey maxkey
+  else compile_switch_as_tree default tbl
diff --git a/backend/RTLgenproof.v b/backend/RTLgenproof.v
index df1ade9dd..d07bd0814 100644
--- a/backend/RTLgenproof.v
+++ b/backend/RTLgenproof.v
@@ -419,37 +419,65 @@ Qed.
 (** Correctness of the translation of [switch] statements *)
 
 Lemma transl_switch_correct:
-  forall cs sp rs m i code r nexits t ns,
-  tr_switch code r nexits t ns ->
+  forall cs sp e m code map r nexits t ns,
+  tr_switch code map r nexits t ns ->
+  forall rs i act,
   rs#r = Vint i ->
-  exists nd,
-  star step tge (State cs code sp ns rs m) E0 (State cs code sp nd rs m) /\
-  nth_error nexits (comptree_match i t) = Some nd.
+  map_wf map ->
+  match_env map e nil rs ->
+  comptree_match i t = Some act ->
+  exists nd, exists rs',
+  star step tge (State cs code sp ns rs m) E0 (State cs code sp nd rs' m) /\
+  nth_error nexits act = Some nd /\
+  match_env map e nil rs'.
 Proof.
-  induction 1; intros; simpl.
-  exists n. split. apply star_refl. auto. 
-
-  caseEq (Int.eq i key); intros.
-  exists nfound; split. 
+  induction 1; simpl; intros.
+(* action *)
+  inv H3. exists n; exists rs; intuition.
+  apply star_refl.
+(* ifeq *)
+  caseEq (Int.eq i key); intro EQ; rewrite EQ in H5.
+  inv H5. exists nfound; exists rs; intuition.
   apply star_one. eapply exec_Icond_true; eauto. 
-  simpl. rewrite H2. congruence. auto.
-  exploit IHtr_switch; eauto. intros [nd [EX MATCH]].
-  exists nd; split.
+  simpl. rewrite H2. congruence.
+  exploit IHtr_switch; eauto. intros [nd1 [rs1 [EX [NTH ME]]]].
+  exists nd1; exists rs1; intuition.
   eapply star_step. eapply exec_Icond_false; eauto. 
   simpl. rewrite H2. congruence. eexact EX. traceEq.
-  auto.
-
-  caseEq (Int.ltu i key); intros.
-  exploit IHtr_switch1; eauto. intros [nd [EX MATCH]].
-  exists nd; split. 
+(* iflt *)
+  caseEq (Int.ltu i key); intro EQ; rewrite EQ in H5.
+  exploit IHtr_switch1; eauto. intros [nd1 [rs1 [EX [NTH ME]]]].
+  exists nd1; exists rs1; intuition.
   eapply star_step. eapply exec_Icond_true; eauto. 
   simpl. rewrite H2. congruence. eexact EX. traceEq.
-  auto.
-  exploit IHtr_switch2; eauto. intros [nd [EX MATCH]].
-  exists nd; split. 
+  exploit IHtr_switch2; eauto. intros [nd1 [rs1 [EX [NTH ME]]]].
+  exists nd1; exists rs1; intuition.
   eapply star_step. eapply exec_Icond_false; eauto. 
   simpl. rewrite H2. congruence. eexact EX. traceEq.
-  auto.
+(* jumptable *)
+  set (rs1 := rs#rt <- (Vint(Int.sub i ofs))).
+  assert (ME1: match_env map e nil rs1).
+    unfold rs1. eauto with rtlg.
+  assert (EX1: step tge (State cs code sp n rs m) E0 (State cs code sp n1 rs1 m)).
+    eapply exec_Iop; eauto. 
+    predSpec Int.eq Int.eq_spec ofs Int.zero; simpl.
+    rewrite H10. rewrite Int.sub_zero_l. congruence.
+    rewrite H6. rewrite <- Int.sub_add_opp. auto. 
+  caseEq (Int.ltu (Int.sub i ofs) sz); intro EQ; rewrite EQ in H9.
+  exploit H5; eauto. intros [nd [A B]].
+  exists nd; exists rs1; intuition. 
+  eapply star_step. eexact EX1.
+  eapply star_step. eapply exec_Icond_true; eauto. 
+  simpl. unfold rs1. rewrite Regmap.gss. congruence. 
+  apply star_one. eapply exec_Ijumptable; eauto. unfold rs1. apply Regmap.gss. 
+  reflexivity. traceEq.
+  exploit (IHtr_switch rs1); eauto. unfold rs1. rewrite Regmap.gso; auto.
+  intros [nd [rs' [EX [NTH ME]]]].
+  exists nd; exists rs'; intuition.
+  eapply star_step. eexact EX1.
+  eapply star_step. eapply exec_Icond_false; eauto. 
+  simpl. unfold rs1. rewrite Regmap.gss. congruence.
+  eexact EX. reflexivity. traceEq.
 Qed.
 
 (** ** Semantic preservation for the translation of expressions *)
@@ -530,8 +558,6 @@ Definition transl_condition_prop
   /\ match_env map e le rs'
   /\ (forall r, reg_in_map map r \/ In r pr -> rs'#r = rs#r).
 
-
-
 (** The correctness of the translation is a huge induction over
   the Cminor evaluation derivation for the source program.  To keep
   the proof manageable, we put each case of the proof in a separate
@@ -1194,15 +1220,16 @@ Proof.
   econstructor; eauto. econstructor; eauto.
 
   (* switch *)
-  inv TS. 
+  inv TS.
+  exploit validate_switch_correct; eauto. intro CTM.
   exploit transl_expr_correct; eauto. 
   intros [rs' [A [B [C D]]]].
   exploit transl_switch_correct; eauto. 
-  intros [nd [E F]].
+  intros [nd [rs'' [E [F G]]]].
   econstructor; split.
   right; split. eapply star_trans. eexact A. eexact E.  traceEq. Lt_state. 
-  econstructor; eauto. 
-  rewrite (validate_switch_correct _ _ _ H3 n). constructor. auto.
+  econstructor; eauto.
+  constructor. auto.
 
   (* return none *)
   inv TS.
diff --git a/backend/RTLgenspec.v b/backend/RTLgenspec.v
index caf93c836..037eb3fb1 100644
--- a/backend/RTLgenspec.v
+++ b/backend/RTLgenspec.v
@@ -713,22 +713,36 @@ Definition tr_store_optvar (c: code) (map: mapping)
 
 (** Auxiliary for the compilation of [switch] statements. *)
 
+Definition tr_jumptable (nexits: list node) (tbl: list nat) (ttbl: list node) : Prop :=
+  forall v act,
+  list_nth_z tbl v = Some act ->
+  exists n, list_nth_z ttbl v = Some n /\ nth_error nexits act = Some n.
+
 Inductive tr_switch
-     (c: code) (r: reg) (nexits: list node):
+     (c: code) (map: mapping) (r: reg) (nexits: list node):
      comptree -> node -> Prop :=
   | tr_switch_action: forall act n,
       nth_error nexits act = Some n ->
-      tr_switch c r nexits (CTaction act) n
+      tr_switch c map r nexits (CTaction act) n
   | tr_switch_ifeq: forall key act t' n ncont nfound,
-      tr_switch c r nexits t' ncont ->
+      tr_switch c map r nexits t' ncont ->
       nth_error nexits act = Some nfound ->
       c!n = Some(Icond (Ccompimm Ceq key) (r :: nil) nfound ncont) ->
-      tr_switch c r nexits (CTifeq key act t') n
+      tr_switch c map r nexits (CTifeq key act t') n
   | tr_switch_iflt: forall key t1 t2 n n1 n2,
-      tr_switch c r nexits t1 n1 ->
-      tr_switch c r nexits t2 n2 ->
+      tr_switch c map r nexits t1 n1 ->
+      tr_switch c map r nexits t2 n2 ->
       c!n = Some(Icond (Ccompuimm Clt key) (r :: nil) n1 n2) ->
-      tr_switch c r nexits (CTiflt key t1 t2) n.
+      tr_switch c map r nexits (CTiflt key t1 t2) n
+  | tr_switch_jumptable: forall ofs sz tbl t n n1 n2 n3 rt ttbl,
+      ~reg_in_map map rt -> rt <> r ->
+      c!n = Some(Iop (if Int.eq ofs Int.zero then Omove else Oaddimm (Int.neg ofs))
+                     (r ::nil) rt n1) ->
+      c!n1 = Some(Icond (Ccompuimm Clt sz) (rt :: nil) n2 n3) ->
+      c!n2 = Some(Ijumptable rt ttbl) ->
+      tr_switch c map r nexits t n3 ->
+      tr_jumptable nexits tbl ttbl ->
+      tr_switch c map r nexits (CTjumptable ofs sz tbl t) n.
 
 (** [tr_stmt c map stmt ns ncont nexits nret rret] holds if the graph [c],
   starting at node [ns], contains instructions that perform the Cminor
@@ -786,7 +800,7 @@ Inductive tr_stmt (c: code) (map: mapping):
   | tr_Sswitch: forall a cases default ns nd nexits ngoto nret rret n r t,
      validate_switch default cases t = true ->
      tr_expr c map nil a ns n r ->
-     tr_switch c r nexits t n ->
+     tr_switch c map r nexits t n ->
      tr_stmt c map (Sswitch a cases default) ns nd nexits ngoto nret rret
   | tr_Sreturn_none: forall nret nd nexits ngoto,
      tr_stmt c map (Sreturn None) nret nd nexits ngoto nret None
@@ -1000,9 +1014,9 @@ Qed.
 
 Lemma tr_switch_incr:
   forall s1 s2, state_incr s1 s2 ->
-  forall r nexits t ns,
-  tr_switch s1.(st_code) r nexits t ns ->
-  tr_switch s2.(st_code) r nexits t ns.
+  forall map r nexits t ns,
+  tr_switch s1.(st_code) map r nexits t ns ->
+  tr_switch s2.(st_code) map r nexits t ns.
 Proof.
   induction 2; econstructor; eauto with rtlg.
 Qed.
@@ -1051,24 +1065,47 @@ Proof.
   destruct (nth_error nexits n); intro; monadInv H. auto.
 Qed.
 
+Lemma transl_jumptable_charact:
+  forall nexits tbl s nl s' incr,
+  transl_jumptable nexits tbl s = OK nl s' incr ->
+  tr_jumptable nexits tbl nl /\ s' = s.
+Proof.
+  induction tbl; intros.
+  monadInv H. split. red. simpl. intros. discriminate. auto.
+  monadInv H. exploit transl_exit_charact; eauto. intros [A B]. 
+  exploit IHtbl; eauto. intros [C D].
+  split. red. simpl. intros. destruct (zeq v 0). inv H. exists x; auto. auto.
+  congruence.
+Qed.
+
 Lemma transl_switch_charact:
-  forall r nexits t s ns s' incr,
+  forall map r nexits t s ns s' incr,
+  map_valid map s -> reg_valid r s ->
   transl_switch r nexits t s = OK ns s' incr ->
-  tr_switch s'.(st_code) r nexits t ns.
+  tr_switch s'.(st_code) map r nexits t ns.
 Proof.
   induction t; simpl; intros.
   exploit transl_exit_charact; eauto. intros [A B].
   econstructor; eauto.
 
-  monadInv H.
+  monadInv H1.
   exploit transl_exit_charact; eauto. intros [A B]. subst s1.
   econstructor; eauto with rtlg. 
   apply tr_switch_incr with s0; eauto with rtlg.
 
-  monadInv H.
+  monadInv H1.
   econstructor; eauto with rtlg. 
   apply tr_switch_incr with s1; eauto with rtlg.
   apply tr_switch_incr with s0; eauto with rtlg.
+
+  monadInv H1.
+  exploit transl_jumptable_charact; eauto. intros [A B]. subst s1.
+  econstructor. eauto with rtlg.
+  apply sym_not_equal. apply valid_fresh_different with s; eauto with rtlg.
+  eauto with rtlg. eauto with rtlg. eauto with rtlg. 
+  apply tr_switch_incr with s3. eauto with rtlg.
+  eapply IHt with (s := s2); eauto with rtlg.
+  auto.
 Qed.
  
 Lemma transl_stmt_charact:
@@ -1091,8 +1128,9 @@ Proof.
   apply tr_expr_incr with s3; eauto with rtlg.
   eapply transl_expr_charact; eauto with rtlg. 
   (* Scall *)
-  assert (state_incr s0 s3) by eauto with rtlg.
-  assert (state_incr s3 s6) by eauto with rtlg.
+  assert (state_incr s0 s2) by eauto with rtlg.
+  assert (state_incr s2 s4) by eauto with rtlg.
+  assert (state_incr s4 s6) by eauto with rtlg.
   econstructor; eauto with rtlg.
   eapply transl_expr_charact; eauto with rtlg.
   apply tr_exprlist_incr with s6. auto. 
@@ -1101,7 +1139,6 @@ Proof.
   apply regs_valid_cons; eauto with rtlg.
   apply regs_valid_incr with s1; eauto with rtlg.
   apply regs_valid_cons; eauto with rtlg.
-  apply regs_valid_incr with s2; eauto with rtlg.
   apply tr_store_optvar_incr with s4; eauto with rtlg.
   eapply store_optvar_charact; eauto with rtlg.
   (* Stailcall *)
@@ -1149,7 +1186,7 @@ Proof.
   econstructor; eauto with rtlg.
   eapply transl_expr_charact; eauto with rtlg.
   apply tr_switch_incr with s1; auto with rtlg.
-  eapply transl_switch_charact; eauto with rtlg.
+  eapply transl_switch_charact with (s := s0); eauto with rtlg.
   monadInv TR. 
   (* Sreturn *)
   destruct o; destruct rret; inv TR.
diff --git a/backend/RTLtyping.v b/backend/RTLtyping.v
index 2df9d5df8..86f0eaf10 100644
--- a/backend/RTLtyping.v
+++ b/backend/RTLtyping.v
@@ -112,6 +112,11 @@ Inductive wt_instr : instruction -> Prop :=
       valid_successor s1 ->
       valid_successor s2 ->
       wt_instr (Icond cond args s1 s2)
+  | wt_Ijumptable:
+      forall arg tbl,
+      env arg = Tint ->
+      (forall s, In s tbl -> valid_successor s) ->
+      wt_instr (Ijumptable arg tbl)
   | wt_Ireturn: 
       forall optres,
       option_map env optres = funct.(fn_sig).(sig_res) ->
@@ -224,6 +229,9 @@ Definition check_instr (i: instruction) : bool :=
       check_regs args (type_of_condition cond)
       && check_successor s1
       && check_successor s2
+  | Ijumptable arg tbl =>
+      check_reg arg Tint
+      && List.forallb check_successor tbl
   | Ireturn optres =>
       match optres, funct.(fn_sig).(sig_res) with
       | None, None => true
@@ -326,6 +334,10 @@ Proof.
   constructor. apply check_regs_correct; auto.
   apply check_successor_correct; auto.
   apply check_successor_correct; auto.
+  (* jumptable *)
+  constructor. apply check_reg_correct; auto.
+  rewrite List.forallb_forall in H0. intros. apply check_successor_correct; auto.
+  intros. 
   (* return *)
   constructor. 
   destruct o; simpl; destruct funct.(fn_sig).(sig_res); try discriminate.
@@ -538,6 +550,8 @@ Proof.
   (* Icond *)
   econstructor; eauto.
   econstructor; eauto.
+  (* Ijumptable *)
+  econstructor; eauto.
   (* Ireturn *)
   econstructor; eauto. 
   destruct or; simpl in *.
diff --git a/backend/RTLtypingaux.ml b/backend/RTLtypingaux.ml
index cc7edf491..406ca07a9 100644
--- a/backend/RTLtypingaux.ml
+++ b/backend/RTLtypingaux.ml
@@ -87,6 +87,8 @@ let type_instr retty (Coq_pair(pc, i)) =
       end
   | Icond(cond, args, _, _) ->
       set_types args (type_of_condition cond)
+  | Ijumptable(arg, _) ->
+      set_type arg Tint
   | Ireturn(optres) ->
       begin match optres, retty with
       | None, None -> ()
diff --git a/backend/Reload.v b/backend/Reload.v
index 621e75b57..5728a6283 100644
--- a/backend/Reload.v
+++ b/backend/Reload.v
@@ -242,6 +242,9 @@ Definition transf_instr
   | LTLin.Lcond cond args lbl =>
       let rargs := regs_for args in
       add_reloads args rargs (Lcond cond rargs lbl :: k)
+  | LTLin.Ljumptable arg tbl =>
+      let rarg := reg_for arg in
+      add_reload arg rarg (Ljumptable rarg tbl :: k)
   | LTLin.Lreturn None =>
       Lreturn :: k
   | LTLin.Lreturn (Some loc) =>
diff --git a/backend/Reloadproof.v b/backend/Reloadproof.v
index a7becc36c..21d5f3806 100644
--- a/backend/Reloadproof.v
+++ b/backend/Reloadproof.v
@@ -1257,6 +1257,20 @@ Proof.
   econstructor; eauto with coqlib.
   apply agree_exten with ls; auto.
 
+  (* Ljumptable *)
+  ExploitWT; inv WTI.
+  exploit add_reload_correct_2.
+  intros [ls2 [A [B [C D]]]].
+  left; econstructor; split.
+  eapply plus_right. eauto. eapply exec_Ljumptable; eauto. 
+  assert (Val.lessdef (rs arg) (ls arg)). apply AG. auto.
+  rewrite H in H2. inv H2. congruence.
+  apply find_label_transf_function; eauto.
+  traceEq.
+  econstructor; eauto with coqlib.
+  apply agree_exten with ls; auto.
+  eapply LTLin.find_label_is_tail; eauto.
+
   (* Lreturn *)
   ExploitWT; inv WTI. 
   destruct or; simpl.
diff --git a/backend/Reloadtyping.v b/backend/Reloadtyping.v
index 375bbfde7..df0715ee7 100644
--- a/backend/Reloadtyping.v
+++ b/backend/Reloadtyping.v
@@ -35,7 +35,7 @@ Require Import Reloadproof.
 
 Hint Resolve wt_Lgetstack wt_Lsetstack wt_Lopmove
              wt_Lop wt_Lload wt_Lstore wt_Lcall wt_Ltailcall
-             wt_Llabel wt_Lgoto wt_Lcond wt_Lreturn: reloadty.
+             wt_Llabel wt_Lgoto wt_Lcond wt_Ljumptable wt_Lreturn: reloadty.
 
 Remark wt_code_cons:
   forall f i c, wt_instr f i -> wt_code f c -> wt_code f (i :: c).
@@ -295,6 +295,10 @@ Proof.
     eauto with reloadty.
   auto with reloadty.
 
+  assert (mreg_type (reg_for arg) = Loc.type arg).
+    eauto with reloadty.
+  auto with reloadty.
+
   destruct optres; simpl in *; auto with reloadty.
   apply wt_add_reload; auto with reloadty. 
   unfold loc_result. rewrite <- H1.
diff --git a/backend/Stacking.v b/backend/Stacking.v
index 182c32269..5d9cf3747 100644
--- a/backend/Stacking.v
+++ b/backend/Stacking.v
@@ -185,6 +185,8 @@ Definition transl_instr
       Mgoto lbl :: k
   | Lcond cond args lbl =>
       Mcond cond args lbl :: k
+  | Ljumptable arg tbl =>
+      Mjumptable arg tbl :: k
   | Lreturn =>
       restore_callee_save fe
         (Mreturn :: k)
diff --git a/backend/Stackingproof.v b/backend/Stackingproof.v
index 5b6f2dc7b..ba4295895 100644
--- a/backend/Stackingproof.v
+++ b/backend/Stackingproof.v
@@ -1510,6 +1510,15 @@ Proof.
   rewrite <- (agree_eval_regs _ _ _ _ _ _ _ args AG) in H; auto.
   econstructor; eauto with coqlib.
 
+  (* Ljumptable *)
+  econstructor; split.
+  apply plus_one; eapply exec_Mjumptable.
+  rewrite <- (agree_eval_reg _ _ _ _ _ _ _ arg AG) in H; eauto.
+  eauto. 
+  apply transl_find_label; eauto.
+  econstructor; eauto.
+  eapply find_label_incl; eauto.
+
   (* Lreturn *)
   exploit restore_callee_save_correct; eauto.
   intros [ls' [A [B C]]].
diff --git a/backend/Stackingtyping.v b/backend/Stackingtyping.v
index 1bafc35b1..8ba5caedb 100644
--- a/backend/Stackingtyping.v
+++ b/backend/Stackingtyping.v
@@ -185,6 +185,9 @@ Proof.
   (* cond *)
   apply wt_instrs_cons; auto.
   constructor; auto.
+  (* jumptable *)
+  apply wt_instrs_cons; auto.
+  constructor; auto.
   (* return *)
   apply wt_restore_callee_save. apply wt_instrs_cons. constructor. auto.
 Qed.
diff --git a/backend/Tailcallproof.v b/backend/Tailcallproof.v
index 1423e1e01..8681d84ad 100644
--- a/backend/Tailcallproof.v
+++ b/backend/Tailcallproof.v
@@ -630,6 +630,13 @@ Proof.
   apply eval_condition_lessdef with (rs##args); auto. apply regset_get_list; auto.
   constructor; auto. 
 
+(* jumptable *)
+  TransfInstr. 
+  left. exists (State s' (fn_code (transf_function f)) (Vptr sp0 Int.zero) pc' rs' m'); split.
+  eapply exec_Ijumptable; eauto.
+  generalize (RLD arg). rewrite H0. intro. inv H2. auto.
+  constructor; auto. 
+
 (* return *)
   TransfInstr.
   left. exists (Returnstate s' (regmap_optget or Vundef rs') (free m' stk)); split.
diff --git a/backend/Tunneling.v b/backend/Tunneling.v
index ef55a1572..3ad8c4d05 100644
--- a/backend/Tunneling.v
+++ b/backend/Tunneling.v
@@ -106,6 +106,8 @@ Definition tunnel_instr (uf: U.t) (b: instruction) : instruction :=
       Ltailcall sig ros args
   | Lcond cond args s1 s2 =>
       Lcond cond args (U.repr uf s1) (U.repr uf s2)
+  | Ljumptable arg tbl =>
+      Ljumptable arg (List.map (U.repr uf) tbl)
   | Lreturn or =>
       Lreturn or
   end.
diff --git a/backend/Tunnelingproof.v b/backend/Tunnelingproof.v
index eccb62dd4..92ec68cf7 100644
--- a/backend/Tunnelingproof.v
+++ b/backend/Tunnelingproof.v
@@ -315,6 +315,13 @@ Proof.
   eapply exec_Lcond_false; eauto.
   rewrite (tunnel_function_lookup _ _ _ H); simpl; eauto.
   econstructor; eauto.
+  (* jumptable *)
+  generalize (record_gotos_correct f pc); rewrite H; intro A; rewrite A.
+  left; econstructor; split.
+  eapply exec_Ljumptable. 
+  rewrite (tunnel_function_lookup _ _ _ H); simpl; eauto.
+  eauto. rewrite list_nth_z_map. change U.elt with node. rewrite H1. reflexivity. 
+  econstructor; eauto. 
   (* return *)
   generalize (record_gotos_correct f pc); rewrite H; intro A; rewrite A.
   left; econstructor; split.
diff --git a/backend/Tunnelingtyping.v b/backend/Tunnelingtyping.v
index 91745dfbe..8990cb44a 100644
--- a/backend/Tunnelingtyping.v
+++ b/backend/Tunnelingtyping.v
@@ -74,7 +74,9 @@ Lemma wt_tunnel_instr:
   wt_instr f i -> wt_instr (tunnel_function f) (tunnel_instr (record_gotos f) i).
 Proof.
   intros; inv H0; simpl; econstructor; eauto;
-  eapply branch_target_valid; eauto.
+  try (eapply branch_target_valid; eauto).
+  intros. exploit list_in_map_inv; eauto. intros [x [A B]]. subst lbl.
+  eapply branch_target_valid; eauto. 
 Qed.
 
 Lemma wt_tunnel_function:
diff --git a/common/Switch.v b/common/Switch.v
index 179d4d2ee..ee8f6aa8f 100644
--- a/common/Switch.v
+++ b/common/Switch.v
@@ -13,12 +13,18 @@
 (*                                                                     *)
 (* *********************************************************************)
 
-(** Multi-way branches (``[switch]'') and their compilation
-    to 2-way comparison trees. *)
+(** Multi-way branches (``switch'' statements) and their compilation
+    to comparison trees. *)
 
 Require Import EqNat.
+Require Import FMaps.
+Require FMapAVL.
 Require Import Coqlib.
 Require Import Integers.
+Require Import Ordered.
+
+Module IntMap := FMapAVL.Make(OrderedInt).
+Module IntMapF := FMapFacts.Facts(IntMap).
 
 (** A multi-way branch is composed of a list of (key, action) pairs,
   plus a default action.  *)
@@ -33,22 +39,29 @@ Fixpoint switch_target (n: int) (dfl: nat) (cases: table)
       if Int.eq n key then action else switch_target n dfl rem
   end.
 
-(** Multi-way branches are translated to a 2-way comparison tree.
-    Each node of the tree performs an equality test or a less-than
-    test against one of the keys. *)
+(** Multi-way branches are translated to comparison trees.
+    Each node of the tree performs either
+- an equality against one of the keys;
+- or a "less than" test against one of the keys;
+- or a computed branch (jump table) against a range of key values. *)
 
 Inductive comptree : Type :=
   | CTaction: nat -> comptree
   | CTifeq: int -> nat -> comptree -> comptree
-  | CTiflt: int -> comptree -> comptree -> comptree.
+  | CTiflt: int -> comptree -> comptree -> comptree
+  | CTjumptable: int -> int -> list nat -> comptree -> comptree.
 
-Fixpoint comptree_match (n: int) (t: comptree) {struct t}: nat :=
+Fixpoint comptree_match (n: int) (t: comptree) {struct t}: option nat :=
   match t with
-  | CTaction act => act
+  | CTaction act => Some act
   | CTifeq key act t' =>
-      if Int.eq n key then act else comptree_match n t'
+      if Int.eq n key then Some act else comptree_match n t'
   | CTiflt key t1 t2 =>
       if Int.ltu n key then comptree_match n t1 else comptree_match n t2
+  | CTjumptable ofs sz tbl t' =>
+      if Int.ltu (Int.sub n ofs) sz
+      then list_nth_z tbl (Int.signed (Int.sub n ofs))
+      else comptree_match n t'
   end.
 
 (** The translation from a table to a comparison tree is performed
@@ -80,12 +93,32 @@ Fixpoint split_eq (pivot: int) (cases: table)
       else (same, (key, act) :: others)
   end.
 
+Fixpoint split_between (ofs sz: int) (cases: table)
+                       {struct cases} : IntMap.t nat * table :=
+  match cases with
+  | nil => (IntMap.empty nat, nil)
+  | (key, act) :: rem =>
+      let (inside, outside) := split_between ofs sz rem in
+      if Int.ltu (Int.sub key ofs) sz
+      then (IntMap.add key act inside, outside)
+      else (inside, (key, act) :: outside)
+  end.
+
 Definition refine_low_bound (v lo: Z) :=
   if zeq v lo then lo + 1 else lo.
 
 Definition refine_high_bound (v hi: Z) :=
   if zeq v hi then hi - 1 else hi.
 
+Fixpoint validate_jumptable (cases: IntMap.t nat) (default: nat)
+                            (tbl: list nat) (n: int) {struct tbl} : bool :=
+  match tbl with
+  | nil => true
+  | act :: rem =>
+      beq_nat act (match IntMap.find n cases with Some a => a | None => default end)
+      && validate_jumptable cases default rem (Int.add n Int.one)
+  end.
+
 Fixpoint validate (default: nat) (cases: table) (t: comptree)
                   (lo hi: Z) {struct t} : bool :=
   match t with
@@ -112,6 +145,15 @@ Fixpoint validate (default: nat) (cases: table) (t: comptree)
           validate default lcases t1 lo (Int.unsigned pivot - 1)
           && validate default rcases t2 (Int.unsigned pivot) hi
       end
+  | CTjumptable ofs sz tbl t' =>
+      let tbl_len := list_length_z tbl in
+      match split_between ofs sz cases with
+      | (inside, outside) =>
+          zle (Int.unsigned sz) tbl_len
+          && zle tbl_len Int.max_signed
+          && validate_jumptable inside default tbl ofs
+          && validate default outside t' lo hi
+     end
   end.
 
 Definition validate_switch (default: nat) (cases: table) (t: comptree) :=
@@ -163,11 +205,78 @@ Proof.
   auto.
 Qed.
 
+Lemma split_between_prop:
+  forall v default ofs sz cases inside outside,
+  split_between ofs sz cases = (inside, outside) ->
+  switch_target v default cases =
+    (if Int.ltu (Int.sub v ofs) sz
+     then match IntMap.find v inside with Some a => a | None => default end
+     else switch_target v default outside).
+Proof.
+  induction cases; intros until outside; simpl.
+  intros. inv H. simpl. destruct (Int.ltu (Int.sub v ofs) sz); auto.
+  destruct a as [key act]. case_eq (split_between ofs sz cases). intros ins outs SEQ.
+  rewrite (IHcases _ _ SEQ). 
+  case_eq (Int.ltu (Int.sub key ofs) sz); intros; inv H0; simpl.
+  rewrite IntMapF.add_o. 
+  predSpec Int.eq Int.eq_spec v key. 
+  subst v. rewrite H. rewrite dec_eq_true. auto.
+  rewrite dec_eq_false; auto.
+  case_eq (Int.ltu (Int.sub v ofs) sz); intros; auto.
+  predSpec Int.eq Int.eq_spec v key. 
+  subst v. congruence.
+  auto.
+Qed.
+
+Lemma validate_jumptable_correct_rec:
+  forall cases default tbl base v,
+  validate_jumptable cases default tbl base = true ->
+  0 <= Int.signed v < list_length_z tbl -> Int.signed v <= Int.max_signed ->
+  list_nth_z tbl (Int.signed v) =
+  Some(match IntMap.find (Int.add base v) cases with Some a => a | None => default end).
+Proof.
+  induction tbl; intros until v; simpl.
+  unfold list_length_z; simpl. intros. omegaContradiction.
+  rewrite list_length_z_cons. intros. destruct (andb_prop _ _ H). clear H.
+  generalize (beq_nat_eq _ _ (sym_equal H2)). clear H2. intro. subst a.
+  destruct (zeq (Int.signed v) 0).
+  rewrite Int.add_signed. rewrite e. rewrite Zplus_0_r. rewrite Int.repr_signed. auto.
+  assert (Int.signed (Int.sub v Int.one) = Int.signed v - 1).
+    rewrite Int.sub_signed. change (Int.signed Int.one) with 1. 
+    apply Int.signed_repr. split. apply Zle_trans with 0. 
+    vm_compute; congruence. omega. omega.
+    replace (Int.add base v) with (Int.add (Int.add base Int.one) (Int.sub v Int.one)).
+  rewrite <- IHtbl. rewrite H. auto. auto. rewrite H. omega. 
+  rewrite H. omega. 
+  rewrite Int.sub_add_opp. rewrite Int.add_permut. rewrite Int.add_assoc. 
+  replace (Int.add Int.one (Int.neg Int.one)) with Int.zero.
+  rewrite Int.add_zero. apply Int.add_commut.
+  apply Int.mkint_eq. reflexivity.
+Qed.
+
+Lemma validate_jumptable_correct:
+  forall cases default tbl ofs v sz,
+  validate_jumptable cases default tbl ofs = true ->
+  Int.ltu (Int.sub v ofs) sz = true ->
+  Int.unsigned sz <= list_length_z tbl <= Int.max_signed ->
+  list_nth_z tbl (Int.signed (Int.sub v ofs)) =
+  Some(match IntMap.find v cases with Some a => a | None => default end).
+Proof.
+  intros.
+  exploit Int.ltu_range_test; eauto. omega. intros. 
+  rewrite (validate_jumptable_correct_rec cases default tbl ofs).
+  rewrite Int.sub_add_opp. rewrite Int.add_permut. rewrite <- Int.sub_add_opp. 
+  rewrite Int.sub_idem. rewrite Int.add_zero. auto. 
+  auto.
+  omega. 
+  omega.
+Qed.
+
 Lemma validate_correct_rec:
   forall default v t cases lo hi,
   validate default cases t lo hi = true ->
   lo <= Int.unsigned v <= hi ->
-  switch_target v default cases = comptree_match v t.
+  comptree_match v t = Some (switch_target v default cases).
 Proof.
   induction t; simpl; intros until hi.
   (* base case *)
@@ -187,7 +296,7 @@ Proof.
   intros. destruct (andb_prop _ _ H). clear H.
   rewrite (split_eq_prop v default _ _ _ _ EQ).
   predSpec Int.eq Int.eq_spec v i.
-  symmetry. apply beq_nat_eq; auto.
+  f_equal. apply beq_nat_eq; auto.
   eapply IHt. eauto.
   assert (Int.unsigned v <> Int.unsigned i).
     rewrite <- (Int.repr_unsigned v) in H.
@@ -203,11 +312,21 @@ Proof.
   unfold Int.ltu. destruct (zlt (Int.unsigned v) (Int.unsigned i)).
   eapply IHt1. eauto. omega.
   eapply IHt2. eauto. omega.
+  (* jumptable node *)
+  case_eq (split_between i i0 cases). intros ins outs EQ V RANGE.
+  destruct (andb_prop _ _ V). clear V.
+  destruct (andb_prop _ _ H). clear H.
+  destruct (andb_prop _ _ H1). clear H1.
+  rewrite (split_between_prop v _ _ _ _ _ _ EQ).
+  case_eq (Int.ltu (Int.sub v i) i0); intros.
+  eapply validate_jumptable_correct; eauto. 
+  split; eapply proj_sumbool_true; eauto.
+  eapply IHt; eauto. 
 Qed.
 
 Definition table_tree_agree
     (default: nat) (cases: table) (t: comptree) : Prop :=
-  forall v, switch_target v default cases = comptree_match v t.
+  forall v, comptree_match v t = Some(switch_target v default cases).
 
 Theorem validate_switch_correct:
   forall default t cases,
diff --git a/lib/Coqlib.v b/lib/Coqlib.v
index 416afa9cb..7bc4f8bf5 100644
--- a/lib/Coqlib.v
+++ b/lib/Coqlib.v
@@ -612,6 +612,80 @@ Proof.
 Qed.
 Hint Resolve nth_error_nil: coqlib.
 
+(** Compute the length of a list, with result in [Z]. *)
+
+Fixpoint list_length_z_aux (A: Type) (l: list A) (acc: Z) {struct l}: Z :=
+  match l with
+  | nil => acc
+  | hd :: tl => list_length_z_aux tl (Zsucc acc)
+  end.
+
+Remark list_length_z_aux_shift:
+  forall (A: Type) (l: list A) n m,
+  list_length_z_aux l n = list_length_z_aux l m + (n - m).
+Proof.
+  induction l; intros; simpl.
+  omega.
+  replace (n - m) with (Zsucc n - Zsucc m) by omega. auto.
+Qed.
+
+Definition list_length_z (A: Type) (l: list A) : Z :=
+  list_length_z_aux l 0.
+
+Lemma list_length_z_cons:
+  forall (A: Type) (hd: A) (tl: list A),
+  list_length_z (hd :: tl) = list_length_z tl + 1.
+Proof.
+  intros. unfold list_length_z. simpl.
+  rewrite (list_length_z_aux_shift tl 1 0). omega. 
+Qed.
+
+Lemma list_length_z_pos:
+  forall (A: Type) (l: list A),
+  list_length_z l >= 0.
+Proof.
+  induction l; simpl. unfold list_length_z; simpl. omega. 
+  rewrite list_length_z_cons. omega.
+Qed.
+
+(** Extract the n-th element of a list, as [List.nth_error] does,
+    but the index [n] is of type [Z]. *)
+
+Fixpoint list_nth_z (A: Type) (l: list A) (n: Z) {struct l}: option A :=
+  match l with
+  | nil => None
+  | hd :: tl => if zeq n 0 then Some hd else list_nth_z tl (Zpred n)
+  end.
+
+Lemma list_nth_z_in:
+  forall (A: Type) (l: list A) n x,
+  list_nth_z l n = Some x -> In x l.
+Proof.
+  induction l; simpl; intros. 
+  congruence.
+  destruct (zeq n 0). left; congruence. right; eauto.
+Qed.
+
+Lemma list_nth_z_map:
+  forall (A B: Type) (f: A -> B) (l: list A) n,
+  list_nth_z (List.map f l) n = option_map f (list_nth_z l n).
+Proof.
+  induction l; simpl; intros.
+  auto.
+  destruct (zeq n 0). auto. eauto.
+Qed.
+
+Lemma list_nth_z_range:
+  forall (A: Type) (l: list A) n x,
+  list_nth_z l n = Some x -> 0 <= n < list_length_z l.
+Proof.
+  induction l; simpl; intros.
+  discriminate.
+  rewrite list_length_z_cons. destruct (zeq n 0).
+  generalize (list_length_z_pos l); omega.
+  exploit IHl; eauto. unfold Zpred. omega. 
+Qed.
+
 (** Properties of [List.incl] (list inclusion). *)
 
 Lemma incl_cons_inv:
diff --git a/lib/Integers.v b/lib/Integers.v
index 1eb59c5c5..c54b6fe5d 100644
--- a/lib/Integers.v
+++ b/lib/Integers.v
@@ -657,6 +657,13 @@ Proof.
   apply eqm_samerepr. unfold z'; red. exists 1. omega.
 Qed.
 
+Theorem signed_eq_unsigned:
+  forall x, unsigned x <= max_signed -> signed x = unsigned x.
+Proof.
+  intros. unfold signed. destruct (zlt (unsigned x) half_modulus).
+  auto. unfold max_signed in H. omegaContradiction.
+Qed.
+
 (** ** Properties of addition *)
 
 Theorem add_unsigned: forall x y, add x y = repr (unsigned x + unsigned y).
@@ -786,6 +793,13 @@ Proof.
   symmetry. apply sub_add_opp.
 Qed.
 
+Theorem sub_signed:
+  forall x y, sub x y = repr (signed x - signed y).
+Proof.
+  intros. unfold sub. apply eqm_samerepr.
+  apply eqm_sub; apply eqm_sym; apply eqm_signed_unsigned.
+Qed.
+
 (** ** Properties of multiplication *)
 
 Theorem mul_commut: forall x y, mul x y = mul y x.
@@ -2565,4 +2579,15 @@ Proof.
   omega. 
 Qed.
 
+Theorem ltu_range_test:
+  forall x y,
+  ltu x y = true -> unsigned y <= max_signed ->
+  0 <= signed x < unsigned y.
+Proof.
+  intros.
+  unfold Int.ltu in H. destruct (zlt (unsigned x) (unsigned y)); try discriminate.
+  rewrite signed_eq_unsigned.
+  generalize (unsigned_range x). omega. omega.
+Qed.
+
 End Int.
diff --git a/lib/Ordered.v b/lib/Ordered.v
index eddc37213..1c7c7f43f 100644
--- a/lib/Ordered.v
+++ b/lib/Ordered.v
@@ -11,11 +11,12 @@
 (* *********************************************************************)
 
 (** Constructions of ordered types, for use with the [FSet] functors
-  for finite sets. *)
+  for finite sets and the [FMap] functors for finite maps. *)
 
 Require Import FSets.
 Require Import Coqlib.
 Require Import Maps.
+Require Import Integers.
 
 (** The ordered type of positive numbers *)
 
@@ -49,6 +50,44 @@ Definition eq_dec : forall x y, { eq x y } + { ~ eq x y } := peq.
 
 End OrderedPositive.
 
+(** The ordered type of machine integers *)
+
+Module OrderedInt <: OrderedType.
+
+Definition t := int.
+Definition eq (x y: t) := x = y.
+Definition lt (x y: t) := Int.unsigned x < Int.unsigned y.
+
+Lemma eq_refl : forall x : t, eq x x.
+Proof (@refl_equal t). 
+Lemma eq_sym : forall x y : t, eq x y -> eq y x.
+Proof (@sym_equal t).
+Lemma eq_trans : forall x y z : t, eq x y -> eq y z -> eq x z.
+Proof (@trans_equal t).
+Lemma lt_trans : forall x y z : t, lt x y -> lt y z -> lt x z.
+Proof.
+  unfold lt; intros. omega.
+Qed.
+Lemma lt_not_eq : forall x y : t, lt x y -> ~ eq x y.
+Proof.
+  unfold lt,eq; intros; red; intros. subst. omega.
+Qed.
+Lemma compare : forall x y : t, Compare lt eq x y.
+Proof.
+  intros. destruct (zlt (Int.unsigned x) (Int.unsigned y)).
+  apply LT. auto.
+  destruct (Int.eq_dec x y).
+  apply EQ. auto.
+  apply GT.
+  assert (Int.unsigned x <> Int.unsigned y).
+    red; intros. rewrite <- (Int.repr_unsigned x) in n. rewrite <- (Int.repr_unsigned y) in n. congruence.
+  red. omega.
+Qed.
+
+Definition eq_dec : forall x y, { eq x y } + { ~ eq x y } := Int.eq_dec.
+
+End OrderedInt.
+
 (** Indexed types (those that inject into [positive]) are ordered. *)
 
 Module OrderedIndexed(A: INDEXED_TYPE) <: OrderedType.
diff --git a/powerpc/Asm.v b/powerpc/Asm.v
index 0e6032fe7..18dc93aba 100644
--- a/powerpc/Asm.v
+++ b/powerpc/Asm.v
@@ -115,6 +115,7 @@ Inductive instruction : Type :=
   | Pbs: ident -> instruction                                 (**r branch to symbol *)
   | Pblr: instruction                                         (**r branch to contents of register LR *)
   | Pbt: crbit -> label -> instruction                        (**r branch if true *)
+  | Pbtbl: ireg -> list label -> instruction                  (**r N-way branch through a jump table *)
   | Pcmplw: ireg -> ireg -> instruction                       (**r unsigned integer comparison *)
   | Pcmplwi: ireg -> constant -> instruction                  (**r same, with immediate argument *)
   | Pcmpw: ireg -> ireg -> instruction                        (**r signed integer comparison *)
@@ -196,8 +197,8 @@ Inductive instruction : Type :=
   Expands to a float load [lfd] from an address in the constant data section
   initialized with the floating-point constant:
 <<
-        addis   r2, 0, ha16(lbl)
-        lfd     rdst, lo16(lbl)(r2)
+        addis   r12, 0, ha16(lbl)
+        lfd     rdst, lo16(lbl)(r12)
         .const_data
 lbl:    .double floatcst
         .text
@@ -218,8 +219,8 @@ lbl:    .double floatcst
   constant [2^31], subtract [2^31] if bigger, then convert to a signed
   integer as above, then add back [2^31] if needed.  Expands to:
 <<
-        addis   r2, 0, ha16(lbl1)
-        lfd     f13, lo16(lbl1)(r2)
+        addis   r12, 0, ha16(lbl1)
+        lfd     f13, lo16(lbl1)(r12)
         fcmpu   cr7, rsrc, f13
         cror    30, 29, 30
         beq     cr7, lbl2
@@ -242,12 +243,12 @@ lbl1:   .long   0x41e00000, 0x00000000    # 2^31 in double precision
   arithmetic over a memory word, which our memory model and axiomatization
   of floats cannot express.  Expands to:
 <<
-        addis   r2, 0, 0x4330
-        stwu    r2, -8(r1)
-        addis   r2, rsrc, 0x8000
-        stw     r2, 4(r1)
-        addis   r2, 0, ha16(lbl)
-        lfd     f13, lo16(lbl)(r2)
+        addis   r12, 0, 0x4330
+        stwu    r12, -8(r1)
+        addis   r12, rsrc, 0x8000
+        stw     r12, 4(r1)
+        addis   r12, 0, ha16(lbl)
+        lfd     f13, lo16(lbl)(r12)
         lfd     rdst, 0(r1)
         addi    r1, r1, 8
         fsub    rdst, rdst, f13
@@ -260,11 +261,11 @@ lbl:    .long   0x43300000, 0x80000000
 - [Piuctf]: convert an unsigned integer to a float.  The expansion is close
   to that [Pictf], and equally obscure.
 <<
-        addis   r2, 0, 0x4330
-        stwu    r2, -8(r1)
+        addis   r12, 0, 0x4330
+        stwu    r12, -8(r1)
         stw     rsrc, 4(r1)
-        addis   r2, 0, ha16(lbl)
-        lfd     f13, lo16(lbl)(r2)
+        addis   r12, 0, ha16(lbl)
+        lfd     f13, lo16(lbl)(r12)
         lfd     rdst, 0(r1)
         addi    r1, r1, 8
         fsub    rdst, rdst, f13
@@ -294,6 +295,18 @@ lbl:    .long   0x43300000, 0x00000000
 >>
   Again, our memory model cannot comprehend that this operation
   frees (logically) the current stack frame.
+- [Pbtbl reg table]: this is a N-way branch, implemented via a jump table
+  as follows:
+<<
+        rlwinm  r12, reg, 2, 0, 29
+        addis   r12, r12, ha16(lbl)
+        lwz     r12, lo16(lbl)(r12)
+        mtctr   r12
+        bctr    r12
+        .const_data
+lbl:    .long   table[0], table[1], ...
+        .text
+>>
 *)
 
 Definition code := list instruction.
@@ -608,6 +621,15 @@ Definition exec_instr (c: code) (i: instruction) (rs: regset) (m: mem) : outcome
       | Vint n => if Int.eq n Int.zero then OK (nextinstr rs) m else goto_label c lbl rs m
       | _ => Error
       end
+  | Pbtbl r tbl =>
+      match rs#r with
+      | Vint n => 
+          match list_nth_z tbl (Int.signed n) with
+          | None => Error
+          | Some lbl => goto_label c lbl (rs #GPR12 <- Vundef #CTR <- Vundef) m
+          end
+      | _ => Error
+      end
   | Pcmplw r1 r2 =>
       OK (nextinstr (compare_uint rs rs#r1 rs#r2)) m
   | Pcmplwi r1 cst =>
diff --git a/powerpc/Asmgen.v b/powerpc/Asmgen.v
index aebb48346..4beabb1c8 100644
--- a/powerpc/Asmgen.v
+++ b/powerpc/Asmgen.v
@@ -502,6 +502,8 @@ Definition transl_instr (f: Mach.function) (i: Mach.instruction) (k: code) :=
       let p := crbit_for_cond cond in
       transl_cond cond args
         (if (snd p) then Pbt (fst p) lbl :: k else Pbf (fst p) lbl :: k)
+  | Mjumptable arg tbl =>
+      Pbtbl (ireg_of arg) tbl :: k
   | Mreturn =>
       Plwz GPR12 (Cint f.(fn_retaddr_ofs)) GPR1 ::
       Pmtlr GPR12 ::
@@ -523,17 +525,11 @@ Definition transl_function (f: Mach.function) :=
   Pstw GPR12 (Cint f.(fn_retaddr_ofs)) GPR1 ::
   transl_code f f.(fn_code).
 
-Fixpoint code_size (c: code) : Z :=
-  match c with
-  | nil => 0
-  | instr :: c' => code_size c' + 1
-  end.
-
 Open Local Scope string_scope.
 
 Definition transf_function (f: Mach.function) : res Asm.code :=
   let c := transl_function f in
-  if zlt Int.max_unsigned (code_size c)
+  if zlt Int.max_unsigned (list_length_z c)
   then Errors.Error (msg "code size exceeded")
   else Errors.OK c.
 
diff --git a/powerpc/Asmgenproof.v b/powerpc/Asmgenproof.v
index 2710eddde..4e45c8eae 100644
--- a/powerpc/Asmgenproof.v
+++ b/powerpc/Asmgenproof.v
@@ -65,19 +65,19 @@ Proof.
   intros. 
   destruct (functions_translated _ _ H) as [tf [A B]].
   rewrite A. generalize B. unfold transf_fundef, transf_partial_fundef, transf_function.
-  case (zlt Int.max_unsigned (code_size (transl_function f))); simpl; intro.
+  case (zlt Int.max_unsigned (list_length_z (transl_function f))); simpl; intro.
   congruence. intro. inv B0. auto.
 Qed.
 
 Lemma functions_transl_no_overflow:
   forall b f,
   Genv.find_funct_ptr ge b = Some (Internal f) ->
-  code_size (transl_function f) <= Int.max_unsigned.
+  list_length_z (transl_function f) <= Int.max_unsigned.
 Proof.
   intros. 
   destruct (functions_translated _ _ H) as [tf [A B]].
   generalize B. unfold transf_fundef, transf_partial_fundef, transf_function.
-  case (zlt Int.max_unsigned (code_size (transl_function f))); simpl; intro.
+  case (zlt Int.max_unsigned (list_length_z (transl_function f))); simpl; intro.
   congruence. intro; omega.
 Qed.
 
@@ -105,21 +105,23 @@ Proof.
   eauto.
 Qed.
 
+(*
 Remark code_size_pos:
   forall fn, code_size fn >= 0.
 Proof.
   induction fn; simpl; omega.
 Qed.
+*)
 
 Remark code_tail_bounds:
   forall fn ofs i c,
-  code_tail ofs fn (i :: c) -> 0 <= ofs < code_size fn.
+  code_tail ofs fn (i :: c) -> 0 <= ofs < list_length_z fn.
 Proof.
   assert (forall ofs fn c, code_tail ofs fn c ->
-          forall i c', c = i :: c' -> 0 <= ofs < code_size fn).
+          forall i c', c = i :: c' -> 0 <= ofs < list_length_z fn).
   induction 1; intros; simpl. 
-  rewrite H. simpl. generalize (code_size_pos c'). omega.
-  generalize (IHcode_tail _ _ H0). omega.
+  rewrite H. rewrite list_length_z_cons. generalize (list_length_z_pos c'). omega.
+  rewrite list_length_z_cons. generalize (IHcode_tail _ _ H0). omega.
   eauto.
 Qed.
 
@@ -138,7 +140,7 @@ Qed.
 
 Lemma code_tail_next_int:
   forall fn ofs i c,
-  code_size fn <= Int.max_unsigned ->
+  list_length_z fn <= Int.max_unsigned ->
   code_tail (Int.unsigned ofs) fn (i :: c) ->
   code_tail (Int.unsigned (Int.add ofs Int.one)) fn c.
 Proof.
@@ -167,7 +169,7 @@ Inductive transl_code_at_pc: val -> block -> Mach.function -> Mach.code -> Prop
 Lemma exec_straight_steps_1:
   forall fn c rs m c' rs' m',
   exec_straight tge fn c rs m c' rs' m' ->
-  code_size fn <= Int.max_unsigned ->
+  list_length_z fn <= Int.max_unsigned ->
   forall b ofs,
   rs#PC = Vptr b ofs ->
   Genv.find_funct_ptr tge b = Some (Internal fn) ->
@@ -191,7 +193,7 @@ Qed.
 Lemma exec_straight_steps_2:
   forall fn c rs m c' rs' m',
   exec_straight tge fn c rs m c' rs' m' ->
-  code_size fn <= Int.max_unsigned ->
+  list_length_z fn <= Int.max_unsigned ->
   forall b ofs,
   rs#PC = Vptr b ofs ->
   Genv.find_funct_ptr tge b = Some (Internal fn) ->
@@ -284,7 +286,7 @@ Lemma label_pos_code_tail:
   exists pos',
   label_pos lbl pos c = Some pos' 
   /\ code_tail (pos' - pos) c c'
-  /\ pos < pos' <= pos + code_size c.
+  /\ pos < pos' <= pos + list_length_z c.
 Proof.
   induction c. 
   simpl; intros. discriminate.
@@ -293,12 +295,12 @@ Proof.
   intro EQ; injection EQ; intro; subst c'.
   exists (pos + 1). split. auto. split.
   replace (pos + 1 - pos) with (0 + 1) by omega. constructor. constructor. 
-  generalize (code_size_pos c). omega. 
+  rewrite list_length_z_cons. generalize (list_length_z_pos c). omega. 
   intros. generalize (IHc (pos + 1) c' H). intros [pos' [A [B C]]].
   exists pos'. split. auto. split.
   replace (pos' - pos) with ((pos' - (pos + 1)) + 1) by omega.
   constructor. auto. 
-  omega.
+  rewrite list_length_z_cons. omega.
 Qed.
 
 (** The following lemmas show that the translation from Mach to PPC
@@ -863,7 +865,7 @@ Proof.
   generalize (wt_function_instrs _ WTF _ (INCL _ (in_eq _ _))).
   intro WTI. inversion WTI.
   inv AT. 
-  assert (NOOV: code_size (transl_function f) <= Int.max_unsigned).
+  assert (NOOV: list_length_z (transl_function f) <= Int.max_unsigned).
     eapply functions_transl_no_overflow; eauto.
   destruct ros; simpl in H; simpl transl_code in H7.
   (* Indirect call *)
@@ -940,7 +942,7 @@ Proof.
   generalize (wt_function_instrs _ WTF _ (INCL _ (in_eq _ _))).
   intro WTI. inversion WTI.
   inversion AT. subst b f0 c0.
-  assert (NOOV: code_size (transl_function f) <= Int.max_unsigned).
+  assert (NOOV: list_length_z (transl_function f) <= Int.max_unsigned).
     eapply functions_transl_no_overflow; eauto.
   destruct ros; simpl in H; simpl in H9.
   (* Indirect call *)
@@ -1127,6 +1129,40 @@ Proof.
   auto with ppcgen.
 Qed.
 
+Lemma exec_Mjumptable_prop:
+  forall (s : list stackframe) (fb : block) (f : function) (sp : val)
+         (arg : mreg) (tbl : list Mach.label) (c : list Mach.instruction)
+         (rs : mreg -> val) (m : mem) (n : int) (lbl : Mach.label)
+         (c' : Mach.code),
+  rs arg = Vint n ->
+  list_nth_z tbl (Int.signed n) = Some lbl ->
+  Genv.find_funct_ptr ge fb = Some (Internal f) ->
+  Mach.find_label lbl (fn_code f) = Some c' ->
+  exec_instr_prop
+    (Machconcr.State s fb sp (Mjumptable arg tbl :: c) rs m) E0
+    (Machconcr.State s fb sp c' rs m).
+Proof.
+  intros; red; intros; inv MS.
+  assert (f0 = f) by congruence. subst f0.
+  generalize (wt_function_instrs _ WTF _ (INCL _ (in_eq _ _))).
+  intro WTI. inv WTI.
+  pose (rs1 := rs0 # GPR12 <- Vundef # CTR <- Vundef).
+  inv AT. simpl in H6.
+  assert (rs1 PC = Vptr fb ofs). rewrite H3. reflexivity.
+  generalize (functions_transl _ _ H1); intro FN.
+  generalize (functions_transl_no_overflow _ _ H1); intro NOOV.
+  exploit find_label_goto_label; eauto. intros [rs2 [A [B C]]].
+  left; exists (State rs2 m); split.
+  apply plus_one. econstructor. symmetry; eauto. eauto.
+  eapply find_instr_tail. eauto. 
+  simpl. rewrite (ireg_val _ _ _ _ AG H4) in H. rewrite H. 
+  change label with Mach.label; rewrite H0. eexact A. 
+  econstructor; eauto. 
+  eapply Mach.find_label_incl; eauto.
+  apply agree_exten_2 with rs1; auto.
+  unfold rs1. repeat apply agree_set_other; auto with ppcgen.
+Qed.
+
 Lemma exec_Mreturn_prop:
   forall (s : list stackframe) (fb stk : block) (soff : int)
          (c : list Mach.instruction) (ms : Mach.regset) (m : mem) (f: Mach.function),
@@ -1292,6 +1328,7 @@ Proof
            exec_Mgoto_prop
            exec_Mcond_true_prop
            exec_Mcond_false_prop
+           exec_Mjumptable_prop
            exec_Mreturn_prop
            exec_function_internal_prop
            exec_function_external_prop
diff --git a/powerpc/PrintAsm.ml b/powerpc/PrintAsm.ml
index 539d9894e..df1b06293 100644
--- a/powerpc/PrintAsm.ml
+++ b/powerpc/PrintAsm.ml
@@ -261,6 +261,17 @@ let print_instruction oc labels = function
       fprintf oc "	blr\n"
   | Pbt(bit, lbl) ->
       fprintf oc "	bt	%a, %a\n" crbit bit label (transl_label lbl)
+  | Pbtbl(r, tbl) ->
+      let lbl = new_label() in
+      fprintf oc "	rlwinm	%a, %a, 2, 0, 29\n" ireg GPR12 ireg r;
+      fprintf oc "	addis	%a, %a, %a\n" ireg GPR12 ireg GPR12 label_high lbl;
+      fprintf oc "	lwz	%a, %a(%a)\n" ireg GPR12 label_low lbl ireg GPR12;
+      fprintf oc "	mtctr	%a\n" ireg GPR12;
+      fprintf oc "	bctr\n";
+      fprintf oc "%a:" label lbl;
+      List.iter
+        (fun l -> fprintf oc "	.long	%a\n" label (transl_label l))
+        tbl
   | Pcmplw(r1, r2) ->
       fprintf oc "	cmplw	%a, %a, %a\n" creg 0 ireg r1 ireg r2
   | Pcmplwi(r1, c) ->
@@ -472,11 +483,15 @@ let print_instruction oc labels = function
       if Labelset.mem lbl labels then
         fprintf oc "%a:\n" label (transl_label lbl)
 
-let rec labels_of_code = function
-  | [] -> Labelset.empty
+let rec labels_of_code accu = function
+  | [] ->
+      accu
   | (Pb lbl | Pbf(_, lbl) | Pbt(_, lbl)) :: c ->
-      Labelset.add lbl (labels_of_code c)
-  | _ :: c -> labels_of_code c
+      labels_of_code (Labelset.add lbl accu) c
+  | Pbtbl(_, tbl) :: c ->
+      labels_of_code (List.fold_right Labelset.add tbl accu) c
+  | _ :: c ->
+      labels_of_code accu c
 
 let print_function oc name code =
   Hashtbl.clear current_function_labels;
@@ -488,7 +503,7 @@ let print_function oc name code =
   if not (Cil2Csyntax.atom_is_static name) then
     fprintf oc "	.globl %a\n" symbol name;
   fprintf oc "%a:\n" symbol name;
-  List.iter (print_instruction oc (labels_of_code code)) code
+  List.iter (print_instruction oc (labels_of_code Labelset.empty code)) code
 
 (* Generation of stub functions *)
 
-- 
GitLab