diff mbox

[ARM,2/2] Add -mexecute-only option.

Message ID 1453812695-1098-3-git-send-email-mickael.guene@st.com
State New
Headers show

Commit Message

Mickael Guene Jan. 26, 2016, 12:51 p.m. UTC
gcc/ChangeLog:

	* config/arm/arm-protos.h (arm_modes_tieable_p): New.
	* config/arm/arm.c (arm_function_section): New.
	(arm_section_type_flags): New.
	(TARGET_ASM_FUNCTION_SECTION): Define.
	(TARGET_SECTION_TYPE_FLAGS): Define.
	(arm_option_override): Add mexecute-only new option.
	(thumb1_gen_const_int): New.
	(thumb1_legitimate_address_p): Disallow constant pool usage for thumb1
	for arm_disable_literal_pool.
	(thumb1_rtx_costs): Update cost for arm_disable_literal_pool.
	(thumb1_size_rtx_costs): Likewise.
	(arm_output_mi_thunk): Avoid literal usage for target_execute_only.
	* config/arm/arm.md (casesi): Disable for target_execute_only.
	* config/arm/arm.opt (target_execute_only): New option.
	* config/arm/thumb1.md (define_insn "thumb1_movsi_symbol_ref"): New.
	(define_insn "*thumb1_movsi_const_int"): New.
	(define_split for generate integer constant): New.
	(define_insn "*thumb1_movsi_insn"): Set use_literal_pool attribute so
	it's enabled/disabled according to arm_disable_literal_pool.
	(define_expand "tablejump"): Disable for target_execute_only.
	* doc/invoke.texi (mexecute-only): New.

gcc/testsuite/ChangeLog:

	* gcc.target/arm/thumb1-execute-only-switch.c: New.
	* gcc.target/arm/thumb1-execute-only.c: New.
	* gcc.target/arm/thumb2-execute-only-switch.c: New.
	* gcc.target/arm/thumb2-execute-only.c: New.

 This option generate code that don't load no data from text section.
---
 gcc/config/arm/arm-protos.h                        |   1 +
 gcc/config/arm/arm.c                               | 114 +++++++++++++++++++--
 gcc/config/arm/arm.md                              |   2 +-
 gcc/config/arm/arm.opt                             |   4 +
 gcc/config/arm/thumb1.md                           |  71 +++++++++++--
 gcc/doc/invoke.texi                                |   7 ++
 .../gcc.target/arm/thumb1-execute-only-switch.c    |  23 +++++
 gcc/testsuite/gcc.target/arm/thumb1-execute-only.c |  69 +++++++++++++
 .../gcc.target/arm/thumb2-execute-only-switch.c    |  23 +++++
 gcc/testsuite/gcc.target/arm/thumb2-execute-only.c |  68 ++++++++++++
 10 files changed, 368 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c
 create mode 100644 gcc/testsuite/gcc.target/arm/thumb1-execute-only.c
 create mode 100644 gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c
 create mode 100644 gcc/testsuite/gcc.target/arm/thumb2-execute-only.c
diff mbox

Patch

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 28f2263..e08842e 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -59,6 +59,7 @@  extern bool arm_modes_tieable_p (machine_mode, machine_mode);
 extern int const_ok_for_arm (HOST_WIDE_INT);
 extern int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
 extern int const_ok_for_dimode_op (HOST_WIDE_INT, enum rtx_code);
+extern void thumb1_gen_const_int (rtx, HOST_WIDE_INT);
 extern int arm_split_constant (RTX_CODE, machine_mode, rtx,
 			       HOST_WIDE_INT, rtx, rtx, int);
 extern int legitimate_pic_operand_p (rtx);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index f152afa..fe8e018 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -300,6 +300,12 @@  static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
 static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void);
 
 static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*);
+
+static section *arm_function_section (tree decl, enum node_frequency freq,
+				      bool startup, bool exit);
+
+static unsigned int arm_section_type_flags (tree, const char *, int);
+
 
 /* Table of machine attributes.  */
 static const struct attribute_spec arm_attribute_table[] =
@@ -735,6 +741,12 @@  static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_SCHED_FUSION_PRIORITY
 #define TARGET_SCHED_FUSION_PRIORITY arm_sched_fusion_priority
 
+#undef  TARGET_ASM_FUNCTION_SECTION
+#define TARGET_ASM_FUNCTION_SECTION arm_function_section
+
+#undef  TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS arm_section_type_flags
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Obstack for minipool constant handling.  */
@@ -3428,6 +3440,15 @@  arm_option_override (void)
   if (target_slow_flash_data)
     arm_disable_literal_pool = true;
 
+  /* We only support -mexecute-only on M-profile targets.  */
+  if (target_execute_only && (flag_pic || !(!arm_arch_notm || arm_arch7em)))
+    error ("-mexecute-only only supports non-pic code on M-profile targets");
+
+  /* In execute-only mode we don't want any memory read into text section and
+     so we disable literal pool.  */
+  if (target_execute_only)
+    arm_disable_literal_pool = true;
+
   /* Disable scheduling fusion by default if it's not armv7 processor
      or doesn't prefer ldrd/strd.  */
   if (flag_schedule_fusion == 2
@@ -3969,6 +3990,36 @@  const_ok_for_dimode_op (HOST_WIDE_INT i, enum rtx_code code)
     }
 }
 
+/* Emit a sequence of movs/adds/shift to produce a 32-bit constant.
+   Avoid generating useless code when byte is zero.  */
+void
+thumb1_gen_const_int (rtx op0, HOST_WIDE_INT op1)
+{
+  int is_mov_done = 0;
+  int i;
+
+  /* Emit upper 3 bytes if needed.  */
+  for (i = 0; i < 3; i++)
+    {
+      int byte = (op1 >> (8 * (3 - i))) & 0xff;
+
+      if (byte)
+	{
+	  emit_set_insn (op0, is_mov_done?
+			      gen_rtx_PLUS (SImode,op0, GEN_INT (byte)):
+			      GEN_INT (byte));
+	  is_mov_done = 1;
+	}
+      if (is_mov_done)
+	emit_set_insn (op0, gen_rtx_ASHIFT (SImode, op0, GEN_INT (8)));
+    }
+  /* Emit lower byte if needed.  */
+  if (!is_mov_done)
+    emit_set_insn (op0, GEN_INT (op1&0xff));
+  else if (op1&0xff)
+    emit_set_insn (op0, gen_rtx_PLUS (SImode, op0, GEN_INT (op1&0xff)));
+}
+
 /* Emit a sequence of insns to handle a large constant.
    CODE is the code of the operation required, it can be any of SET, PLUS,
    IOR, AND, XOR, MINUS;
@@ -7621,7 +7672,8 @@  thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
   /* This is PC relative data before arm_reorg runs.  */
   else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
 	   && GET_CODE (x) == SYMBOL_REF
-           && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
+	   && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic
+	   && !arm_disable_literal_pool)
     return 1;
 
   /* This is PC relative data after arm_reorg runs.  */
@@ -7689,6 +7741,7 @@  thumb1_legitimate_address_p (machine_mode mode, rtx x, int strict_p)
 	   && GET_MODE_SIZE (mode) == 4
 	   && GET_CODE (x) == SYMBOL_REF
 	   && CONSTANT_POOL_ADDRESS_P (x)
+	   && !arm_disable_literal_pool
 	   && ! (flag_pic
 		 && symbol_mentioned_p (get_pool_constant (x))
 		 && ! pcrel_constant_p (get_pool_constant (x))))
@@ -8296,7 +8349,8 @@  thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
 	    return 0;
 	  if (thumb_shiftable_const (INTVAL (x)))
 	    return COSTS_N_INSNS (2);
-	  return COSTS_N_INSNS (3);
+	  return arm_disable_literal_pool ? COSTS_N_INSNS (8) :\
+					    COSTS_N_INSNS (3);
 	}
       else if ((outer == PLUS || outer == COMPARE)
 	       && INTVAL (x) < 256 && INTVAL (x) > -256)
@@ -9058,7 +9112,8 @@  thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
 	  /* See split "TARGET_THUMB1 && satisfies_constraint_K".  */
           if (thumb_shiftable_const (INTVAL (x)))
             return COSTS_N_INSNS (2);
-          return COSTS_N_INSNS (3);
+	  return arm_disable_literal_pool ? COSTS_N_INSNS (8) :\
+					    COSTS_N_INSNS (3);
         }
       else if ((outer == PLUS || outer == COMPARE)
                && INTVAL (x) < 256 && INTVAL (x) > -256)
@@ -26097,14 +26152,36 @@  arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
 	  /* push r3 so we can use it as a temporary.  */
 	  /* TODO: Omit this save if r3 is not used.  */
 	  fputs ("\tpush {r3}\n", file);
-	  fputs ("\tldr\tr3, ", file);
+	  if (target_execute_only)
+	    {
+	      fputs ("\tmovs\tr3, #:upper8_15:#", file);
+	      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+	      fputc ('\n', file);
+	      fputs ("\tlsls r3, #8\n", file);
+	      fputs ("\tadds\tr3, #:upper0_7:#", file);
+	      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+	      fputc ('\n', file);
+	      fputs ("\tlsls r3, #8\n", file);
+	      fputs ("\tadds\tr3, #:lower8_15:#", file);
+	      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+	      fputc ('\n', file);
+	      fputs ("\tlsls r3, #8\n", file);
+	      fputs ("\tadds\tr3, #:lower0_7:#", file);
+	      assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+	      fputc ('\n', file);
+	    }
+	  else
+	    fputs ("\tldr\tr3, ", file);
 	}
       else
 	{
 	  fputs ("\tldr\tr12, ", file);
 	}
-      assemble_name (file, label);
-      fputc ('\n', file);
+      if (!target_execute_only)
+	{
+	  assemble_name (file, label);
+	  fputc ('\n', file);
+	}
       if (flag_pic)
 	{
 	  /* If we are generating PIC, the ldr instruction below loads
@@ -30188,4 +30265,29 @@  arm_sched_fusion_priority (rtx_insn *insn, int max_pri,
   return;
 }
 
+/* Implement the TARGET_ASM_FUNCTION_SECTION hook.
+
+   Be sure that code compiled with mexecute-only is not moved in a section
+   name '.text' so SECTION_NOREAD attribute is not removed by assembler.  */
+static section *
+arm_function_section (tree decl,
+		      enum node_frequency freq,
+		      bool startup,
+		      bool exit)
+{
+  return target_execute_only ?
+	 get_named_text_section (decl, ".text.noread", NULL):
+	 default_function_section (decl, freq, startup, exit);
+}
+
+/* Implement the TARGET_SECTION_TYPE_FLAGS hook.  */
+
+static unsigned int
+arm_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+  return target_execute_only ? flags|SECTION_NOREAD : flags;
+}
+
 #include "gt-arm.h"
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 64873a2..a0ccbc6 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8179,7 +8179,7 @@ 
    (match_operand:SI 2 "const_int_operand" "")	; total range
    (match_operand:SI 3 "" "")			; table label
    (match_operand:SI 4 "" "")]			; Out of range label
-  "TARGET_32BIT || optimize_size || flag_pic"
+  "(TARGET_32BIT || optimize_size || flag_pic) && !target_execute_only"
   "
   {
     enum insn_code code;
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 0ebe017..b16a51a 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -281,3 +281,7 @@  Assume loading data from flash is slower than fetching instructions.
 masm-syntax-unified
 Target Report Var(inline_asm_unified) Init(0) Save
 Assume unified syntax for inline assembly code.
+
+mexecute-only
+Target Report Var(target_execute_only) Init(0)
+Forbid load into text sections.
diff --git a/gcc/config/arm/thumb1.md b/gcc/config/arm/thumb1.md
index 072ed4d..b4e0a0a 100644
--- a/gcc/config/arm/thumb1.md
+++ b/gcc/config/arm/thumb1.md
@@ -41,7 +41,62 @@ 
 ;; differently).  In particular there is no Thumb1 armv6-m pattern for
 ;; sbc or adc.
 
+(define_insn "thumb1_movsi_symbol_ref"
+  [(set (match_operand:SI 0 "register_operand" "=l")
+	(match_operand:SI 1 "general_operand" ""))
+   ]
+  "TARGET_THUMB1
+   && arm_disable_literal_pool
+   && GET_CODE (operands[1]) == SYMBOL_REF"
+  "*
+  output_asm_insn (\"movs\\t%0, #:upper8_15:%1\", operands);
+  output_asm_insn (\"lsls\\t%0, #8\", operands);
+  output_asm_insn (\"adds\\t%0, #:upper0_7:%1\", operands);
+  output_asm_insn (\"lsls\\t%0, #8\", operands);
+  output_asm_insn (\"adds\\t%0, #:lower8_15:%1\", operands);
+  output_asm_insn (\"lsls\\t%0, #8\", operands);
+  output_asm_insn (\"adds\\t%0, #:lower0_7:%1\", operands);
+  return \"\";
+  "
+  [(set_attr "length" "14")
+   (set_attr "conds" "clob")]
+)
+
+(define_insn "*thumb1_movsi_const_int"
+  [(set (match_operand:SI 0 "register_operand" "=l")
+	(match_operand:SI 1 "immediate_operand" "i"))
+   ]
+  "TARGET_THUMB1
+   && arm_disable_literal_pool
+   && GET_CODE (operands[1]) == CONST_INT
+   && !satisfies_constraint_I (operands[1])"
+  "*
+  output_asm_insn (\"movs\\t%0, #(%c1>>24)&0xff\", operands);
+  output_asm_insn (\"lsls\\t%0, #8\", operands);
+  output_asm_insn (\"adds\\t%0, #(%c1>>16)&0xff\", operands);
+  output_asm_insn (\"lsls\\t%0, #8\", operands);
+  output_asm_insn (\"adds\\t%0, #(%c1>>8)&0xff\", operands);
+  output_asm_insn (\"lsls\\t%0, #8\", operands);
+  output_asm_insn (\"adds\\t%0, #%c1&0xff\", operands);
+  return \"\";
+  "
+  [(set_attr "length" "14")
+   (set_attr "conds" "clob")]
+)
 
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+	(match_operand:SI 1 "immediate_operand" ""))]
+  "TARGET_THUMB1
+   && arm_disable_literal_pool
+   && GET_CODE (operands[1]) == CONST_INT
+   && !satisfies_constraint_I (operands[1])"
+  [(clobber (const_int 0))]
+  "
+    thumb1_gen_const_int (operands[0], INTVAL (operands[1]));
+    DONE;
+  "
+)
 
 (define_insn "*thumb1_adddi3"
   [(set (match_operand:DI          0 "register_operand" "=l")
@@ -632,8 +687,8 @@ 
 )
 
 (define_insn "*thumb1_movsi_insn"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l, m,*l*h*k")
-	(match_operand:SI 1 "general_operand"      "l, I,J,K,>,l,mi,l,*l*h*k"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=l,l,l,l,l,>,l,l, m,*l*h*k")
+       (match_operand:SI 1 "general_operand"      "l, I,J,K,>,l,m,mi,l,*l*h*k"))]
   "TARGET_THUMB1
    && (   register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))"
@@ -645,12 +700,14 @@ 
    ldmia\\t%1, {%0}
    stmia\\t%0, {%1}
    ldr\\t%0, %1
+   ldr\\t%0, %1
    str\\t%1, %0
    mov\\t%0, %1"
-  [(set_attr "length" "2,2,4,4,2,2,2,2,2")
-   (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,store1,mov_reg")
-   (set_attr "pool_range" "*,*,*,*,*,*,1018,*,*")
-   (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond")])
+  [(set_attr "length" "2,2,4,4,2,2,2,2,2,2")
+   (set_attr "type" "mov_reg,mov_imm,multiple,multiple,load1,store1,load1,load1,store1,mov_reg")
+   (set_attr "pool_range" "*,*,*,*,*,*,1018,1018,*,*")
+   (set_attr "use_literal_pool" "no,no,no,no,no,no,no,yes,no,no")
+   (set_attr "conds" "set,clob,*,*,nocond,nocond,nocond,nocond,nocond,nocond")])
 
 ; Split the load of 64-bit constant into two loads for high and low 32-bit parts respectively
 ; to see if we can load them in fewer instructions or fewer cycles.
@@ -1760,7 +1817,7 @@ 
 (define_expand "tablejump"
   [(parallel [(set (pc) (match_operand:SI 0 "register_operand" ""))
 	      (use (label_ref (match_operand 1 "" "")))])]
-  "TARGET_THUMB1"
+  "TARGET_THUMB1 && !target_execute_only"
   "
   if (flag_pic)
     {
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ba0b4b2..cb43fdd 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -630,6 +630,7 @@  Objective-C and Objective-C++ Dialects}.
 -munaligned-access @gol
 -mneon-for-64bits @gol
 -mslow-flash-data @gol
+-mexecute-only @gol
 -masm-syntax-unified @gol
 -mrestrict-it}
 
@@ -14139,6 +14140,12 @@  Therefore literal load is minimized for better performance.
 This option is only supported when compiling for ARMv7 M-profile and
 off by default.
 
+@item -mexecute-only
+@opindex mexecute-only
+Disable read memory access inside code sections.  Only code fetching is
+allowed.
+This option is off by default.
+
 @item -masm-syntax-unified
 @opindex masm-syntax-unified
 Assume inline assembler is using unified asm syntax.  The default is
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c b/gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c
new file mode 100644
index 0000000..f9bba9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb1-execute-only-switch.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-options "-O2 -march=armv6s-m -mthumb -mexecute-only" } */
+
+int
+foo (int a)
+{
+  switch (a)
+    {
+      case 0: return 12;
+      case 1: return 2;
+      case 2: return 1231;
+      case 3: return 0xdead;
+      default:
+	break;
+    }
+
+  return -1;
+}
+
+/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/thumb1-execute-only.c b/gcc/testsuite/gcc.target/arm/thumb1-execute-only.c
new file mode 100644
index 0000000..90b74df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb1-execute-only.c
@@ -0,0 +1,69 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb1_ok } */
+/* { dg-options "-O2 -march=armv6s-m -mthumb -mexecute-only" } */
+
+float sf;
+double df;
+long long l;
+static char *p = "Hello World";
+
+float
+testsf (float *p)
+{
+  if (*p > 1.1234f)
+    return 2.1234f;
+  else
+    return 3.1234f;
+}
+
+double
+testdf (double *p)
+{
+  if (*p > 4.1234)
+    return 2.1234;
+  else
+    return 3.1234;
+}
+
+long long
+testll (long long *p)
+{
+  if (*p > 0x123456789ABCDEFll)
+    return 0x111111111ll;
+  else
+    return 0x222222222ll;
+}
+
+char *
+testchar ()
+{
+  return p + 4;
+}
+
+int
+foo (int a, int b)
+{
+  int i;
+  int *labelref = &&label1;
+
+  if (a > b)
+    {
+      while (i < b)
+	{
+	  a += *labelref;
+	  i += 1;
+	}
+      goto *labelref;
+    }
+  else
+    b = b + 3;
+
+  a = a * b;
+
+label1:
+  return a + b;
+}
+
+/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */
+
diff --git a/gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c b/gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c
new file mode 100644
index 0000000..2493c28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb2-execute-only-switch.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-options "-O2 -march=armv7-m -mthumb -mexecute-only" } */
+
+int
+foo (int a)
+{
+  switch (a)
+    {
+      case 0: return 12;
+      case 1: return 2;
+      case 2: return 1231;
+      case 3: return 0xdead;
+      default:
+	break;
+    }
+
+  return -1;
+}
+
+/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */
+/* { dg-final { scan-assembler-not "ldrls\[\t \]+r\[0-9\]+, .L" } } */
diff --git a/gcc/testsuite/gcc.target/arm/thumb2-execute-only.c b/gcc/testsuite/gcc.target/arm/thumb2-execute-only.c
new file mode 100644
index 0000000..10b7fd1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/thumb2-execute-only.c
@@ -0,0 +1,68 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_cortex_m } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+/* { dg-options "-O2 -march=armv7-m -mthumb -mexecute-only" } */
+
+float sf;
+double df;
+long long l;
+static char *p = "Hello World";
+
+float
+testsf (float *p)
+{
+  if (*p > 1.1234f)
+    return 2.1234f;
+  else
+    return 3.1234f;
+}
+
+double
+testdf (double *p)
+{
+  if (*p > 4.1234)
+    return 2.1234;
+  else
+    return 3.1234;
+}
+
+long long
+testll (long long *p)
+{
+  if (*p > 0x123456789ABCDEFll)
+    return 0x111111111ll;
+  else
+    return 0x222222222ll;
+}
+
+char *
+testchar ()
+{
+  return p + 4;
+}
+
+int
+foo (int a, int b)
+{
+  int i;
+  int *labelref = &&label1;
+
+  if (a > b)
+    {
+      while (i < b)
+	{
+	  a += *labelref;
+	  i += 1;
+	}
+      goto *labelref;
+    }
+  else
+    b = b + 3;
+
+  a = a * b;
+
+label1:
+  return a + b;
+}
+
+/* { dg-final { scan-assembler-not "ldr\[\t \]+r\[0-9\]+, .L" } } */