Blob Blame History Raw
From 1469caf50519c50979aeb27518f53d5976aed4ce Mon Sep 17 00:00:00 2001
From: Mark Shinwell <mark@three-tuns.net>
Date: Tue, 9 Jun 2015 11:52:59 +0100
Subject: [PATCH 18/18] aarch64: AArch64 backend generates invalid asm:
 conditional branch out of range (RHBZ#1224815).

Upstream bug: http://caml.inria.fr/mantis/view.php?id=6878
---
 .depend                           | 148 ++++++++++---------
 Makefile                          |   2 +
 asmcomp/arm64/arch.ml             |  13 ++
 asmcomp/arm64/emit.mlp            | 294 +++++++++++++++++++++++++++++++++++---
 asmcomp/branch_relaxation.ml      | 135 +++++++++++++++++
 asmcomp/branch_relaxation.mli     |  26 ++++
 asmcomp/branch_relaxation_intf.ml |  53 +++++++
 asmcomp/power/emit.mlp            | 190 ++++++++++--------------
 8 files changed, 655 insertions(+), 206 deletions(-)
 create mode 100644 asmcomp/branch_relaxation.ml
 create mode 100644 asmcomp/branch_relaxation.mli
 create mode 100644 asmcomp/branch_relaxation_intf.ml

diff --git a/.depend b/.depend
index 5d95a9b..d18b769 100644
--- a/.depend
+++ b/.depend
@@ -94,10 +94,10 @@ typing/ctype.cmi : typing/types.cmi typing/path.cmi parsing/longident.cmi \
     typing/ident.cmi typing/env.cmi parsing/asttypes.cmi
 typing/datarepr.cmi : typing/types.cmi typing/path.cmi typing/ident.cmi \
     parsing/asttypes.cmi
+typing/envaux.cmi : typing/subst.cmi typing/path.cmi typing/env.cmi
 typing/env.cmi : utils/warnings.cmi typing/types.cmi typing/subst.cmi \
     typing/path.cmi parsing/longident.cmi parsing/location.cmi \
     typing/ident.cmi utils/consistbl.cmi parsing/asttypes.cmi
-typing/envaux.cmi : typing/subst.cmi typing/path.cmi typing/env.cmi
 typing/ident.cmi :
 typing/includeclass.cmi : typing/types.cmi typing/env.cmi typing/ctype.cmi
 typing/includecore.cmi : typing/types.cmi typing/typedtree.cmi \
@@ -115,10 +115,10 @@ typing/parmatch.cmi : typing/types.cmi typing/typedtree.cmi \
 typing/path.cmi : typing/ident.cmi
 typing/predef.cmi : typing/types.cmi typing/path.cmi typing/ident.cmi
 typing/primitive.cmi :
+typing/printtyped.cmi : typing/typedtree.cmi
 typing/printtyp.cmi : typing/types.cmi typing/path.cmi \
     typing/outcometree.cmi parsing/longident.cmi typing/ident.cmi \
     typing/env.cmi
-typing/printtyped.cmi : typing/typedtree.cmi
 typing/stypes.cmi : typing/typedtree.cmi parsing/location.cmi \
     typing/annot.cmi
 typing/subst.cmi : typing/types.cmi typing/path.cmi typing/ident.cmi
@@ -131,11 +131,11 @@ typing/typecore.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
 typing/typedecl.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
     parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
     typing/includecore.cmi typing/ident.cmi typing/env.cmi
-typing/typedtree.cmi : typing/types.cmi typing/primitive.cmi typing/path.cmi \
-    parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
-    typing/ident.cmi typing/env.cmi parsing/asttypes.cmi
 typing/typedtreeIter.cmi : typing/typedtree.cmi parsing/asttypes.cmi
 typing/typedtreeMap.cmi : typing/typedtree.cmi
+typing/typedtree.cmi : typing/types.cmi typing/primitive.cmi typing/path.cmi \
+    parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
+    typing/ident.cmi typing/env.cmi parsing/asttypes.cmi
 typing/typemod.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
     parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
     typing/includemod.cmi typing/ident.cmi typing/env.cmi \
@@ -176,6 +176,12 @@ typing/datarepr.cmo : typing/types.cmi typing/path.cmi parsing/location.cmi \
 typing/datarepr.cmx : typing/types.cmx typing/path.cmx parsing/location.cmx \
     typing/ident.cmx typing/btype.cmx parsing/asttypes.cmi \
     typing/datarepr.cmi
+typing/envaux.cmo : typing/types.cmi typing/subst.cmi typing/printtyp.cmi \
+    typing/path.cmi utils/misc.cmi typing/ident.cmi typing/env.cmi \
+    parsing/asttypes.cmi typing/envaux.cmi
+typing/envaux.cmx : typing/types.cmx typing/subst.cmx typing/printtyp.cmx \
+    typing/path.cmx utils/misc.cmx typing/ident.cmx typing/env.cmx \
+    parsing/asttypes.cmi typing/envaux.cmi
 typing/env.cmo : utils/warnings.cmi typing/types.cmi utils/tbl.cmi \
     typing/subst.cmi typing/predef.cmi typing/path.cmi utils/misc.cmi \
     parsing/longident.cmi parsing/location.cmi typing/ident.cmi \
@@ -188,12 +194,6 @@ typing/env.cmx : utils/warnings.cmx typing/types.cmx utils/tbl.cmx \
     typing/datarepr.cmx utils/consistbl.cmx utils/config.cmx \
     typing/cmi_format.cmx utils/clflags.cmx typing/btype.cmx \
     parsing/asttypes.cmi typing/env.cmi
-typing/envaux.cmo : typing/types.cmi typing/subst.cmi typing/printtyp.cmi \
-    typing/path.cmi utils/misc.cmi typing/ident.cmi typing/env.cmi \
-    parsing/asttypes.cmi typing/envaux.cmi
-typing/envaux.cmx : typing/types.cmx typing/subst.cmx typing/printtyp.cmx \
-    typing/path.cmx utils/misc.cmx typing/ident.cmx typing/env.cmx \
-    parsing/asttypes.cmi typing/envaux.cmi
 typing/ident.cmo : typing/ident.cmi
 typing/ident.cmx : typing/ident.cmi
 typing/includeclass.cmo : typing/types.cmi typing/printtyp.cmi \
@@ -252,24 +252,24 @@ typing/predef.cmx : typing/types.cmx typing/path.cmx parsing/location.cmx \
     typing/ident.cmx typing/btype.cmx parsing/asttypes.cmi typing/predef.cmi
 typing/primitive.cmo : utils/misc.cmi typing/primitive.cmi
 typing/primitive.cmx : utils/misc.cmx typing/primitive.cmi
-typing/printtyp.cmo : typing/types.cmi typing/primitive.cmi \
-    typing/predef.cmi typing/path.cmi typing/outcometree.cmi \
-    typing/oprint.cmi utils/misc.cmi parsing/longident.cmi \
-    parsing/location.cmi typing/ident.cmi typing/env.cmi typing/ctype.cmi \
-    utils/clflags.cmi typing/btype.cmi parsing/asttypes.cmi \
-    typing/printtyp.cmi
-typing/printtyp.cmx : typing/types.cmx typing/primitive.cmx \
-    typing/predef.cmx typing/path.cmx typing/outcometree.cmi \
-    typing/oprint.cmx utils/misc.cmx parsing/longident.cmx \
-    parsing/location.cmx typing/ident.cmx typing/env.cmx typing/ctype.cmx \
-    utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \
-    typing/printtyp.cmi
 typing/printtyped.cmo : typing/typedtree.cmi parsing/printast.cmi \
     typing/path.cmi utils/misc.cmi parsing/longident.cmi parsing/location.cmi \
     typing/ident.cmi parsing/asttypes.cmi typing/printtyped.cmi
 typing/printtyped.cmx : typing/typedtree.cmx parsing/printast.cmx \
     typing/path.cmx utils/misc.cmx parsing/longident.cmx parsing/location.cmx \
     typing/ident.cmx parsing/asttypes.cmi typing/printtyped.cmi
+typing/printtyp.cmo : typing/types.cmi typing/primitive.cmi \
+    typing/predef.cmi typing/path.cmi typing/outcometree.cmi \
+    typing/oprint.cmi utils/misc.cmi parsing/longident.cmi \
+    parsing/location.cmi typing/ident.cmi typing/env.cmi typing/ctype.cmi \
+    utils/clflags.cmi typing/btype.cmi parsing/asttypes.cmi \
+    typing/printtyp.cmi
+typing/printtyp.cmx : typing/types.cmx typing/primitive.cmx \
+    typing/predef.cmx typing/path.cmx typing/outcometree.cmi \
+    typing/oprint.cmx utils/misc.cmx parsing/longident.cmx \
+    parsing/location.cmx typing/ident.cmx typing/env.cmx typing/ctype.cmx \
+    utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \
+    typing/printtyp.cmi
 typing/stypes.cmo : typing/typedtree.cmi typing/printtyp.cmi \
     parsing/location.cmi utils/clflags.cmi typing/annot.cmi typing/stypes.cmi
 typing/stypes.cmx : typing/typedtree.cmx typing/printtyp.cmx \
@@ -332,14 +332,6 @@ typing/typedecl.cmx : utils/warnings.cmx typing/typetexp.cmx \
     typing/ident.cmx typing/env.cmx typing/ctype.cmx utils/config.cmx \
     utils/clflags.cmx typing/btype.cmx parsing/asttypes.cmi \
     parsing/ast_helper.cmx typing/typedecl.cmi
-typing/typedtree.cmo : typing/types.cmi typing/primitive.cmi typing/path.cmi \
-    parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \
-    parsing/location.cmi typing/ident.cmi typing/env.cmi parsing/asttypes.cmi \
-    typing/typedtree.cmi
-typing/typedtree.cmx : typing/types.cmx typing/primitive.cmx typing/path.cmx \
-    parsing/parsetree.cmi utils/misc.cmx parsing/longident.cmx \
-    parsing/location.cmx typing/ident.cmx typing/env.cmx parsing/asttypes.cmi \
-    typing/typedtree.cmi
 typing/typedtreeIter.cmo : typing/typedtree.cmi utils/misc.cmi \
     parsing/asttypes.cmi typing/typedtreeIter.cmi
 typing/typedtreeIter.cmx : typing/typedtree.cmx utils/misc.cmx \
@@ -348,6 +340,14 @@ typing/typedtreeMap.cmo : typing/typedtree.cmi utils/misc.cmi \
     typing/typedtreeMap.cmi
 typing/typedtreeMap.cmx : typing/typedtree.cmx utils/misc.cmx \
     typing/typedtreeMap.cmi
+typing/typedtree.cmo : typing/types.cmi typing/primitive.cmi typing/path.cmi \
+    parsing/parsetree.cmi utils/misc.cmi parsing/longident.cmi \
+    parsing/location.cmi typing/ident.cmi typing/env.cmi parsing/asttypes.cmi \
+    typing/typedtree.cmi
+typing/typedtree.cmx : typing/types.cmx typing/primitive.cmx typing/path.cmx \
+    parsing/parsetree.cmi utils/misc.cmx parsing/longident.cmx \
+    parsing/location.cmx typing/ident.cmx typing/env.cmx parsing/asttypes.cmi \
+    typing/typedtree.cmi
 typing/typemod.cmo : utils/warnings.cmi typing/typetexp.cmi typing/types.cmi \
     typing/typedtree.cmi typing/typedecl.cmi typing/typecore.cmi \
     typing/typeclass.cmi typing/subst.cmi typing/stypes.cmi \
@@ -578,27 +578,29 @@ bytecomp/typeopt.cmo : typing/types.cmi typing/typedtree.cmi \
 bytecomp/typeopt.cmx : typing/types.cmx typing/typedtree.cmx \
     typing/predef.cmx typing/path.cmx bytecomp/lambda.cmx typing/ident.cmx \
     typing/env.cmx typing/ctype.cmx bytecomp/typeopt.cmi
-asmcomp/CSEgen.cmi : asmcomp/mach.cmi
 asmcomp/asmgen.cmi : bytecomp/lambda.cmi asmcomp/cmm.cmi
 asmcomp/asmlibrarian.cmi :
 asmcomp/asmlink.cmi : asmcomp/cmx_format.cmi
 asmcomp/asmpackager.cmi : typing/env.cmi
+asmcomp/branch_relaxation.cmi : asmcomp/linearize.cmi \
+    asmcomp/branch_relaxation_intf.cmo
 asmcomp/clambda.cmi : bytecomp/lambda.cmi typing/ident.cmi \
     asmcomp/debuginfo.cmi parsing/asttypes.cmi
 asmcomp/closure.cmi : bytecomp/lambda.cmi asmcomp/clambda.cmi
-asmcomp/cmm.cmi : bytecomp/lambda.cmi typing/ident.cmi asmcomp/debuginfo.cmi
 asmcomp/cmmgen.cmi : asmcomp/cmx_format.cmi asmcomp/cmm.cmi \
     asmcomp/clambda.cmi
+asmcomp/cmm.cmi : bytecomp/lambda.cmi typing/ident.cmi asmcomp/debuginfo.cmi
 asmcomp/cmx_format.cmi : asmcomp/clambda.cmi
 asmcomp/codegen.cmi : asmcomp/cmm.cmi
 asmcomp/coloring.cmi :
 asmcomp/comballoc.cmi : asmcomp/mach.cmi
 asmcomp/compilenv.cmi : typing/ident.cmi asmcomp/cmx_format.cmi \
     asmcomp/clambda.cmi
+asmcomp/CSEgen.cmi : asmcomp/mach.cmi
 asmcomp/deadcode.cmi : asmcomp/mach.cmi
 asmcomp/debuginfo.cmi : parsing/location.cmi bytecomp/lambda.cmi
-asmcomp/emit.cmi : asmcomp/linearize.cmi asmcomp/cmm.cmi
 asmcomp/emitaux.cmi : asmcomp/debuginfo.cmi
+asmcomp/emit.cmi : asmcomp/linearize.cmi asmcomp/cmm.cmi
 asmcomp/interf.cmi : asmcomp/mach.cmi
 asmcomp/linearize.cmi : asmcomp/reg.cmi asmcomp/mach.cmi bytecomp/lambda.cmi \
     asmcomp/debuginfo.cmi
@@ -611,8 +613,8 @@ asmcomp/printlinear.cmi : asmcomp/linearize.cmi
 asmcomp/printmach.cmi : asmcomp/reg.cmi asmcomp/mach.cmi
 asmcomp/proc.cmi : asmcomp/reg.cmi asmcomp/mach.cmi
 asmcomp/reg.cmi : typing/ident.cmi asmcomp/cmm.cmi
-asmcomp/reload.cmi : asmcomp/mach.cmi
 asmcomp/reloadgen.cmi : asmcomp/reg.cmi asmcomp/mach.cmi
+asmcomp/reload.cmi : asmcomp/mach.cmi
 asmcomp/schedgen.cmi : asmcomp/mach.cmi asmcomp/linearize.cmi
 asmcomp/scheduling.cmi : asmcomp/linearize.cmi
 asmcomp/selectgen.cmi : utils/tbl.cmi asmcomp/reg.cmi asmcomp/mach.cmi \
@@ -621,12 +623,6 @@ asmcomp/selection.cmi : asmcomp/mach.cmi asmcomp/cmm.cmi
 asmcomp/spill.cmi : asmcomp/mach.cmi
 asmcomp/split.cmi : asmcomp/mach.cmi
 asmcomp/strmatch.cmi : asmcomp/cmm.cmi
-asmcomp/CSE.cmo : asmcomp/mach.cmi asmcomp/CSEgen.cmi asmcomp/arch.cmo
-asmcomp/CSE.cmx : asmcomp/mach.cmx asmcomp/CSEgen.cmx asmcomp/arch.cmx
-asmcomp/CSEgen.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \
-    asmcomp/CSEgen.cmi
-asmcomp/CSEgen.cmx : asmcomp/reg.cmx asmcomp/proc.cmx asmcomp/mach.cmx \
-    asmcomp/CSEgen.cmi
 asmcomp/arch.cmo :
 asmcomp/arch.cmx :
 asmcomp/asmgen.cmo : bytecomp/translmod.cmi asmcomp/split.cmi \
@@ -677,6 +673,14 @@ asmcomp/asmpackager.cmx : typing/typemod.cmx bytecomp/translmod.cmx \
     utils/config.cmx asmcomp/compilenv.cmx asmcomp/cmx_format.cmi \
     utils/clflags.cmx utils/ccomp.cmx asmcomp/asmlink.cmx asmcomp/asmgen.cmx \
     asmcomp/asmpackager.cmi
+asmcomp/branch_relaxation_intf.cmo : asmcomp/linearize.cmi asmcomp/arch.cmo
+asmcomp/branch_relaxation_intf.cmx : asmcomp/linearize.cmx asmcomp/arch.cmx
+asmcomp/branch_relaxation.cmo : utils/misc.cmi asmcomp/mach.cmi \
+    asmcomp/linearize.cmi asmcomp/cmm.cmi asmcomp/branch_relaxation_intf.cmo \
+    asmcomp/branch_relaxation.cmi
+asmcomp/branch_relaxation.cmx : utils/misc.cmx asmcomp/mach.cmx \
+    asmcomp/linearize.cmx asmcomp/cmm.cmx asmcomp/branch_relaxation_intf.cmx \
+    asmcomp/branch_relaxation.cmi
 asmcomp/clambda.cmo : bytecomp/lambda.cmi typing/ident.cmi \
     asmcomp/debuginfo.cmi parsing/asttypes.cmi asmcomp/clambda.cmi
 asmcomp/clambda.cmx : bytecomp/lambda.cmx typing/ident.cmx \
@@ -691,10 +695,6 @@ asmcomp/closure.cmx : utils/tbl.cmx bytecomp/switch.cmx typing/primitive.cmx \
     asmcomp/debuginfo.cmx asmcomp/compilenv.cmx utils/clflags.cmx \
     asmcomp/clambda.cmx parsing/asttypes.cmi asmcomp/arch.cmx \
     asmcomp/closure.cmi
-asmcomp/cmm.cmo : bytecomp/lambda.cmi typing/ident.cmi asmcomp/debuginfo.cmi \
-    asmcomp/arch.cmo asmcomp/cmm.cmi
-asmcomp/cmm.cmx : bytecomp/lambda.cmx typing/ident.cmx asmcomp/debuginfo.cmx \
-    asmcomp/arch.cmx asmcomp/cmm.cmi
 asmcomp/cmmgen.cmo : typing/types.cmi bytecomp/switch.cmi \
     asmcomp/strmatch.cmi asmcomp/proc.cmi typing/primitive.cmi utils/misc.cmi \
     bytecomp/lambda.cmi typing/ident.cmi asmcomp/debuginfo.cmi \
@@ -707,6 +707,10 @@ asmcomp/cmmgen.cmx : typing/types.cmx bytecomp/switch.cmx \
     utils/config.cmx asmcomp/compilenv.cmx asmcomp/cmx_format.cmi \
     asmcomp/cmm.cmx utils/clflags.cmx asmcomp/clambda.cmx \
     parsing/asttypes.cmi asmcomp/arch.cmx asmcomp/cmmgen.cmi
+asmcomp/cmm.cmo : bytecomp/lambda.cmi typing/ident.cmi asmcomp/debuginfo.cmi \
+    asmcomp/arch.cmo asmcomp/cmm.cmi
+asmcomp/cmm.cmx : bytecomp/lambda.cmx typing/ident.cmx asmcomp/debuginfo.cmx \
+    asmcomp/arch.cmx asmcomp/cmm.cmi
 asmcomp/codegen.cmo : asmcomp/split.cmi asmcomp/spill.cmi asmcomp/reload.cmi \
     asmcomp/reg.cmi asmcomp/printmach.cmi asmcomp/printlinear.cmi \
     asmcomp/printcmm.cmi asmcomp/liveness.cmi asmcomp/linearize.cmi \
@@ -729,6 +733,12 @@ asmcomp/compilenv.cmo : utils/misc.cmi parsing/location.cmi typing/ident.cmi \
 asmcomp/compilenv.cmx : utils/misc.cmx parsing/location.cmx typing/ident.cmx \
     typing/env.cmx utils/config.cmx asmcomp/cmx_format.cmi \
     asmcomp/clambda.cmx asmcomp/compilenv.cmi
+asmcomp/CSEgen.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \
+    asmcomp/CSEgen.cmi
+asmcomp/CSEgen.cmx : asmcomp/reg.cmx asmcomp/proc.cmx asmcomp/mach.cmx \
+    asmcomp/CSEgen.cmi
+asmcomp/CSE.cmo : asmcomp/mach.cmi asmcomp/CSEgen.cmi asmcomp/arch.cmo
+asmcomp/CSE.cmx : asmcomp/mach.cmx asmcomp/CSEgen.cmx asmcomp/arch.cmx
 asmcomp/deadcode.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \
     asmcomp/deadcode.cmi
 asmcomp/deadcode.cmx : asmcomp/reg.cmx asmcomp/proc.cmx asmcomp/mach.cmx \
@@ -737,20 +747,20 @@ asmcomp/debuginfo.cmo : parsing/location.cmi bytecomp/lambda.cmi \
     asmcomp/debuginfo.cmi
 asmcomp/debuginfo.cmx : parsing/location.cmx bytecomp/lambda.cmx \
     asmcomp/debuginfo.cmi
-asmcomp/emit.cmo : asmcomp/reg.cmi asmcomp/proc.cmi utils/misc.cmi \
-    asmcomp/mach.cmi asmcomp/linearize.cmi bytecomp/lambda.cmi \
-    asmcomp/emitaux.cmi asmcomp/debuginfo.cmi utils/config.cmi \
-    asmcomp/compilenv.cmi asmcomp/cmm.cmi utils/clflags.cmi asmcomp/arch.cmo \
-    asmcomp/emit.cmi
-asmcomp/emit.cmx : asmcomp/reg.cmx asmcomp/proc.cmx utils/misc.cmx \
-    asmcomp/mach.cmx asmcomp/linearize.cmx bytecomp/lambda.cmx \
-    asmcomp/emitaux.cmx asmcomp/debuginfo.cmx utils/config.cmx \
-    asmcomp/compilenv.cmx asmcomp/cmm.cmx utils/clflags.cmx asmcomp/arch.cmx \
-    asmcomp/emit.cmi
 asmcomp/emitaux.cmo : asmcomp/linearize.cmi asmcomp/debuginfo.cmi \
     utils/config.cmi utils/clflags.cmi asmcomp/arch.cmo asmcomp/emitaux.cmi
 asmcomp/emitaux.cmx : asmcomp/linearize.cmx asmcomp/debuginfo.cmx \
     utils/config.cmx utils/clflags.cmx asmcomp/arch.cmx asmcomp/emitaux.cmi
+asmcomp/emit.cmo : asmcomp/reg.cmi asmcomp/proc.cmi utils/misc.cmi \
+    asmcomp/mach.cmi asmcomp/linearize.cmi bytecomp/lambda.cmi \
+    asmcomp/emitaux.cmi utils/config.cmi asmcomp/compilenv.cmi \
+    asmcomp/cmm.cmi utils/clflags.cmi asmcomp/branch_relaxation.cmi \
+    asmcomp/arch.cmo asmcomp/emit.cmi
+asmcomp/emit.cmx : asmcomp/reg.cmx asmcomp/proc.cmx utils/misc.cmx \
+    asmcomp/mach.cmx asmcomp/linearize.cmx bytecomp/lambda.cmx \
+    asmcomp/emitaux.cmx utils/config.cmx asmcomp/compilenv.cmx \
+    asmcomp/cmm.cmx utils/clflags.cmx asmcomp/branch_relaxation.cmx \
+    asmcomp/arch.cmx asmcomp/emit.cmi
 asmcomp/interf.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \
     asmcomp/interf.cmi
 asmcomp/interf.cmx : asmcomp/reg.cmx asmcomp/proc.cmx asmcomp/mach.cmx \
@@ -796,21 +806,19 @@ asmcomp/printmach.cmx : asmcomp/reg.cmx asmcomp/proc.cmx \
     asmcomp/debuginfo.cmx asmcomp/cmm.cmx asmcomp/arch.cmx \
     asmcomp/printmach.cmi
 asmcomp/proc.cmo : asmcomp/reg.cmi utils/misc.cmi asmcomp/mach.cmi \
-    utils/config.cmi asmcomp/cmm.cmi utils/clflags.cmi utils/ccomp.cmi \
-    asmcomp/arch.cmo asmcomp/proc.cmi
+    utils/config.cmi asmcomp/cmm.cmi utils/ccomp.cmi asmcomp/arch.cmo \
+    asmcomp/proc.cmi
 asmcomp/proc.cmx : asmcomp/reg.cmx utils/misc.cmx asmcomp/mach.cmx \
-    utils/config.cmx asmcomp/cmm.cmx utils/clflags.cmx utils/ccomp.cmx \
-    asmcomp/arch.cmx asmcomp/proc.cmi
+    utils/config.cmx asmcomp/cmm.cmx utils/ccomp.cmx asmcomp/arch.cmx \
+    asmcomp/proc.cmi
 asmcomp/reg.cmo : typing/ident.cmi asmcomp/cmm.cmi asmcomp/reg.cmi
 asmcomp/reg.cmx : typing/ident.cmx asmcomp/cmm.cmx asmcomp/reg.cmi
-asmcomp/reload.cmo : asmcomp/reloadgen.cmi asmcomp/reg.cmi asmcomp/mach.cmi \
-    asmcomp/cmm.cmi utils/clflags.cmi asmcomp/arch.cmo asmcomp/reload.cmi
-asmcomp/reload.cmx : asmcomp/reloadgen.cmx asmcomp/reg.cmx asmcomp/mach.cmx \
-    asmcomp/cmm.cmx utils/clflags.cmx asmcomp/arch.cmx asmcomp/reload.cmi
 asmcomp/reloadgen.cmo : asmcomp/reg.cmi utils/misc.cmi asmcomp/mach.cmi \
     asmcomp/reloadgen.cmi
 asmcomp/reloadgen.cmx : asmcomp/reg.cmx utils/misc.cmx asmcomp/mach.cmx \
     asmcomp/reloadgen.cmi
+asmcomp/reload.cmo : asmcomp/reloadgen.cmi asmcomp/reload.cmi
+asmcomp/reload.cmx : asmcomp/reloadgen.cmx asmcomp/reload.cmi
 asmcomp/schedgen.cmo : asmcomp/reg.cmi asmcomp/proc.cmi asmcomp/mach.cmi \
     asmcomp/linearize.cmi asmcomp/cmm.cmi asmcomp/arch.cmo \
     asmcomp/schedgen.cmi
@@ -827,11 +835,11 @@ asmcomp/selectgen.cmx : utils/tbl.cmx bytecomp/simplif.cmx asmcomp/reg.cmx \
     asmcomp/proc.cmx utils/misc.cmx asmcomp/mach.cmx bytecomp/lambda.cmx \
     typing/ident.cmx asmcomp/debuginfo.cmx asmcomp/cmm.cmx utils/clflags.cmx \
     asmcomp/arch.cmx asmcomp/selectgen.cmi
-asmcomp/selection.cmo : asmcomp/selectgen.cmi asmcomp/proc.cmi \
-    asmcomp/mach.cmi asmcomp/cmm.cmi utils/clflags.cmi asmcomp/arch.cmo \
+asmcomp/selection.cmo : asmcomp/selectgen.cmi asmcomp/mach.cmi \
+    asmcomp/compilenv.cmi asmcomp/cmm.cmi utils/clflags.cmi asmcomp/arch.cmo \
     asmcomp/selection.cmi
-asmcomp/selection.cmx : asmcomp/selectgen.cmx asmcomp/proc.cmx \
-    asmcomp/mach.cmx asmcomp/cmm.cmx utils/clflags.cmx asmcomp/arch.cmx \
+asmcomp/selection.cmx : asmcomp/selectgen.cmx asmcomp/mach.cmx \
+    asmcomp/compilenv.cmx asmcomp/cmm.cmx utils/clflags.cmx asmcomp/arch.cmx \
     asmcomp/selection.cmi
 asmcomp/spill.cmo : asmcomp/reg.cmi asmcomp/proc.cmi utils/misc.cmi \
     asmcomp/mach.cmi asmcomp/spill.cmi
@@ -849,8 +857,8 @@ driver/compenv.cmi :
 driver/compile.cmi :
 driver/compmisc.cmi : typing/env.cmi
 driver/errors.cmi :
-driver/main.cmi :
 driver/main_args.cmi :
+driver/main.cmi :
 driver/optcompile.cmi :
 driver/opterrors.cmi :
 driver/optmain.cmi :
@@ -885,6 +893,8 @@ driver/compmisc.cmx : typing/typemod.cmx utils/misc.cmx \
     parsing/asttypes.cmi driver/compmisc.cmi
 driver/errors.cmo : parsing/location.cmi driver/errors.cmi
 driver/errors.cmx : parsing/location.cmx driver/errors.cmi
+driver/main_args.cmo : utils/warnings.cmi driver/main_args.cmi
+driver/main_args.cmx : utils/warnings.cmx driver/main_args.cmi
 driver/main.cmo : utils/warnings.cmi utils/misc.cmi driver/main_args.cmi \
     parsing/location.cmi utils/config.cmi driver/compmisc.cmi \
     driver/compile.cmi driver/compenv.cmi utils/clflags.cmi \
@@ -895,8 +905,6 @@ driver/main.cmx : utils/warnings.cmx utils/misc.cmx driver/main_args.cmx \
     driver/compile.cmx driver/compenv.cmx utils/clflags.cmx \
     bytecomp/bytepackager.cmx bytecomp/bytelink.cmx \
     bytecomp/bytelibrarian.cmx driver/main.cmi
-driver/main_args.cmo : utils/warnings.cmi driver/main_args.cmi
-driver/main_args.cmx : utils/warnings.cmx driver/main_args.cmi
 driver/optcompile.cmo : utils/warnings.cmi typing/typemod.cmi \
     typing/typedtree.cmi typing/typecore.cmi bytecomp/translmod.cmi \
     typing/stypes.cmi bytecomp/simplif.cmi typing/printtyped.cmi \
diff --git a/Makefile b/Makefile
index 6c0e7e6..7a20e2c 100644
--- a/Makefile
+++ b/Makefile
@@ -94,6 +94,8 @@ ASMCOMP=asmcomp/arch.cmo asmcomp/debuginfo.cmo \
   asmcomp/deadcode.cmo \
   asmcomp/printlinear.cmo asmcomp/linearize.cmo \
   asmcomp/schedgen.cmo asmcomp/scheduling.cmo \
+  asmcomp/branch_relaxation_intf.cmo \
+  asmcomp/branch_relaxation.cmo \
   asmcomp/emitaux.cmo asmcomp/emit.cmo asmcomp/asmgen.cmo \
   asmcomp/asmlink.cmo asmcomp/asmlibrarian.cmo asmcomp/asmpackager.cmo \
   driver/opterrors.cmo driver/optcompile.cmo
diff --git a/asmcomp/arm64/arch.ml b/asmcomp/arm64/arch.ml
index bfbe183..3e62da8 100644
--- a/asmcomp/arm64/arch.ml
+++ b/asmcomp/arm64/arch.ml
@@ -34,8 +34,12 @@ type addressing_mode =
 (* Specific operations *)
 
 type specific_operation =
+  | Ifar_alloc of int
+  | Ifar_intop_checkbound
+  | Ifar_intop_imm_checkbound of int
   | Ishiftarith of arith_operation * int
   | Ishiftcheckbound of int
+  | Ifar_shiftcheckbound of int
   | Imuladd       (* multiply and add *)
   | Imulsub       (* multiply and subtract *)
   | Inegmulf      (* floating-point negate and multiply *)
@@ -91,6 +95,12 @@ let print_addressing printreg addr ppf arg =
 
 let print_specific_operation printreg op ppf arg =
   match op with
+  | Ifar_alloc n ->
+    fprintf ppf "(far) alloc %i" n
+  | Ifar_intop_checkbound ->
+    fprintf ppf "%a (far) check > %a" printreg arg.(0) printreg arg.(1)
+  | Ifar_intop_imm_checkbound n ->
+    fprintf ppf "%a (far) check > %i" printreg arg.(0) n
   | Ishiftarith(op, shift) ->
       let op_name = function
       | Ishiftadd -> "+"
@@ -103,6 +113,9 @@ let print_specific_operation printreg op ppf arg =
        printreg arg.(0) (op_name op) printreg arg.(1) shift_mark
   | Ishiftcheckbound n ->
       fprintf ppf "check %a >> %i > %a" printreg arg.(0) n printreg arg.(1)
+  | Ifar_shiftcheckbound n ->
+      fprintf ppf
+        "(far) check %a >> %i > %a" printreg arg.(0) n printreg arg.(1)
   | Imuladd ->
       fprintf ppf "(%a * %a) + %a"
         printreg arg.(0)
diff --git a/asmcomp/arm64/emit.mlp b/asmcomp/arm64/emit.mlp
index c5c30d4..3d7a297 100644
--- a/asmcomp/arm64/emit.mlp
+++ b/asmcomp/arm64/emit.mlp
@@ -231,6 +231,32 @@ let emit_intconst dst n =
   in
     if n < 0n then emit_neg true 48 else emit_pos true 48
 
+let num_instructions_for_intconst n =
+  let num_instructions = ref 0 in
+  let rec count_pos first shift =
+    if shift < 0 then begin
+      if first then incr num_instructions
+    end else begin
+      let s = Nativeint.(logand (shift_right_logical n shift) 0xFFFFn) in
+      if s = 0n then count_pos first (shift - 16) else begin
+        incr num_instructions;
+        count_pos false (shift - 16)
+      end
+    end
+  and count_neg first shift =
+    if shift < 0 then begin
+      if first then incr num_instructions
+    end else begin
+      let s = Nativeint.(logand (shift_right_logical n shift) 0xFFFFn) in
+      if s = 0xFFFFn then count_neg first (shift - 16) else begin
+        incr num_instructions;
+        count_neg false (shift - 16)
+      end
+    end
+  in
+  if n < 0n then count_neg true 48 else count_pos true 48;
+  !num_instructions
+
 (* Recognize float constants appropriate for FMOV dst, #fpimm instruction:
    "a normalized binary floating point encoding with 1 sign bit, 4
     bits of fraction and a 3-bit exponent" *)
@@ -302,6 +328,217 @@ let emit_load_symbol_addr dst s =
     `	ldr	{emit_reg dst}, [{emit_reg dst}, #:got_lo12:{emit_symbol s}]\n`
   end
 
+(* The following functions are used for calculating the sizes of the
+   call GC and bounds check points emitted out-of-line from the function
+   body.  See branch_relaxation.mli. *)
+
+let num_call_gc_and_check_bound_points instr =
+  let rec loop instr ((call_gc, check_bound) as totals) =
+    match instr.desc with
+    | Lend -> totals
+    | Lop (Ialloc _) when !fastcode_flag ->
+      loop instr.next (call_gc + 1, check_bound)
+    | Lop (Iintop Icheckbound)
+    | Lop (Iintop_imm (Icheckbound, _))
+    | Lop (Ispecific (Ishiftcheckbound _)) ->
+      let check_bound =
+        (* When not in debug mode, there is at most one check-bound point. *)
+        if not !Clflags.debug then min (check_bound + 1) 1
+        else check_bound + 1
+      in
+      loop instr.next (call_gc, check_bound)
+    (* The following four should never be seen, since this function is run
+       before branch relaxation. *)
+    | Lop (Ispecific (Ifar_alloc _))
+    | Lop (Ispecific Ifar_intop_checkbound)
+    | Lop (Ispecific (Ifar_intop_imm_checkbound _))
+    | Lop (Ispecific (Ifar_shiftcheckbound _)) -> assert false
+    | _ -> loop instr.next totals
+  in
+  loop instr (0, 0)
+
+let max_out_of_line_code_offset instr ~num_call_gc ~num_check_bound =
+  if num_call_gc < 1 && num_check_bound < 1 then 0
+  else begin
+    let size_of_call_gc = 2 in
+    let size_of_check_bound = 1 in
+    let size_of_last_thing =
+      (* Call-GC points come before check-bound points. *)
+      if num_check_bound >= 1 then size_of_check_bound else size_of_call_gc
+    in
+    let total_size =
+      size_of_call_gc*num_call_gc + size_of_check_bound*num_check_bound
+    in
+    let max_offset = total_size - size_of_last_thing in
+    assert (max_offset >= 0);
+    max_offset
+  end
+
+module BR = Branch_relaxation.Make (struct
+  (* CR-someday mshinwell: B and BL have +/- 128Mb ranges; for the moment we
+     assume we will never exceed this.  It would seem to be most likely to
+     occur for branches between functions; in this case, the linker should be
+     able to insert veneers anyway.  (See section 4.6.7 of the document
+     "ELF for the ARM 64-bit architecture (AArch64)".) *)
+
+  type distance = int
+
+  module Cond_branch = struct
+    type t = TB | CB | Bcc
+
+    let all = [TB; CB; Bcc]
+
+    (* AArch64 instructions are 32 bits wide, so [distance] in this module
+       means units of 32-bit words. *)
+    let max_displacement = function
+      | TB -> 32 * 1024 / 4  (* +/- 32Kb *)
+      | CB | Bcc -> 1 * 1024 * 1024 / 4  (* +/- 1Mb *)
+
+    let classify_instr = function
+      | Lop (Ialloc _)
+      | Lop (Iintop Icheckbound)
+      | Lop (Iintop_imm (Icheckbound, _))
+      | Lop (Ispecific (Ishiftcheckbound _)) -> Some Bcc
+      (* The various "far" variants in [specific_operation] don't need to
+         return [Some] here, since their code sequences never contain any
+         conditional branches that might need relaxing. *)
+      | Lcondbranch (Itruetest, _)
+      | Lcondbranch (Ifalsetest, _) -> Some CB
+      | Lcondbranch (Iinttest _, _)
+      | Lcondbranch (Iinttest_imm _, _)
+      | Lcondbranch (Ifloattest _, _) -> Some Bcc
+      | Lcondbranch (Ioddtest, _)
+      | Lcondbranch (Ieventest, _) -> Some TB
+      | Lcondbranch3 _ -> Some Bcc
+      | _ -> None
+  end
+
+  let offset_pc_at_branch = 0
+
+  let epilogue_size () =
+    if !contains_calls then 3 else 2
+
+  let instr_size = function
+    | Lend -> 0
+    | Lop (Imove | Ispill | Ireload) -> 1
+    | Lop (Iconst_int n | Iconst_blockheader n) ->
+      num_instructions_for_intconst n
+    | Lop (Iconst_float _) -> 2
+    | Lop (Iconst_symbol _) -> 2
+    | Lop (Icall_ind) -> 1
+    | Lop (Icall_imm _) -> 1
+    | Lop (Itailcall_ind) -> epilogue_size ()
+    | Lop (Itailcall_imm s) ->
+      if s = !function_name then 1 else epilogue_size ()
+    | Lop (Iextcall (_, false)) -> 1
+    | Lop (Iextcall (_, true)) -> 3
+    | Lop (Istackoffset _) -> 2
+    | Lop (Iload (size, addr)) | Lop (Istore (size, addr, _)) ->
+      let based = match addr with Iindexed _ -> 0 | Ibased _ -> 1 in
+      based + begin match size with Single -> 2 | _ -> 1 end
+    | Lop (Ialloc _) when !fastcode_flag -> 4
+    | Lop (Ispecific (Ifar_alloc _)) when !fastcode_flag -> 5
+    | Lop (Ialloc num_words) | Lop (Ispecific (Ifar_alloc num_words)) ->
+      begin match num_words with
+      | 16 | 24 | 32 -> 1
+      | _ -> 1 + num_instructions_for_intconst (Nativeint.of_int num_words)
+      end
+    | Lop (Iintop (Icomp _)) -> 2
+    | Lop (Iintop_imm (Icomp _, _)) -> 2
+    | Lop (Iintop Icheckbound) -> 2
+    | Lop (Ispecific Ifar_intop_checkbound) -> 3
+    | Lop (Iintop_imm (Icheckbound, _)) -> 2
+    | Lop (Ispecific (Ifar_intop_imm_checkbound _)) -> 3
+    | Lop (Ispecific (Ishiftcheckbound _)) -> 2
+    | Lop (Ispecific (Ifar_shiftcheckbound _)) -> 3
+    | Lop (Iintop Imod) -> 2
+    | Lop (Iintop Imulh) -> 1
+    | Lop (Iintop _) -> 1
+    | Lop (Iintop_imm _) -> 1
+    | Lop (Ifloatofint | Iintoffloat | Iabsf | Inegf | Ispecific Isqrtf) -> 1
+    | Lop (Iaddf | Isubf | Imulf | Idivf | Ispecific Inegmulf) -> 1
+    | Lop (Ispecific (Imuladdf | Inegmuladdf | Imulsubf | Inegmulsubf)) -> 1
+    | Lop (Ispecific (Ishiftarith _)) -> 1
+    | Lop (Ispecific (Imuladd | Imulsub)) -> 1
+    | Lop (Ispecific (Ibswap 16)) -> 2
+    | Lop (Ispecific (Ibswap _)) -> 1
+    | Lreloadretaddr -> 0
+    | Lreturn -> epilogue_size ()
+    | Llabel _ -> 0
+    | Lbranch _ -> 1
+    | Lcondbranch (tst, _) ->
+      begin match tst with
+      | Itruetest -> 1
+      | Ifalsetest -> 1
+      | Iinttest _ -> 2
+      | Iinttest_imm _ -> 2
+      | Ifloattest _ -> 2
+      | Ioddtest -> 1
+      | Ieventest -> 1
+      end
+    | Lcondbranch3 (lbl0, lbl1, lbl2) ->
+      1 + begin match lbl0 with None -> 0 | Some _ -> 1 end
+        + begin match lbl1 with None -> 0 | Some _ -> 1 end
+        + begin match lbl2 with None -> 0 | Some _ -> 1 end
+    | Lswitch jumptbl -> 3 + Array.length jumptbl
+    | Lsetuptrap _ -> 2
+    | Lpushtrap -> 3
+    | Lpoptrap -> 1
+    | Lraise k ->
+      begin match !Clflags.debug, k with
+      | true, (Lambda.Raise_regular | Lambda.Raise_reraise) -> 1
+      | false, _
+      | true, Lambda.Raise_notrace -> 4
+      end
+
+  let relax_allocation ~num_words =
+    Lop (Ispecific (Ifar_alloc num_words))
+
+  let relax_intop_checkbound () =
+    Lop (Ispecific Ifar_intop_checkbound)
+
+  let relax_intop_imm_checkbound ~bound =
+    Lop (Ispecific (Ifar_intop_imm_checkbound bound))
+
+  let relax_specific_op = function
+    | Ishiftcheckbound shift -> Lop (Ispecific (Ifar_shiftcheckbound shift))
+    | _ -> assert false
+end)
+
+(* Output the assembly code for allocation. *)
+
+let assembly_code_for_allocation i ~n ~far =
+  let lbl_frame = record_frame_label i.live i.dbg in
+  if !fastcode_flag then begin
+    let lbl_redo = new_label() in
+    let lbl_call_gc = new_label() in
+    `{emit_label lbl_redo}:`;
+    `	sub	{emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, #{emit_int n}\n`;
+    `	cmp	{emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_limit}\n`;
+    `	add	{emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, #8\n`;
+    if not far then begin
+      `	b.lo	{emit_label lbl_call_gc}\n`
+    end else begin
+      let lbl = new_label () in
+      `	b.cs	{emit_label lbl}\n`;
+      `	b	{emit_label lbl_call_gc}\n`;
+      `{emit_label lbl}:\n`
+    end;
+    call_gc_sites :=
+      { gc_lbl = lbl_call_gc;
+        gc_return_lbl = lbl_redo;
+        gc_frame_lbl = lbl_frame } :: !call_gc_sites
+  end else begin
+    begin match n with
+    | 16 -> `	bl	{emit_symbol "caml_alloc1"}\n`
+    | 24 -> `	bl	{emit_symbol "caml_alloc2"}\n`
+    | 32 -> `	bl	{emit_symbol "caml_alloc3"}\n`
+    | _  -> emit_intconst reg_x15 (Nativeint.of_int n);
+            `	bl	{emit_symbol "caml_allocN"}\n`
+    end;
+    `{emit_label lbl_frame}:	add	{emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, #8\n`
+  end
+
 (* Output the assembly code for an instruction *)
 
 let emit_instr i =
@@ -410,29 +647,9 @@ let emit_instr i =
             `	str	{emit_reg src}, {emit_addressing addr base}\n`
         end
     | Lop(Ialloc n) ->
-        let lbl_frame = record_frame_label i.live i.dbg in
-        if !fastcode_flag then begin
-          let lbl_redo = new_label() in
-          let lbl_call_gc = new_label() in
-          `{emit_label lbl_redo}:`;
-          `	sub	{emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, #{emit_int n}\n`;
-          `	cmp	{emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_limit}\n`;
-          `	add	{emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, #8\n`;
-          `	b.lo	{emit_label lbl_call_gc}\n`;
-          call_gc_sites :=
-            { gc_lbl = lbl_call_gc;
-              gc_return_lbl = lbl_redo;
-              gc_frame_lbl = lbl_frame } :: !call_gc_sites
-        end else begin
-          begin match n with
-          | 16 -> `	bl	{emit_symbol "caml_alloc1"}\n`
-          | 24 -> `	bl	{emit_symbol "caml_alloc2"}\n`
-          | 32 -> `	bl	{emit_symbol "caml_alloc3"}\n`
-          | _  -> emit_intconst reg_x15 (Nativeint.of_int n);
-                  `	bl	{emit_symbol "caml_allocN"}\n`
-          end;
-          `{emit_label lbl_frame}:	add	{emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, #8\n`
-        end
+        assembly_code_for_allocation i ~n ~far:false
+    | Lop(Ispecific (Ifar_alloc n)) ->
+        assembly_code_for_allocation i ~n ~far:true
     | Lop(Iintop(Icomp cmp)) ->
         `	cmp	{emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
         `	cset	{emit_reg i.res.(0)}, {emit_string (name_for_comparison cmp)}\n`
@@ -443,14 +660,35 @@ let emit_instr i =
         let lbl = bound_error_label i.dbg in
         `	cmp	{emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
         `	b.ls	{emit_label lbl}\n`
+    | Lop(Ispecific Ifar_intop_checkbound) ->
+        let lbl = bound_error_label i.dbg in
+        let lbl2 = new_label () in
+        `	cmp	{emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
+        `	b.ge	{emit_label lbl2}\n`;
+        `	b	{emit_label lbl}\n`;
+        `{emit_label lbl2}:\n`;
     | Lop(Iintop_imm(Icheckbound, n)) ->
         let lbl = bound_error_label i.dbg in
         `	cmp	{emit_reg i.arg.(0)}, #{emit_int n}\n`;
         `	b.ls	{emit_label lbl}\n`
+    | Lop(Ispecific(Ifar_intop_imm_checkbound bound)) ->
+        let lbl = bound_error_label i.dbg in
+        let lbl2 = new_label () in
+        `	cmp	{emit_reg i.arg.(0)}, #{emit_int bound}\n`;
+        `	b.ge	{emit_label lbl2}\n`;
+        `	b	{emit_label lbl}\n`;
+        `{emit_label lbl2}:\n`;
     | Lop(Ispecific(Ishiftcheckbound shift)) ->
         let lbl = bound_error_label i.dbg in
         `	cmp	{emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}, lsr #{emit_int shift}\n`;
         `	b.cs	{emit_label lbl}\n`
+    | Lop(Ispecific(Ifar_shiftcheckbound shift)) ->
+        let lbl = bound_error_label i.dbg in
+        let lbl2 = new_label () in
+        `	cmp	{emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}, lsr #{emit_int shift}\n`;
+        `	b.ge	{emit_label lbl2}\n`;
+        `	b	{emit_label lbl}\n`;
+        `{emit_label lbl2}:\n`;
     | Lop(Iintop Imod) ->
         `	sdiv	{emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
         `	msub	{emit_reg i.res.(0)}, {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`
@@ -659,9 +897,19 @@ let fundecl fundecl =
     `	str	x30, [sp, #{emit_int (n-8)}]\n`
   end;
   `{emit_label !tailrec_entry_point}:\n`;
+  let num_call_gc, num_check_bound =
+    num_call_gc_and_check_bound_points fundecl.fun_body
+  in
+  let max_out_of_line_code_offset =
+    max_out_of_line_code_offset fundecl.fun_body ~num_call_gc
+      ~num_check_bound
+  in
+  BR.relax fundecl.fun_body ~max_out_of_line_code_offset;
   emit_all fundecl.fun_body;
   List.iter emit_call_gc !call_gc_sites;
   List.iter emit_call_bound_error !bound_error_sites;
+  assert (List.length !call_gc_sites = num_call_gc);
+  assert (List.length !bound_error_sites = num_check_bound);
   cfi_endproc();
   `	.type	{emit_symbol fundecl.fun_name}, %function\n`;
   `	.size	{emit_symbol fundecl.fun_name}, .-{emit_symbol fundecl.fun_name}\n`;
diff --git a/asmcomp/branch_relaxation.ml b/asmcomp/branch_relaxation.ml
new file mode 100644
index 0000000..8fd3891
--- /dev/null
+++ b/asmcomp/branch_relaxation.ml
@@ -0,0 +1,135 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                                OCaml                                *)
+(*                                                                     *)
+(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
+(*                   Mark Shinwell, Jane Street Europe                 *)
+(*                                                                     *)
+(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the Q Public License version 1.0.               *)
+(*                                                                     *)
+(***********************************************************************)
+
+open Mach
+open Linearize
+
+module Make (T : Branch_relaxation_intf.S) = struct
+  let label_map code =
+    let map = Hashtbl.create 37 in
+    let rec fill_map pc instr =
+      match instr.desc with
+      | Lend -> (pc, map)
+      | Llabel lbl -> Hashtbl.add map lbl pc; fill_map pc instr.next
+      | op -> fill_map (pc + T.instr_size op) instr.next
+    in
+    fill_map 0 code
+
+  let branch_overflows map pc_branch lbl_dest max_branch_offset =
+    let pc_dest = Hashtbl.find map lbl_dest in
+    let delta = pc_dest - (pc_branch + T.offset_pc_at_branch) in
+    delta <= -max_branch_offset || delta >= max_branch_offset
+
+  let opt_branch_overflows map pc_branch opt_lbl_dest max_branch_offset =
+    match opt_lbl_dest with
+    | None -> false
+    | Some lbl_dest ->
+      branch_overflows map pc_branch lbl_dest max_branch_offset
+
+  let instr_overflows ~code_size ~max_out_of_line_code_offset instr map pc =
+    match T.Cond_branch.classify_instr instr.desc with
+    | None -> false
+    | Some branch ->
+      let max_branch_offset =
+        (* Remember to cut some slack for multi-word instructions (in the
+           [Linearize] sense of the word) where the branch can be anywhere in
+           the middle.  12 words of slack is plenty. *)
+        T.Cond_branch.max_displacement branch - 12
+      in
+      match instr.desc with
+      | Lop (Ialloc _)
+      | Lop (Iintop Icheckbound)
+      | Lop (Iintop_imm (Icheckbound, _))
+      | Lop (Ispecific _) ->
+        (* We assume that any branches eligible for relaxation generated
+           by these instructions only branch forward.  We further assume
+           that any of these may branch to an out-of-line code block. *)
+        code_size + max_out_of_line_code_offset - pc >= max_branch_offset
+      | Lcondbranch (_, lbl) ->
+        branch_overflows map pc lbl max_branch_offset
+      | Lcondbranch3 (lbl0, lbl1, lbl2) ->
+        opt_branch_overflows map pc lbl0 max_branch_offset
+          || opt_branch_overflows map pc lbl1 max_branch_offset
+          || opt_branch_overflows map pc lbl2 max_branch_offset
+      | _ ->
+        Misc.fatal_error "Unsupported instruction for branch relaxation"
+
+  let fixup_branches ~code_size ~max_out_of_line_code_offset map code =
+    let expand_optbranch lbl n arg next =
+      match lbl with
+      | None -> next
+      | Some l ->
+        instr_cons (Lcondbranch (Iinttest_imm (Isigned Cmm.Ceq, n), l))
+          arg [||] next
+    in
+    let rec fixup did_fix pc instr =
+      match instr.desc with
+      | Lend -> did_fix
+      | _ ->
+        let overflows =
+          instr_overflows ~code_size ~max_out_of_line_code_offset instr map pc
+        in
+        if not overflows then
+          fixup did_fix (pc + T.instr_size instr.desc) instr.next
+        else
+          match instr.desc with
+          | Lop (Ialloc num_words) ->
+            instr.desc <- T.relax_allocation ~num_words;
+            fixup true (pc + T.instr_size instr.desc) instr.next
+          | Lop (Iintop Icheckbound) ->
+            instr.desc <- T.relax_intop_checkbound ();
+            fixup true (pc + T.instr_size instr.desc) instr.next
+          | Lop (Iintop_imm (Icheckbound, bound)) ->
+            instr.desc <- T.relax_intop_imm_checkbound ~bound;
+            fixup true (pc + T.instr_size instr.desc) instr.next
+          | Lop (Ispecific specific) ->
+            instr.desc <- T.relax_specific_op specific;
+            fixup true (pc + T.instr_size instr.desc) instr.next
+          | Lcondbranch (test, lbl) ->
+            let lbl2 = new_label() in
+            let cont =
+              instr_cons (Lbranch lbl) [||] [||]
+                (instr_cons (Llabel lbl2) [||] [||] instr.next)
+            in
+            instr.desc <- Lcondbranch (invert_test test, lbl2);
+            instr.next <- cont;
+            fixup true (pc + T.instr_size instr.desc) instr.next
+          | Lcondbranch3 (lbl0, lbl1, lbl2) ->
+            let cont =
+              expand_optbranch lbl0 0 instr.arg
+                (expand_optbranch lbl1 1 instr.arg
+                  (expand_optbranch lbl2 2 instr.arg instr.next))
+            in
+            instr.desc <- cont.desc;
+            instr.next <- cont.next;
+            fixup true pc instr
+          | _ ->
+            Misc.fatal_error "Unsupported instruction for branch relaxation"
+    in
+    fixup false 0 code
+
+  (* Iterate branch expansion till all conditional branches are OK *)
+
+  let rec relax code ~max_out_of_line_code_offset =
+    let min_of_max_branch_offsets =
+      List.fold_left (fun min_of_max_branch_offsets branch ->
+          min min_of_max_branch_offsets
+            (T.Cond_branch.max_displacement branch))
+        max_int T.Cond_branch.all
+    in
+    let (code_size, map) = label_map code in
+    if code_size >= min_of_max_branch_offsets
+        && fixup_branches ~code_size ~max_out_of_line_code_offset map code
+    then relax code ~max_out_of_line_code_offset
+    else ()
+end
diff --git a/asmcomp/branch_relaxation.mli b/asmcomp/branch_relaxation.mli
new file mode 100644
index 0000000..9d517b1
--- /dev/null
+++ b/asmcomp/branch_relaxation.mli
@@ -0,0 +1,26 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                                OCaml                                *)
+(*                                                                     *)
+(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
+(*                   Mark Shinwell, Jane Street Europe                 *)
+(*                                                                     *)
+(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the Q Public License version 1.0.               *)
+(*                                                                     *)
+(***********************************************************************)
+
+(* Fix up conditional branches that exceed hardware-allowed ranges. *)
+
+module Make (T : Branch_relaxation_intf.S) : sig
+  val relax
+     : Linearize.instruction
+    (* [max_offset_of_out_of_line_code] specifies the furthest distance,
+       measured from the first address immediately after the last instruction
+       of the function, that may be branched to from within the function in
+       order to execute "out of line" code blocks such as call GC and
+       bounds check points. *)
+    -> max_out_of_line_code_offset:T.distance
+    -> unit
+end
diff --git a/asmcomp/branch_relaxation_intf.ml b/asmcomp/branch_relaxation_intf.ml
new file mode 100644
index 0000000..fb721b2
--- /dev/null
+++ b/asmcomp/branch_relaxation_intf.ml
@@ -0,0 +1,53 @@
+(***********************************************************************)
+(*                                                                     *)
+(*                                OCaml                                *)
+(*                                                                     *)
+(*                   Mark Shinwell, Jane Street Europe                 *)
+(*                                                                     *)
+(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
+(*  en Automatique.  All rights reserved.  This file is distributed    *)
+(*  under the terms of the Q Public License version 1.0.               *)
+(*                                                                     *)
+(***********************************************************************)
+
+module type S = sig
+  (* The distance between two instructions, in arbitrary units (typically
+     the natural word size of instructions). *)
+  type distance = int
+
+  module Cond_branch : sig
+    (* The various types of conditional branches for a given target that
+       may require relaxation. *)
+    type t
+
+    (* All values of type [t] that the emitter may produce. *)
+    val all : t list
+
+    (* If [max_displacement branch] is [n] then [branch] is assumed to
+       reach any address in the range [pc - n, pc + n] (inclusive), after
+       the [pc] of the branch has been adjusted by [offset_pc_at_branch]
+       (see below). *)
+    val max_displacement : t -> distance
+
+    (* Which variety of conditional branch may be produced by the emitter for a
+       given instruction description.  For the moment we assume that only one
+       such variety per instruction description is needed. *)
+    val classify_instr : Linearize.instruction_desc -> t option
+  end
+
+  (* The value to be added to the program counter (in [distance] units)
+     when it is at a branch instruction, prior to calculating the distance
+     to a branch target. *)
+  val offset_pc_at_branch : distance
+
+  (* The maximum size of a given instruction. *)
+  val instr_size : Linearize.instruction_desc -> distance
+
+  (* Insertion of target-specific code to relax operations that cannot be
+     relaxed generically.  It is assumed that these rewrites do not change
+     the size of out-of-line code (cf. branch_relaxation.mli). *)
+  val relax_allocation : num_words:int -> Linearize.instruction_desc
+  val relax_intop_checkbound : unit -> Linearize.instruction_desc
+  val relax_intop_imm_checkbound : bound:int -> Linearize.instruction_desc
+  val relax_specific_op : Arch.specific_operation -> Linearize.instruction_desc
+end
diff --git a/asmcomp/power/emit.mlp b/asmcomp/power/emit.mlp
index 8e31b58..717ab12 100644
--- a/asmcomp/power/emit.mlp
+++ b/asmcomp/power/emit.mlp
@@ -308,126 +308,87 @@ let defined_functions = ref StringSet.empty
 (* Label of glue code for calling the GC *)
 let call_gc_label = ref 0
 
-(* Fixup conditional branches that exceed hardware allowed range *)
+module BR = Branch_relaxation.Make (struct
+  type distance = int
 
-let load_store_size = function
-    Ibased(s, d) -> 2
-  | Iindexed ofs -> if is_immediate ofs then 1 else 3
-  | Iindexed2 -> 1
+  module Cond_branch = struct
+    type t = Branch
 
-let instr_size = function
-    Lend -> 0
-  | Lop(Imove | Ispill | Ireload) -> 1
-  | Lop(Iconst_int n | Iconst_blockheader n) ->
-    if is_native_immediate n then 1 else 2
-  | Lop(Iconst_float s) -> 2
-  | Lop(Iconst_symbol s) -> 2
-  | Lop(Icall_ind) -> 2
-  | Lop(Icall_imm s) -> 1
-  | Lop(Itailcall_ind) -> 5
-  | Lop(Itailcall_imm s) -> if s = !function_name then 1 else 4
-  | Lop(Iextcall(s, true)) -> 3
-  | Lop(Iextcall(s, false)) -> if pic_externals then 4 else 1
-  | Lop(Istackoffset n) -> 1
-  | Lop(Iload(chunk, addr)) ->
+    let all = [Branch]
+
+    let max_displacement = function
+      (* 14-bit signed offset in words. *)
+      | Branch -> 8192
+
+    let classify_instr = function
+      | Lop (Ialloc _)
+      (* [Ialloc_far] does not need to be here, since its code sequence
+         never involves any conditional branches that might need relaxing. *)
+      | Lcondbranch _
+      | Lcondbranch3 _ -> Some Branch
+      | _ -> None
+  end
+
+  let offset_pc_at_branch = 1
+
+  let load_store_size = function
+    | Ibased(s, d) -> 2
+    | Iindexed ofs -> if is_immediate ofs then 1 else 3
+    | Iindexed2 -> 1
+
+  let instr_size = function
+    | Lend -> 0
+    | Lop(Imove | Ispill | Ireload) -> 1
+    | Lop(Iconst_int n | Iconst_blockheader n) ->
+      if is_native_immediate n then 1 else 2
+    | Lop(Iconst_float s) -> 2
+    | Lop(Iconst_symbol s) -> 2
+    | Lop(Icall_ind) -> 2
+    | Lop(Icall_imm s) -> 1
+    | Lop(Itailcall_ind) -> 5
+    | Lop(Itailcall_imm s) -> if s = !function_name then 1 else 4
+    | Lop(Iextcall(s, true)) -> 3
+    | Lop(Iextcall(s, false)) -> if pic_externals then 4 else 1
+    | Lop(Istackoffset n) -> 1
+    | Lop(Iload(chunk, addr)) ->
       if chunk = Byte_signed
       then load_store_size addr + 1
       else load_store_size addr
-  | Lop(Istore(chunk, addr, _)) -> load_store_size addr
-  | Lop(Ialloc n) -> 4
-  | Lop(Ispecific(Ialloc_far n)) -> 5
-  | Lop(Iintop Imod) -> 3
-  | Lop(Iintop(Icomp cmp)) -> 4
-  | Lop(Iintop op) -> 1
-  | Lop(Iintop_imm(Icomp cmp, n)) -> 4
-  | Lop(Iintop_imm(op, n)) -> 1
-  | Lop(Inegf | Iabsf | Iaddf | Isubf | Imulf | Idivf) -> 1
-  | Lop(Ifloatofint) -> 9
-  | Lop(Iintoffloat) -> 4
-  | Lop(Ispecific sop) -> 1
-  | Lreloadretaddr -> 2
-  | Lreturn -> 2
-  | Llabel lbl -> 0
-  | Lbranch lbl -> 1
-  | Lcondbranch(tst, lbl) -> 2
-  | Lcondbranch3(lbl0, lbl1, lbl2) ->
+    | Lop(Istore(chunk, addr, _)) -> load_store_size addr
+    | Lop(Ialloc n) -> 4
+    | Lop(Ispecific(Ialloc_far n)) -> 5
+    | Lop(Iintop Imod) -> 3
+    | Lop(Iintop(Icomp cmp)) -> 4
+    | Lop(Iintop op) -> 1
+    | Lop(Iintop_imm(Icomp cmp, n)) -> 4
+    | Lop(Iintop_imm(op, n)) -> 1
+    | Lop(Inegf | Iabsf | Iaddf | Isubf | Imulf | Idivf) -> 1
+    | Lop(Ifloatofint) -> 9
+    | Lop(Iintoffloat) -> 4
+    | Lop(Ispecific sop) -> 1
+    | Lreloadretaddr -> 2
+    | Lreturn -> 2
+    | Llabel lbl -> 0
+    | Lbranch lbl -> 1
+    | Lcondbranch(tst, lbl) -> 2
+    | Lcondbranch3(lbl0, lbl1, lbl2) ->
       1 + (if lbl0 = None then 0 else 1)
         + (if lbl1 = None then 0 else 1)
         + (if lbl2 = None then 0 else 1)
-  | Lswitch jumptbl -> 8
-  | Lsetuptrap lbl -> 1
-  | Lpushtrap -> 4
-  | Lpoptrap -> 2
-  | Lraise _ -> 6
-
-let label_map code =
-  let map = Hashtbl.create 37 in
-  let rec fill_map pc instr =
-    match instr.desc with
-      Lend -> (pc, map)
-    | Llabel lbl -> Hashtbl.add map lbl pc; fill_map pc instr.next
-    | op -> fill_map (pc + instr_size op) instr.next
-  in fill_map 0 code
-
-let max_branch_offset = 8180
-(* 14-bit signed offset in words.  Remember to cut some slack
-   for multi-word instructions where the branch can be anywhere in
-   the middle.  12 words of slack is plenty. *)
-
-let branch_overflows map pc_branch lbl_dest =
-  let pc_dest = Hashtbl.find map lbl_dest in
-  let delta = pc_dest - (pc_branch + 1) in
-  delta <= -max_branch_offset || delta >= max_branch_offset
-
-let opt_branch_overflows map pc_branch opt_lbl_dest =
-  match opt_lbl_dest with
-    None -> false
-  | Some lbl_dest -> branch_overflows map pc_branch lbl_dest
-
-let fixup_branches codesize map code =
-  let expand_optbranch lbl n arg next =
-    match lbl with
-      None -> next
-    | Some l ->
-        instr_cons (Lcondbranch(Iinttest_imm(Isigned Ceq, n), l))
-                   arg [||] next in
-  let rec fixup did_fix pc instr =
-    match instr.desc with
-      Lend -> did_fix
-    | Lcondbranch(test, lbl) when branch_overflows map pc lbl ->
-        let lbl2 = new_label() in
-        let cont =
-          instr_cons (Lbranch lbl) [||] [||]
-            (instr_cons (Llabel lbl2) [||] [||] instr.next) in
-        instr.desc <- Lcondbranch(invert_test test, lbl2);
-        instr.next <- cont;
-        fixup true (pc + 2) instr.next
-    | Lcondbranch3(lbl0, lbl1, lbl2)
-      when opt_branch_overflows map pc lbl0
-        || opt_branch_overflows map pc lbl1
-        || opt_branch_overflows map pc lbl2 ->
-        let cont =
-          expand_optbranch lbl0 0 instr.arg
-            (expand_optbranch lbl1 1 instr.arg
-              (expand_optbranch lbl2 2 instr.arg instr.next)) in
-        instr.desc <- cont.desc;
-        instr.next <- cont.next;
-        fixup true pc instr
-    | Lop(Ialloc n) when codesize - pc >= max_branch_offset ->
-        instr.desc <- Lop(Ispecific(Ialloc_far n));
-        fixup true (pc + 4) instr.next
-    | op ->
-        fixup did_fix (pc + instr_size op) instr.next
-  in fixup false 0 code
-
-(* Iterate branch expansion till all conditional branches are OK *)
-
-let rec branch_normalization code =
-  let (codesize, map) = label_map code in
-  if codesize >= max_branch_offset && fixup_branches codesize map code
-  then branch_normalization code
-  else ()
-
+    | Lswitch jumptbl -> 8
+    | Lsetuptrap lbl -> 1
+    | Lpushtrap -> 4
+    | Lpoptrap -> 2
+    | Lraise _ -> 6
+
+  let relax_allocation ~num_words = Lop (Ispecific (Ialloc_far num_words))
+
+  (* [classify_addr], above, never identifies these instructions as needing
+     relaxing.  As such, these functions should never be called. *)
+  let relax_specific_op _ = assert false
+  let relax_intop_checkbound () = assert false
+  let relax_intop_imm_checkbound ~bound:_ = assert false
+end)
 
 (* Output the assembly code for an instruction *)
 
@@ -848,7 +809,10 @@ let fundecl fundecl =
       `	addi	{emit_gpr 1}, {emit_gpr 1}, {emit_int(-n)}\n`
   end;
   `{emit_label !tailrec_entry_point}:\n`;
-  branch_normalization fundecl.fun_body;
+  (* On this target, there is at most one "out of line" code block per
+     function: a single "call GC" point.  It comes immediately after the
+     function's body. *)
+  BR.relax fundecl.fun_body ~max_out_of_line_code_offset:0;
   emit_all fundecl.fun_body;
   (* Emit the glue code to call the GC *)
   if !call_gc_label > 0 then begin
-- 
2.4.1