From 576182a333d24a91f07c34d29757fdfc28b6e68b Mon Sep 17 00:00:00 2001 From: Tom Wood Date: Tue, 23 Mar 1993 12:48:46 +0000 Subject: [PATCH] (untyped_call, untyped_return): New patterns. From-SVN: r3837 --- gcc/config/i386/i386.md | 117 ++++++++++++++++++++++++++++++++++++++ gcc/config/sparc/sparc.md | 77 +++++++++++++++++++++++++ 2 files changed, 194 insertions(+) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index cdb9e3ca9b12..c02b33840097 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -4113,6 +4113,123 @@ "!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. diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 293893db69ec..87d1a2e7f866 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -2749,6 +2749,83 @@ 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")]) (define_insn "return" [(return)] -- 2.43.5