Commit b46de15e by Jeff Law

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
parent e47ae1c2
...@@ -4462,9 +4462,7 @@ output_millicode_call (insn, call_dest) ...@@ -4462,9 +4462,7 @@ output_millicode_call (insn, call_dest)
and we're sure that the branch will reach the beginning of the $CODE$ and we're sure that the branch will reach the beginning of the $CODE$
subspace. */ subspace. */
if ((dbr_sequence_length () == 0 if ((dbr_sequence_length () == 0
/* CYGNUS LOCAL mentor6480hack/law */
&& (get_attr_length (insn) == 8 || get_attr_length (insn) == 28)) && (get_attr_length (insn) == 8 || get_attr_length (insn) == 28))
/* END CYGNUS LOCAL */
|| (dbr_sequence_length () != 0 || (dbr_sequence_length () != 0
&& GET_CODE (NEXT_INSN (insn)) != JUMP_INSN && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
&& get_attr_length (insn) == 4)) && get_attr_length (insn) == 4))
......
...@@ -23,6 +23,8 @@ Boston, MA 02111-1307, USA. */ ...@@ -23,6 +23,8 @@ Boston, MA 02111-1307, USA. */
enum cmp_type /* comparison type */ 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_SI, /* compare integers */
CMP_SF, /* compare single precision floats */ CMP_SF, /* compare single precision floats */
CMP_DF, /* compare double precision floats */ CMP_DF, /* compare double precision floats */
...@@ -1661,6 +1663,26 @@ while (0) ...@@ -1661,6 +1663,26 @@ while (0)
between pointers and any other objects of this machine mode. */ between pointers and any other objects of this machine mode. */
#define Pmode SImode #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. /* Add any extra modes needed to represent the condition code.
HPPA floating comparisons produce condition codes. */ HPPA floating comparisons produce condition codes. */
......
...@@ -340,6 +340,44 @@ ...@@ -340,6 +340,44 @@
;; emit RTL for both the compare and the branch. ;; 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" (define_expand "cmpsi"
[(set (reg:CC 0) [(set (reg:CC 0)
(compare:CC (match_operand:SI 0 "reg_or_0_operand" "") (compare:CC (match_operand:SI 0 "reg_or_0_operand" "")
...@@ -5262,3 +5300,88 @@ ...@@ -5262,3 +5300,88 @@
[(set_attr "type" "multi") [(set_attr "type" "multi")
(set_attr "length" "8")]) (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)))])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment