aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/pa/pa.c80
-rw-r--r--gcc/config/pa/pa.h3
-rw-r--r--gcc/config/pa/pa.md7
3 files changed, 90 insertions, 0 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index a164cd0..6d6a165 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -2759,6 +2759,12 @@ pa_adjust_insn_length (insn, length)
else
return 0;
}
+ /* Jumps inside switch tables which have unfilled delay slots
+ also need adjustment. */
+ else if (GET_CODE (insn) == JUMP_INSN
+ && simplejump_p (insn)
+ && GET_MODE (PATTERN (insn)) == DImode)
+ return 4;
/* Millicode insn with an unfilled delay slot. */
else if (GET_CODE (insn) == INSN
&& GET_CODE (pat) != SEQUENCE
@@ -4392,3 +4398,77 @@ jump_in_call_delay (insn)
else
return 0;
}
+
+
+/* We use this hook to perform a PA specific optimization which is difficult
+ to do in earlier passes.
+
+ We want the delay slots of branches within jump tables to be filled.
+ None of the compiler passes at the moment even has the notion that a
+ PA jump table doesn't contain addresses, but instead contains actual
+ instructions!
+
+ Because we actually jump into the table, the addresses of each entry
+ must stay contant in relation to the beginning of the table (which
+ itself must stay constant relative to the instruction to jump into
+ it). I don't believe we can guarantee earlier passes of the compiler
+ will adhere to those rules.
+
+ So, late in the compilation process we find all the jump tables, and
+ expand them into real code -- eg each entry in the jump table vector
+ will get an appropriate label followed by a jump to the final target.
+
+ Reorg and the final jump pass can then optimize these branches and
+ fill their delay slots. We end up with smaller, more efficient code.
+
+ The jump instructions within the table are special; we must be able
+ to identify them during assembly output (if the jumps don't get filled
+ we need to emit a nop rather than nullifying the delay slot)). We
+ identify jumps in switch tables by marking the SET with DImode. */
+
+pa_reorg (insns)
+ rtx insns;
+{
+ rtx insn;
+
+ /* This is fairly cheap, so always run it if optimizing. */
+ if (optimize > 0)
+ {
+ /* Find and explode all ADDR_VEC insns. */
+ insns = get_insns ();
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ {
+ rtx pattern, tmp, location;
+ unsigned int length, i;
+
+ /* Find an ADDR_VEC insn to explode. */
+ if (GET_CODE (insn) != JUMP_INSN
+ || GET_CODE (PATTERN (insn)) != ADDR_VEC)
+ continue;
+
+ pattern = PATTERN (insn);
+ location = PREV_INSN (insn);
+ length = XVECLEN (pattern, 0);
+ for (i = 0; i < length; i++)
+ {
+ /* Emit the jump itself. */
+ tmp = gen_switch_jump (XEXP (XVECEXP (pattern, 0, i), 0));
+ tmp = emit_jump_insn_after (tmp, location);
+ JUMP_LABEL (tmp) = XEXP (XVECEXP (pattern, 0, i), 0);
+
+ /* Emit a BARRIER after the jump. */
+ location = NEXT_INSN (location);
+ emit_barrier_after (location);
+
+ /* Put a CODE_LABEL before each so jump.c does not optimize
+ the jumps away. */
+ location = NEXT_INSN (location);
+ tmp = gen_label_rtx ();
+ LABEL_NUSES (tmp) = 1;
+ emit_label_after (tmp, location);
+ location = NEXT_INSN (location);
+ }
+ /* Delete the ADDR_VEC. */
+ delete_insn (insn);
+ }
+ }
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index 792af84..f6d8c83 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -239,6 +239,9 @@ extern int target_flags;
/* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP
+/* Machine dependent reorg pass. */
+#define MACHINE_DEPENDENT_REORG(X) pa_reorg(X)
+
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "-Dhppa -Dhp9000s800 -D__hp9000s800 -Dhp9k8 -Dunix -D_HPUX_SOURCE -Dhp9000 -Dhp800 -Dspectrum -DREVARGV -Asystem(unix) -Asystem(bsd) -Acpu(hppa) -Amachine(hppa)"
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index b01a504..ff80e61 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -3405,6 +3405,13 @@
""
[(set_attr "length" "0")])
+(define_insn "switch_jump"
+ [(set:DI (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ "bl %l0,0%#"
+ [(set_attr "type" "uncond_branch")
+ (set_attr "length" "4")])
+
(define_insn "jump"
[(set (pc) (label_ref (match_operand 0 "" "")))]
""