+2016-11-15 Maciej W. Rozycki <macro@imgtec.com>
+
+ * config/mips/mips.c (mips16_emit_constants): Emit `consttable'
+ insn at the beginning of the constant pool.
+ (mips_insert_insn_pseudos): New function.
+ (mips_machine_reorg2): Call it.
+ * config/mips/mips.md (unspec): Add UNSPEC_CONSTTABLE and
+ UNSPEC_INSN_PSEUDO enum values.
+ (insn_pseudo, consttable): New insns.
+
2016-11-15 Michael Matz <matz@suse.de>
PR missed-optimization/77881
int align;
align = 0;
+ if (constants)
+ insn = emit_insn_after (gen_consttable (), insn);
for (c = constants; c != NULL; c = next)
{
/* If necessary, increase the alignment of PC. */
while (something_changed);
}
+/* Insert a `.insn' assembly pseudo-op after any labels followed by
+ a MIPS16 constant pool or no insn at all. This is needed so that
+ targets that have been optimized away are still marked as code
+ and therefore branches that remained and point to them are known
+ to retain the ISA mode and as such can be successfully assembled. */
+
+static void
+mips_insert_insn_pseudos (void)
+{
+ bool insn_pseudo_needed = TRUE;
+ rtx_insn *insn;
+
+ for (insn = get_last_insn (); insn != NULL_RTX; insn = PREV_INSN (insn))
+ switch (GET_CODE (insn))
+ {
+ case INSN:
+ if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+ && XINT (PATTERN (insn), 1) == UNSPEC_CONSTTABLE)
+ {
+ insn_pseudo_needed = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case JUMP_INSN:
+ case CALL_INSN:
+ case JUMP_TABLE_DATA:
+ insn_pseudo_needed = FALSE;
+ break;
+ case CODE_LABEL:
+ if (insn_pseudo_needed)
+ {
+ emit_insn_after (gen_insn_pseudo (), insn);
+ insn_pseudo_needed = FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
/* Implement TARGET_MACHINE_DEPENDENT_REORG. */
static void
optimizations, but this should be an extremely rare case anyhow. */
mips_reorg_process_insns ();
mips16_split_long_branches ();
+ mips_insert_insn_pseudos ();
return 0;
}
;; MIPS16 constant pools.
UNSPEC_ALIGN
+ UNSPEC_CONSTTABLE
UNSPEC_CONSTTABLE_INT
UNSPEC_CONSTTABLE_FLOAT
;; Stack checking.
UNSPEC_PROBE_STACK_RANGE
+
+ ;; The `.insn' pseudo-op.
+ UNSPEC_INSN_PSEUDO
])
(define_constants
return "#nop";
}
[(set_attr "type" "nop")])
+
+;; The `.insn' pseudo-op.
+(define_insn "insn_pseudo"
+ [(unspec_volatile [(const_int 0)] UNSPEC_INSN_PSEUDO)]
+ ""
+ ".insn"
+ [(set_attr "mode" "none")
+ (set_attr "insn_count" "0")])
\f
;; MIPS4 Conditional move instructions.
;; ....................
;;
+(define_insn "consttable"
+ [(unspec_volatile [(const_int 0)] UNSPEC_CONSTTABLE)]
+ ""
+ ""
+ [(set_attr "mode" "none")
+ (set_attr "insn_count" "0")])
+
(define_insn "consttable_tls_reloc"
[(unspec_volatile [(match_operand 0 "tls_reloc_operand" "")
(match_operand 1 "const_int_operand" "")]
+2016-11-15 Maciej W. Rozycki <macro@imgtec.com>
+
+ * gcc.target/mips/insn-casesi.c: New test case.
+ * gcc.target/mips/insn-pseudo-1.c: New test case.
+ * gcc.target/mips/insn-pseudo-2.c: New test case.
+ * gcc.target/mips/insn-pseudo-3.c: New test case.
+ * gcc.target/mips/insn-pseudo-4.c: New test case.
+ * gcc.target/mips/insn-tablejump.c: New test case.
+
2016-11-15 Maciej W. Rozycki <macro@imgtec.com>
* gcc.target/mips/mips.exp (mips_option_tests): Add
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-mips16 -mcode-readable=yes" } */
+
+int __attribute__ ((noinline))
+frob (int i)
+{
+ switch (i)
+ {
+ case -5:
+ return -2;
+ case -3:
+ return -1;
+ case 0:
+ return 0;
+ case 3:
+ return 1;
+ case 5:
+ break;
+ default:
+ __builtin_unreachable ();
+ }
+ return i;
+}
+
+int
+main (int argc, char **argv)
+{
+ asm ("" : "+r" (argc));
+ argc = frob ((argc & 10) - 5);
+ asm ("" : "+r" (argc));
+ return !argc;
+}
+
+/* This will result in assembly like:
+
+ .text
+ .align 2
+ .globl frob
+ .set mips16
+ .set nomicromips
+ .ent frob
+ .type frob, @function
+frob:
+ .frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
+ .mask 0x00000000,0
+ .fmask 0x00000000,0
+ addiu $2,$4,5
+ sltu $2,11
+ bteqz $L2
+ sll $3,$2,1
+ la $2,$L4
+ addu $3,$2,$3
+ lh $3,0($3)
+ addu $2,$2,$3
+ j $2
+ .align 1
+ .align 2
+$L4:
+ .half $L3-$L4
+ .half $L2-$L4
+ .half $L9-$L4
+ .half $L2-$L4
+ .half $L2-$L4
+ .half $L8-$L4
+ .half $L2-$L4
+ .half $L2-$L4
+ .half $L7-$L4
+ .half $L2-$L4
+ .half $L8-$L4
+$L8:
+ .set noreorder
+ .set nomacro
+ jr $31
+ move $2,$4
+ .set macro
+ .set reorder
+
+$L9:
+ li $2,1
+ .set noreorder
+ .set nomacro
+ jr $31
+ neg $2,$2
+ .set macro
+ .set reorder
+
+$L3:
+ li $2,2
+ .set noreorder
+ .set nomacro
+ jr $31
+ neg $2,$2
+ .set macro
+ .set reorder
+
+$L7:
+ .set noreorder
+ .set nomacro
+ jr $31
+ li $2,1
+ .set macro
+ .set reorder
+
+$L2:
+ .insn
+ .end frob
+ .size frob, .-frob
+
+ for `frob' and we want to make sure it links correctly owing to the
+ `.insn' pseudo-op which needs to be there at `$L2' as there's no
+ code following and the label is a MIPS16 branch target (even though
+ the branch is never taken. See also insn-tablejump.c. */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-mno-micromips -mno-mips16" } */
+
+void
+unreachable (int i)
+{
+ asm volatile goto ("b\t.\n\tbeqz\t%0,%l1" : : "r" (i) : : punt);
+punt:
+ __builtin_unreachable ();
+}
+
+/* Expect assembly like:
+
+ beqz $4,$L2
+ # Anything goes here.
+$L2: # The label must match.
+ .insn
+$L3 = . # It's there, but we don't care.
+ .end unreachable
+
+ that is .insn to be inserted if a code label is at function's end. */
+
+/* { dg-final { scan-assembler "\tbeqz\t\\\$\[0-9\]+,(.L\[0-9\]+)\n.*\n\\1:\n\t\\.insn\n(?:.L\[0-9\]+ = \\.\n)?\t\\.end\tunreachable\n" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-mmicromips" } */
+
+void
+unreachable (int i)
+{
+ asm volatile goto ("b\t.\n\tbeqz\t%0,%l1" : : "r" (i) : : punt);
+punt:
+ __builtin_unreachable ();
+}
+
+/* Expect assembly like:
+
+ beqz $4,$L2
+ # Anything goes here.
+$L2: # The label must match.
+ .insn
+$L3 = . # It's there, but we don't care.
+ .end unreachable
+
+ that is .insn to be inserted if a code label is at function's end. */
+
+/* { dg-final { scan-assembler "\tbeqz\t\\\$\[0-9\]+,(.L\[0-9\]+)\n.*\n\\1:\n\t\\.insn\n(?:.L\[0-9\]+ = \\.\n)?\t\\.end\tunreachable\n" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-mips16" } */
+
+void
+unreachable (int i)
+{
+ asm volatile goto ("b\t.\n\tbeqz\t%0,%l1" : : "r" (i) : : punt);
+punt:
+ __builtin_unreachable ();
+}
+
+/* Expect assembly like:
+
+ beqz $4,$L2
+ # Anything goes here.
+$L2: # The label must match.
+ .insn
+$L3 = . # It's there, but we don't care.
+ .end unreachable
+
+ that is .insn to be inserted if a code label is at function's end. */
+
+/* { dg-final { scan-assembler "\tbeqz\t\\\$\[0-9\]+,(.L\[0-9\]+)\n.*\n\\1:\n\t\\.insn\n(?:.L\[0-9\]+ = \\.\n)?\t\\.end\tunreachable\n" } } */
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-mips16 -mcode-readable=yes" } */
+
+void
+unreachable (void)
+{
+ asm volatile goto ("b\t.\n\tbeqz\t%0,%l1" : : "r" (0x12345678) : : punt);
+punt:
+ __builtin_unreachable ();
+}
+
+/* Expect assembly like:
+
+ lw $2,$L5
+ # Anything goes here.
+ beqz $2,$L2 # The register must match.
+ # Anything goes here.
+$L2: # The label must match.
+ .insn
+$L3 = . # It's there, but we don't care.
+ .align 2
+$L5: # The label must match.
+ .word 305419896
+
+ that is .insn to be inserted if a code label is at a constant pool. */
+
+/* { dg-final { scan-assembler "\tlw\t(\\\$\[0-9\]+),(.L\[0-9\]+)\n.*\tbeqz\t\\1,(.L\[0-9\]+)\n.*\n\\3:\n\t\\.insn\n(?:.L\[0-9\]+ = \\.\n)?\t\\.align\t2\n\\2:\n\t\\.word\t305419896\n" } } */
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-mmicromips" } */
+
+int __attribute__ ((noinline))
+frob (int i)
+{
+ switch (i)
+ {
+ case -5:
+ return -2;
+ case -3:
+ return -1;
+ case 0:
+ return 0;
+ case 3:
+ return 1;
+ case 5:
+ break;
+ default:
+ __builtin_unreachable ();
+ }
+ return i;
+}
+
+int
+main (int argc, char **argv)
+{
+ asm ("" : "+r" (argc));
+ argc = frob ((argc & 10) - 5);
+ asm ("" : "+r" (argc));
+ return !argc;
+}
+
+/* This will result in assembly like:
+
+ .text
+ .align 2
+ .globl frob
+ .set nomips16
+ .set micromips
+ .ent frob
+ .type frob, @function
+frob:
+ .frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
+ .mask 0x00000000,0
+ .fmask 0x00000000,0
+ .set noreorder
+ .set nomacro
+ addiu $3,$4,5
+ sltu $2,$3,11
+ beqzc $2,$L2
+ lui $2,%hi($L4)
+ addiu $2,$2,%lo($L4)
+ lwxs $3,$3($2)
+ jrc $3
+ .rdata
+ .align 2
+ .align 2
+$L4:
+ .word $L3
+ .word $L2
+ .word $L9
+ .word $L2
+ .word $L2
+ .word $L8
+ .word $L2
+ .word $L2
+ .word $L7
+ .word $L2
+ .word $L8
+ .text
+$L8:
+ jr $31
+ move $2,$4
+
+$L9:
+ jr $31
+ li $2,-1 # 0xffffffffffffffff
+
+$L3:
+ jr $31
+ li $2,-2 # 0xfffffffffffffffe
+
+$L7:
+ jr $31
+ li $2,1 # 0x1
+
+$L2:
+ .insn
+ .set macro
+ .set reorder
+ .end frob
+ .size frob, .-frob
+
+ for `frob' and we want to make sure it links correctly owing to the
+ `.insn' pseudo-op which needs to be there at `$L2' as there's no
+ code following and the label is a microMIPS branch target (even though
+ the branch is never taken. See also insn-casesi.c. */