]> gcc.gnu.org Git - gcc.git/commitdiff
(untyped_call, untyped_return): New patterns.
authorTom Wood <wood@gnu.org>
Tue, 23 Mar 1993 12:48:46 +0000 (12:48 +0000)
committerTom Wood <wood@gnu.org>
Tue, 23 Mar 1993 12:48:46 +0000 (12:48 +0000)
From-SVN: r3837

gcc/config/i386/i386.md
gcc/config/sparc/sparc.md

index cdb9e3ca9b12d0b70d1ba3d2a35d57b03d4e444e..c02b3384009710a6c09ec65d47ec5e639fe5a479 100644 (file)
   "!HALF_PIC_P ()"
   "call %P1")
 
+(define_expand "untyped_call"
+  [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
+                   (const_int 0))
+             (match_operand:BLK 1 "memory_operand" "")
+             (match_operand 2 "" "")])]
+  ""
+  "
+{
+  rtx addr;
+
+  if (flag_pic)
+    current_function_uses_pic_offset_table = 1;
+
+  /* With half-pic, force the address into a register.  */
+  addr = XEXP (operands[0], 0);
+  if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
+    XEXP (operands[0], 0) = force_reg (Pmode, addr);
+
+  operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
+}")
+
+(define_insn ""
+  [(call (match_operand:QI 0 "indirect_operand" "m")
+        (const_int 0))
+   (match_operand:DI 1 "memory_operand" "o")
+   (match_operand 2 "" "")]
+  ""
+  "*
+{
+  rtx addr = operands[1];
+
+  if (GET_CODE (operands[0]) == MEM
+      && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
+    {
+      operands[0] = XEXP (operands[0], 0);
+      output_asm_insn (AS1 (call,%*%0), operands);
+    }
+  else
+    output_asm_insn (AS1 (call,%P0), operands);
+
+  operands[2] = gen_rtx (REG, SImode, 0);
+  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
+
+  operands[2] = gen_rtx (REG, SImode, 1);
+  operands[1] = adj_offsettable_operand (addr, 4);
+  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
+
+  operands[1] = adj_offsettable_operand (addr, 8);
+  return AS1 (fnsave,%1);
+}")
+
+(define_insn ""
+  [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
+        (const_int 0))
+   (match_operand:DI 1 "memory_operand" "o")
+   (match_operand 2 "" "")]
+  "!HALF_PIC_P ()"
+  "*
+{
+  rtx addr = operands[1];
+
+  output_asm_insn (AS1 (call,%P0));
+
+  operands[2] = gen_rtx (REG, SImode, 0);
+  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
+
+  operands[2] = gen_rtx (REG, SImode, 1);
+  operands[1] = adj_offsettable_operand (addr, 4);
+  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
+
+  operands[1] = adj_offsettable_operand (addr, 8);
+  return AS1 (fnsave,%1);
+}")
+
+;; We use fnsave and frstor to save and restore the floating point result.
+;; These are expensive instructions and require a large space to save the
+;; FPU state.  An more complicated alternative is to use fnstenv to store
+;; the FPU environment and test whether the stack top is valid.  Store the
+;; result of the test, and if it is valid, pop and save the value.  The
+;; untyped_return would check the test and optionally push the saved value.
+
+(define_expand "untyped_return"
+  [(match_operand:BLK 0 "memory_operand" "")
+   (match_operand 1 "" "")]
+  ""
+  "
+{
+  rtx valreg1 = gen_rtx (REG, SImode, 0);
+  rtx valreg2 = gen_rtx (REG, SImode, 1);
+  rtx result = operands[0];
+
+  /* Restore the FPU state.  */
+  emit_insn (gen_update_return (change_address (result, SImode,
+                                               plus_constant (XEXP (result, 0),
+                                                              8))));
+
+  /* Reload the function value registers.  */
+  emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0)));
+  emit_move_insn (valreg2,
+                 change_address (result, SImode,
+                                 plus_constant (XEXP (result, 0), 4)));
+
+  /* Put USE insns before the return.  */
+  emit_insn (gen_rtx (USE, VOIDmode, valreg1));
+  emit_insn (gen_rtx (USE, VOIDmode, valreg2));
+
+  /* Construct the return.  */
+  expand_null_return ();
+
+  DONE;
+}")
+
+(define_insn "update_return"
+  [(unspec:SI [(match_operand:SI 0 "memory_operand" "m")] 0)]
+  ""
+  "frstor %0")
+
 ;; Insn emitted into the body of a function to return from a function.
 ;; This is only done if the function's epilogue is known to be simple.
 ;; See comments for simple_386_epilogue in i386.c.
index 293893db69ec44d91f9f6c5f3c4314a58f00e8c9..87d1a2e7f866f1ea33f18782f8edb72f3f9bface 100644 (file)
   return \"call %a1,%2%#\";
 }"
   [(set_attr "type" "call")])
+
+(define_expand "untyped_call"
+  [(parallel [(call (match_operand:SI 0 "call_operand" "")
+                   (const_int 0))
+             (match_operand:BLK 1 "memory_operand" "")
+             (match_operand 2 "" "")
+             (clobber (reg:SI 15))])]
+  ""
+  "
+{
+  operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
+}")
+
+;; Make a call followed by two nops in case the function being called
+;; returns a structure value and expects to skip an unimp instruction.
+
+(define_insn ""
+  [(call (mem:SI (match_operand:SI 0 "call_operand_address" "rS"))
+        (const_int 0))
+   (match_operand:DI 1 "memory_operand" "o")
+   (match_operand 2 "" "")
+   (clobber (reg:SI 15))]
+  ""
+  "*
+{
+  operands[2] = adj_offsettable_operand (operands[1], 8);
+  return \"call %a0,0\;nop\;nop\;std %%o0,%1\;st %%f0,%2\";
+}"
+  [(set_attr "type" "multi")])
+
+;; Prepare to return any type including a structure value.
+
+(define_expand "untyped_return"
+  [(match_operand:BLK 0 "memory_operand" "")
+   (match_operand 1 "" "")]
+  ""
+  "
+{
+  rtx valreg1 = gen_rtx (REG, DImode, 24);
+  rtx valreg2 = gen_rtx (REG, DFmode, 32);
+  rtx result = operands[0];
+  rtx rtnreg = gen_rtx (REG, SImode, (leaf_function ? 15 : 31));
+  rtx value = gen_reg_rtx (SImode);
+
+  /* Fetch the instruction where we will return to and see if it's an unimp
+     instruction (the most significant 10 bits will be zero).  If so,
+     update the return address to skip the unimp instruction.  */
+  emit_move_insn (value,
+                 gen_rtx (MEM, SImode, plus_constant (rtnreg, 8)));
+  emit_insn (gen_lshrsi3 (value, value, GEN_INT (22)));
+  emit_insn (gen_update_return (rtnreg, value));
+
+  /* Reload the function value registers.  */
+  emit_move_insn (valreg1, change_address (result, DImode, XEXP (result, 0)));
+  emit_move_insn (valreg2,
+                 change_address (result, DFmode,
+                                 plus_constant (XEXP (result, 0), 8)));
+
+  /* Put USE insns before the return.  */
+  emit_insn (gen_rtx (USE, VOIDmode, valreg1));
+  emit_insn (gen_rtx (USE, VOIDmode, valreg2));
+
+  /* Construct the return.  */
+  expand_null_return ();
+
+  DONE;
+}")
+
+;; This is a bit of a hack.  We're incrementing a fixed register (%i7),
+;; and parts of the compiler don't want to believe that the add is needed.
+
+(define_insn "update_return"
+  [(unspec:SI [(match_operand:SI 0 "register_operand" "r")
+              (match_operand:SI 1 "register_operand" "r")] 0)]
+  ""
+  "cmp %1,0\;be,a .+8\;add %0,4,%0"
+  [(set_attr "type" "multi")])
 \f
 (define_insn "return"
   [(return)]
This page took 0.076806 seconds and 5 git commands to generate.