diff options
author | Jeff Law <law@gcc.gnu.org> | 1996-06-10 13:22:32 -0600 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 1996-06-10 13:22:32 -0600 |
commit | b46de15ede48804ec0dce7b15bb60160c859bb51 (patch) | |
tree | f92e62cb5cd9a76e107a30b40578d9fcc4a08aaf /gcc | |
parent | e47ae1c2d3c228f988571479613b1786fe6c9165 (diff) | |
download | gcc-b46de15ede48804ec0dce7b15bb60160c859bb51.zip gcc-b46de15ede48804ec0dce7b15bb60160c859bb51.tar.gz gcc-b46de15ede48804ec0dce7b15bb60160c859bb51.tar.bz2 |
pa.h (cmp_type): Add CMP_PSI.
* pa/pa.h (cmp_type): Add CMP_PSI.
(FUNCTION_POINTER_COMPARISON_MODE): Define.
* pa.md (cmppsi): New expander.
(plabel_dereference): New pattern
From-SVN: r12266
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/pa/pa.c | 2 | ||||
-rw-r--r-- | gcc/config/pa/pa.h | 22 | ||||
-rw-r--r-- | gcc/config/pa/pa.md | 123 |
3 files changed, 145 insertions, 2 deletions
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index f2dca71..9cc78a4 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -4462,9 +4462,7 @@ output_millicode_call (insn, call_dest) and we're sure that the branch will reach the beginning of the $CODE$ subspace. */ if ((dbr_sequence_length () == 0 -/* CYGNUS LOCAL mentor6480hack/law */ && (get_attr_length (insn) == 8 || get_attr_length (insn) == 28)) -/* END CYGNUS LOCAL */ || (dbr_sequence_length () != 0 && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN && get_attr_length (insn) == 4)) diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index 8179c6b..4ccb487 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -23,6 +23,8 @@ Boston, MA 02111-1307, USA. */ enum cmp_type /* comparison type */ { + /* See FUNCTION_POINTER_COMPARISON_MODE for info on CMP_PSI. */ + CMP_PSI, /* For function pointers. */ CMP_SI, /* compare integers */ CMP_SF, /* compare single precision floats */ CMP_DF, /* compare double precision floats */ @@ -1661,6 +1663,26 @@ while (0) between pointers and any other objects of this machine mode. */ #define Pmode SImode +/* XXX FIXME. The function pointer comparison code is only at the FSF + for documentation and merging purposes, it is _NOT_ actually used. + + I've been trying to get Kenner to deal with the machine independent + problems for many months, and for whatever reason nothing ever seems + to happen. + + If you want function pointer comparisons to work, first scream at + Kenner to deal with the MI problems, then email me for a hack that + will get the job done (law@cygnus.com). + + The mode in which function pointer comparisons occur. The PA backend + uses this mode to identify function pointer comparisons so that special + code needed to compare functions can be generated. + + Note, special code is not needed for function pointer comparisons + in the portable runtime model. */ +#define FUNCTION_POINTER_COMPARISON_MODE \ + (TARGET_PORTABLE_RUNTIME ? Pmode : PSImode) + /* Add any extra modes needed to represent the condition code. HPPA floating comparisons produce condition codes. */ diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index 28f4f1b..7a90964 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -340,6 +340,44 @@ ;; emit RTL for both the compare and the branch. ;; +;; This expander is not used by the FSF compiler, refer to +;; FUNCTION_POINTER_COMPARISON_MODE in pa.h for a brief discussion why. +(define_expand "cmppsi" + [(set (reg:CC 0) + (compare:CC (match_operand:SI 0 "reg_or_0_operand" "") + (match_operand:SI 1 "reg_or_0_operand" "")))] + "" + " +{ + rtx res0, res1; + + /* We need two new pseudos to hold the value of the dereferenced + plabel. */ + res0 = gen_reg_rtx (Pmode); + res1 = gen_reg_rtx (Pmode); + + /* Move the first function pointer into %r26 and call the + magic millicode routine to get the function's actual + address. Copy the result from %r29 into the first + psuedo. */ + emit_move_insn (gen_rtx (REG, Pmode, 26), operands[0]); + emit_insn (gen_plabel_dereference (gen_reg_rtx (SImode))); + emit_move_insn (res0, gen_rtx (REG, Pmode, 29)); + + /* Likewise for the second function pointer. */ + emit_move_insn (gen_rtx (REG, Pmode, 26), operands[1]); + emit_insn (gen_plabel_dereference (gen_reg_rtx (SImode))); + emit_move_insn (res1, gen_rtx (REG, Pmode, 29)); + + /* Put the results in hppa_compare_op0 and hppa_compare_op1. */ + hppa_compare_op0 = res0; + hppa_compare_op1 = res1; + /* The branch is really a SImode branch. PSImode was used just + so we could identify this as a function pointer comparison. */ + hppa_branch_type = CMP_SI; + DONE; +}") + (define_expand "cmpsi" [(set (reg:CC 0) (compare:CC (match_operand:SI 0 "reg_or_0_operand" "") @@ -5262,3 +5300,88 @@ [(set_attr "type" "multi") (set_attr "length" "8")]) +/* Given a function pointer (aka plabel) in %r26, return (in %r29) the + actual address of the function that would be called if the function + pointer was used in an indirect call. + + We must show %r1 as clobbered since the linker might insert a stub + in the call path that clobbers %r1 (yes, it really happens). */ +;; This expander is not used by the FSF compiler, refer to +;; FUNCTION_POINTER_COMPARISON_MODE in pa.h for a brief discussion why. +(define_insn "plabel_dereference" + [(set (reg:SI 29) (unspec:SI [(reg:SI 26)] 0)) + (clobber (match_operand:SI 0 "register_operand" "=a")) + (clobber (reg:SI 26)) + (clobber (reg:SI 22)) + (clobber (reg:SI 31))] + "" + "* +{ + /* Must import the magic millicode routine. */ + output_asm_insn (\".IMPORT $$sh_func_adrs,MILLICODE\", NULL); + + /* This is absolutely fucking amazing. + + First, copy our input parameter into %r29 just in case we don't + need to call $$sh_func_adrs. */ + output_asm_insn (\"copy %%r26,%%r29\", NULL); + + /* Next, examine the low two bits in %r26, if they aren't 0x2, then + we use %r26 unchanged. */ + if (get_attr_length (insn) == 32) + output_asm_insn (\"extru %%r26,31,2,%%r31\;comib,<>,n 2,%%r31,.+24\", NULL); + else if (get_attr_length (insn) == 40) + output_asm_insn (\"extru %%r26,31,2,%%r31\;comib,<>,n 2,%%r31,.+32\", NULL); + else if (get_attr_length (insn) == 44) + output_asm_insn (\"extru %%r26,31,2,%%r31\;comib,<>,n 2,%%r31,.+36\", NULL); + else + output_asm_insn (\"extru %%r26,31,2,%%r31\;comib,<>,n 2,%%r31,.+20\", NULL); + + /* Next, compare %r26 with 4096, if %r26 is less than or equal to + 4096, then we use %r26 unchanged. */ + if (get_attr_length (insn) == 32) + output_asm_insn (\"ldi 4096,%%r31\;comb,<<,n %%r26,%%r31,.+16\", NULL); + else if (get_attr_length (insn) == 40) + output_asm_insn (\"ldi 4096,%%r31\;comb,<<,n %%r26,%%r31,.+24\", NULL); + else if (get_attr_length (insn) == 44) + output_asm_insn (\"ldi 4096,%%r31\;comb,<<,n %%r26,%%r31,.+28\", NULL); + else + output_asm_insn (\"ldi 4096,%%r31\;comb,<<,n %%r26,%%r31,.+12\", NULL); + + /* Else call $$sh_func_adrs to extract the function's real add24. */ + return output_millicode_call (insn, + gen_rtx (SYMBOL_REF, SImode, + \"$$sh_func_adrs\")); +}" + [(set_attr "type" "multi") + (set (attr "length") + (cond [ +;; Target (or stub) within reach + (and (lt (plus (symbol_ref "total_code_bytes") (pc)) + (const_int 240000)) + (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") + (const_int 0))) + (const_int 28) + +;; NO_SPACE_REGS + (ne (symbol_ref "TARGET_NO_SPACE_REGS") + (const_int 0)) + (const_int 32) + +;; Out of reach, but not PIC or PORTABLE_RUNTIME +;; same as NO_SPACE_REGS code + (and (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") + (const_int 0)) + (eq (symbol_ref "flag_pic") + (const_int 0))) + (const_int 32) + +;; PORTABLE_RUTNIME + (ne (symbol_ref "TARGET_PORTABLE_RUNTIME") + (const_int 0)) + (const_int 40)] + +;; Out of range and PIC + (const_int 44)))]) + + |