pa.h (cmp_type): Add CMP_PSI.
authorJeff Law <law@gcc.gnu.org>
Mon, 10 Jun 1996 19:22:32 +0000 (13:22 -0600)
committerJeff Law <law@gcc.gnu.org>
Mon, 10 Jun 1996 19:22:32 +0000 (13:22 -0600)
        * 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

gcc/config/pa/pa.c
gcc/config/pa/pa.h
gcc/config/pa/pa.md

index f2dca71dcee022d2ef060a8ee5e927a9947f4216..9cc78a45cd4b1737d38e187c02514b06e05ca5ed 100644 (file)
@@ -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))
index 8179c6b2ce2ed1af75f48433f376bed59be7e8fe..4ccb4871a6282b518a95be2a9a60e781214799a6 100644 (file)
@@ -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. */
index 28f4f1b8febf7d9a36816c5b908b4bfc63d39102..7a909649c8b95c079c6afdcd571cac270d720075 100644 (file)
 ;; 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" "")
   [(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)))])
+
+