This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 3/3] MIPS/GCC: Mark trailing labels with `.insn'
- From: "Maciej W. Rozycki" <macro at imgtec dot com>
- To: <gcc-patches at gcc dot gnu dot org>
- Cc: Matthew Fortune <Matthew dot Fortune at imgtec dot com>, Catherine Moore <clm at codesourcery dot com>
- Date: Fri, 11 Nov 2016 10:38:31 +0000
- Subject: [PATCH 3/3] MIPS/GCC: Mark trailing labels with `.insn'
- Authentication-results: sourceware.org; auth=none
- References: <alpine.DEB.2.20.17.1611081751280.10580@tp.orcam.me.uk>
Mark trailing labels, either at the end of a function or preceding a
MIPS16 constant pool, with the `.insn' assembly pseudo-op so that they
are considered code rather than data labels and consequently have ISA
annotation added in the symbol table by the assembler.
Such labels are created for some cases of unreachable code like with the
following example:
$ cat switch.c
int
foo (int i)
{
static int j;
j += 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 j;
}
$ gcc -S -mips16 -O2 -o switch-mips16.s switch.c
$ cat switch-mips16.s
.file 1 "switch.c"
.section .mdebug.abi32
.previous
.nan legacy
.module fp=xx
.module nooddspreg
.abicalls
.option pic0
.text
.align 2
.globl foo
.set mips16
.set nomicromips
.ent foo
.type foo, @function
foo:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
lw $3,$L11
lw $2,0($3)
addu $2,$4,$2
sw $2,0($3)
addiu $3,$4,5
sltu $3, 11
bteqz $L2
sll $5, $3, 1
la $3, $L4
addu $5, $3, $5
lh $5, 0($5)
addu $3, $3, $5
j $3
.align 1
.align 2
$L4:
.half $L9-$L4
.half $L2-$L4
.half $L5-$L4
.half $L2-$L4
.half $L2-$L4
.half $L6-$L4
.half $L2-$L4
.half $L2-$L4
.half $L7-$L4
.half $L2-$L4
.half $L1-$L4
$L9:
li $2,2
neg $2,$2
$L1:
jr $31
$L7:
.set noreorder
.set nomacro
jr $31
li $2,1
.set macro
.set reorder
$L6:
.set noreorder
.set nomacro
jr $31
move $2,$4
.set macro
.set reorder
$L5:
li $2,1
.set noreorder
.set nomacro
jr $31
neg $2,$2
.set macro
.set reorder
$L2:
.align 2
$L11:
.word j.1474
.end foo
.size foo, .-foo
.local j.1474
.comm j.1474,4,4
.ident "GCC: (GNU) 7.0.0 20160810 (experimental)"
$
where `$L2' is placed before MIPS16 constant pool data, or:
$ gcc -S -mmicromips -O2 -o switch-micromips.s switch.c
$ cat switch-micromips.s
.file 1 "switch.c"
.section .mdebug.abi32
.previous
.nan legacy
.module fp=xx
.module nooddspreg
.abicalls
.option pic0
.text
.align 2
.globl foo
.set nomips16
.set micromips
.ent foo
.type foo, @function
foo:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
.set noreorder
.set nomacro
lui $5,%hi(j.1401)
addiu $3,$4,5
lw $2,%lo(j.1401)($5)
sltu $6,$3,11
addu $2,$4,$2
beqz $6,$L2
sw $2,%lo(j.1401)($5)
lui $5,%hi($L4)
addiu $5,$5,%lo($L4)
lwxs $3,$3($5)
jrc $3
.rdata
.align 2
.align 2
$L4:
.word $L9
.word $L2
.word $L5
.word $L2
.word $L2
.word $L6
.word $L2
.word $L2
.word $L7
.word $L2
.word $L1
.text
$L9:
li $2,-2 # 0xfffffffffffffffe
$L1:
jrc $31
$L7:
jr $31
li $2,1 # 0x1
$L6:
jr $31
move $2,$4
$L5:
jr $31
li $2,-1 # 0xffffffffffffffff
$L2:
.set macro
.set reorder
.end foo
.size foo, .-foo
.local j.1401
.comm j.1401,4,4
.ident "GCC: (GNU) 7.0.0 20160810 (experimental)"
where the same label is placed at the end of a function. This in turn
makes recent trunk versions of gas complain:
$ as -o switch-mips16.o switch-mips16.s
switch-mips16.s: Assembler messages:
switch-mips16.s:26: Error: branch to a symbol in another ISA mode
$
as commit 9d862524f6ae ("MIPS: Verify the ISA mode and alignment of
branch and jump targets") closed a hole in branch processing, making
relocation calculation respect the ISA mode of the symbol referred.
This allowed diagnosing the situation where an attempt is made to pass
control from code assembled for one ISA mode to code assembled for a
different ISA mode and either relaxing the branch to a cross-mode jump
or if that is not possible, then reporting this as an error rather than
letting such code build and then fail unpredictably at the run time.
This however requires the correct annotation of branch targets as code,
because the ISA mode is not relevant for data symbols and is therefore
not recorded for them. The `.insn' pseudo-op is used for this purpose
and has been supported by GAS since:
Wed Feb 12 14:36:29 1997 Ian Lance Taylor <ian@cygnus.com>
* config/tc-mips.c (mips_pseudo_table): Add "insn".
(s_insn): New static function.
* doc/c-mips.texi: Document .insn.
so there has been no reason to avoid it where required. More recently
this pseudo-op has been documented, by the microMIPS architecture
specification[1][2], as required for the correct interpretation of any
code label which is not followed by an actual instruction in an assembly
source.
Let it be produced then, making it appear in output generated right
after `$L2' definitions above and thus fixing the assembly. Use the
`mach2' pass, after all the MIPS16 constant pools have been fixed, to
scan the insn stream backwards, identifying any labels still present at
the end of a function or immediately preceding a MIPS16 constant pool,
using dummy `consttable' insns previously inserted to identify the
beginning of each such constant pool. Insert the `insn_pseudo' insn
immediately after these labels, which emits the `.insn' pseudo-op.
References:
[1] "MIPS Architecture for Programmers, Volume II-B: The microMIPS32
Instruction Set", MIPS Technologies, Inc., Document Number: MD00582,
Revision 5.04, January 15, 2014, Section 7.1 "Assembly-Level
Compatibility", p. 533
[2] "MIPS Architecture for Programmers, Volume II-B: The microMIPS64
Instruction Set", MIPS Technologies, Inc., Document Number: MD00594,
Revision 5.04, January 15, 2014, Section 8.1 "Assembly-Level
Compatibility", p. 623
gcc/
* 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.
gcc/testsuite/
* 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.
---
I have successfully regression-tested it with the `mips-mti-linux-gnu'
target, with a big-endian o32 regular MIPS multilib and a little-endian
o32 MIPS16 multilib, with no regressions, except as noted below. I did
some big-endian n64 regular MIPS and little-endian o32 microMIPS testing,
including with the new cases, and things looked good, except as noted
below. I also generated assembly manually (for the assembly-match cases)
and examined output visually, including all the four above multilibs, and
also -fPIC and -mno-abicalls variants, which I have no immediate way of
testing automatically.
With n64 (`-mabi=n64') testing none of the test cases under
gcc.target/mips/ were run and the test harness broke as follows:
ERROR: (DejaGnu) proc "cc1: error: '-mfpxx' can only be used with the o32 ABI" does not exist.
The error code is NONE
The info on the error is:
invalid command name "cc1:"
while executing
"::tcl_unknown cc1: error: '-mfpxx' can only be used with the o32 ABI"
("uplevel" body line 1)
invoked from within
"uplevel 1 ::tcl_unknown $args"
I take it as a bug in the harness, which ought to be looked into
separately, and not a problem with this change.
With MIPS16 (`-mips16') and microMIPS (`-mmicromips') testing the test
cases failed to compile as follows, respectively:
spawn -ignore SIGHUP .../gcc/gcc/xgcc -B.../gcc/gcc/ .../gcc/testsuite/gcc.target/mips/insn-tablejump.c -fno-diagnostics-show-caret -fdiagnostics-color=never --sysroot=.../sysroot -O0 -DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression)) -mmicromips -mno-mips16 -DMICROMIPS=__attribute__((micromips)) -EL -mips16 -Wl,-dynamic-linker,.../sysroot/mipsel-r2-mips16-hard/lib/ld.so.1 -Wl,-rpath,.../sysroot/mipsel-r2-mips16-hard/lib -Wl,-rpath,.../sysroot/mipsel-r2-mips16-hard/usr/lib -lm -o insn-tablejump.exe
cc1: error: unsupported combination: -mips16 -mmicromips
compiler exited with status 1
output is:
cc1: error: unsupported combination: -mips16 -mmicromips
FAIL: gcc.target/mips/insn-tablejump.c -O0 (test for excess errors)
Excess errors:
cc1: error: unsupported combination: -mips16 -mmicromips
and:
spawn -ignore SIGHUP .../gcc/gcc/xgcc -B.../gcc/gcc/ .../gcc/testsuite/gcc.target/mips/insn-casesi.c -fno-diagnostics-show-caret -fdiagnostics-color=never --sysroot=.../sysroot -O0 -DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression)) -mno-micromips -mips16 -mcode-readable=yes -DMIPS16=__attribute__((mips16)) -EL -mmicromips-Wl,-dynamic-linker,.../sysroot/micromipsel-r2-hard/lib/ld.so.1 -Wl,-rpath,.../sysroot/micromipsel-r2-hard/lib -Wl,-rpath,.../sysroot/micromipsel-r2-hard/usr/lib -lm -o insn-casesi.exe
cc1: error: unsupported combination: -mips16 -mmicromips
compiler exited with status 1
output is:
cc1: error: unsupported combination: -mips16 -mmicromips
FAIL: gcc.target/mips/insn-casesi.c -O0 (test for excess errors)
Excess errors:
cc1: error: unsupported combination: -mips16 -mmicromips
Again, I take it as a bug in the harness, which places the required
overrides specified and implied by `dg-options' before board compilation
flags rather than afterwards. As such it's a separate problem which has
nothing to do with this change and needs to be fixed independently.
OK to apply?
Maciej
gcc-mips-label-insn.diff
Index: gcc/gcc/config/mips/mips.c
===================================================================
--- gcc.orig/gcc/config/mips/mips.c 2016-11-09 15:04:00.793911910 +0000
+++ gcc/gcc/config/mips/mips.c 2016-11-09 15:04:20.254759246 +0000
@@ -17133,6 +17133,8 @@ mips16_emit_constants (struct mips16_con
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. */
@@ -19008,6 +19010,46 @@ mips16_split_long_branches (void)
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 optimised 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
@@ -19043,6 +19085,7 @@ mips_machine_reorg2 (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;
}
Index: gcc/gcc/config/mips/mips.md
===================================================================
--- gcc.orig/gcc/config/mips/mips.md 2016-11-09 15:04:00.802108728 +0000
+++ gcc/gcc/config/mips/mips.md 2016-11-09 15:04:20.271031267 +0000
@@ -120,6 +120,7 @@
;; MIPS16 constant pools.
UNSPEC_ALIGN
+ UNSPEC_CONSTTABLE
UNSPEC_CONSTTABLE_INT
UNSPEC_CONSTTABLE_FLOAT
@@ -151,6 +152,9 @@
;; Stack checking.
UNSPEC_PROBE_STACK_RANGE
+
+ ;; The `.insn' pseudo-op.
+ UNSPEC_INSN_PSEUDO
])
(define_constants
@@ -7174,6 +7178,14 @@
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")])
;; MIPS4 Conditional move instructions.
@@ -7308,6 +7320,13 @@
;; ....................
;;
+(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" "")]
Index: gcc/gcc/testsuite/gcc.target/mips/insn-casesi.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-casesi.c 2016-11-09 18:55:39.856029933 +0000
@@ -0,0 +1,112 @@
+/* { 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. */
Index: gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-1.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-1.c 2016-11-09 18:55:39.866624599 +0000
@@ -0,0 +1,23 @@
+/* { 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" } } */
Index: gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-2.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-2.c 2016-11-09 18:55:39.876167216 +0000
@@ -0,0 +1,23 @@
+/* { 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" } } */
Index: gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-3.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-3.c 2016-11-09 18:55:39.892706789 +0000
@@ -0,0 +1,23 @@
+/* { 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" } } */
Index: gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-4.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-pseudo-4.c 2016-11-09 18:55:39.933208494 +0000
@@ -0,0 +1,27 @@
+/* { 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" } } */
Index: gcc/gcc/testsuite/gcc.target/mips/insn-tablejump.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc/gcc/testsuite/gcc.target/mips/insn-tablejump.c 2016-11-09 18:55:39.954800846 +0000
@@ -0,0 +1,98 @@
+/* { 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. */