diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/pa/pa.c | 80 | ||||
-rw-r--r-- | gcc/config/pa/pa.h | 3 | ||||
-rw-r--r-- | gcc/config/pa/pa.md | 7 |
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 "" "")))] "" |