From f5b65a56691fdc8f8b914011da7ed8ec4fa1176c Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 1 Apr 1996 11:48:52 -0700 Subject: [PATCH] h8300.c (interrupt_handler): Renamed from pragma_interrupt. * h8300.c (interrupt_handler): Renamed from pragma_interrupt. All references changed. (function_prologue): Set interrupt_handler if the current function has the "interrrupt-handler" attribute. (small_call_insn_operand): New function. (h8300_interrrupt_function_p): New function. (h8300_funcvec_function_p): New function. (h8300_valid_machine_decl_attribute): New function. * h8300.h (VALID_MACHINE_DECL_ATTRIBUTE): Define. * h8300.md (call insns): Handle calls through the function vector. Indirect calls and calls through the function vector have a length of two bytes. From-SVN: r11650 --- gcc/config/h8300/h8300.c | 108 +++++++++++++++++++++++++++++++++++--- gcc/config/h8300/h8300.h | 15 ++++++ gcc/config/h8300/h8300.md | 28 ++++++++-- 3 files changed, 141 insertions(+), 10 deletions(-) diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index cadff014961..6a85ecb9ebc 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -40,11 +40,16 @@ Boston, MA 02111-1307, USA. */ void print_operand_address (); char *index (); +static int h8300_interrupt_function_p PROTO ((tree)); +static int h8300_funcvec_function_p PROTO ((tree)); + /* CPU_TYPE, says what cpu we're compiling for. */ int cpu_type; -/* True if a #pragma interrupt has been seen for the current function. */ -int pragma_interrupt; +/* True if the current function is an interrupt handler + (either via #pragma or an attribute specification). */ +int interrupt_handler; + /* True if a #pragma saveall has been seen for the current function. */ int pragma_saveall; @@ -110,7 +115,7 @@ byte_reg (x, b) #define WORD_REG_USED(regno) \ (regno < 7 && \ - (pragma_interrupt \ + (interrupt_handler \ || pragma_saveall \ || (regno == FRAME_POINTER_REGNUM && regs_ever_live[regno]) \ || (regs_ever_live[regno] & !call_used_regs[regno]))) @@ -190,6 +195,9 @@ function_prologue (file, size) int idx; extra_pop = 0; + if (h8300_interrupt_function_p (current_function_decl)) + interrupt_handler = 1; + if (current_function_anonymous_args && TARGET_QUICKCALL) { /* Push regs as if done by caller, and move around return address. */ @@ -325,13 +333,13 @@ function_epilogue (file, size) } else { - if (pragma_interrupt) + if (interrupt_handler) fprintf (file, "\trte\n"); else fprintf (file, "\trts\n"); } - pragma_interrupt = 0; + interrupt_handler = 0; pragma_saveall = 0; current_function_anonymous_args = 0; @@ -470,6 +478,32 @@ call_insn_operand (op, mode) return 0; } +/* Return true if OP is a valid call operand, and OP represents + an operand for a small call (4 bytes instead of 6 bytes). */ + +int +small_call_insn_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + if (GET_CODE (op) == MEM) + { + rtx inside = XEXP (op, 0); + + /* Register indirect is a small call. */ + if (register_operand (inside, Pmode)) + return 1; + + /* A call through the function vector is a small + call too. */ + if (GET_CODE (inside) == SYMBOL_REF + && SYMBOL_REF_FLAG (inside)) + return 1; + } + /* Otherwise it's a large call. */ + return 0; +} + /* Return true if OP is a valid jump operand. */ int @@ -569,7 +603,7 @@ handle_pragma (file, c) pbuf[psize] = 0; if (strcmp (pbuf, "interrupt") == 0) - pragma_interrupt = 1; + interrupt_handler = 1; else if (strcmp (pbuf, "saveall") == 0) pragma_saveall = 1; @@ -2065,3 +2099,65 @@ fix_bit_operand (operands, what, type) } return 1; } + + +/* Return nonzero if FUNC is an interrupt function as specified + by the "interrupt" attribute. */ + +static int +h8300_interrupt_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + return 0; + + a = lookup_attribute ("interrupt-handler", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +/* Return nonzero if FUNC is a function that should be called + through the function vector. */ + +int +h8300_funcvec_function_p (func) + tree func; +{ + tree a; + + if (TREE_CODE (func) != FUNCTION_DECL) + return 0; + + a = lookup_attribute ("function-vector", DECL_MACHINE_ATTRIBUTES (func)); + return a != NULL_TREE; +} + +/* Return nonzero if ATTR is a valid attribute for DECL. + ATTRIBUTES are any existing attributes and ARGS are the arguments + supplied with ATTR. + + Supported attributes: + + interrupt-handler: output a prologue and epilogue suitable for an + interrupt handler. + + function-vector: This function should be called through the + function vector. */ + +int +h8300_valid_machine_decl_attribute (decl, attributes, attr, args) + tree decl; + tree attributes; + tree attr; + tree args; +{ + if (args != NULL_TREE) + return 0; + + if (is_attribute_p ("interrupt-handler", attr) + || is_attribute_p ("function-vector", attr)) + return TREE_CODE (decl) == FUNCTION_DECL; + return 0; +} + diff --git a/gcc/config/h8300/h8300.h b/gcc/config/h8300/h8300.h index b1a44a79280..197d814933f 100644 --- a/gcc/config/h8300/h8300.h +++ b/gcc/config/h8300/h8300.h @@ -932,6 +932,13 @@ extern int current_function_anonymous_args; so give the MEM rtx a byte's mode. */ #define FUNCTION_MODE QImode +/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS + is a valid machine specific attribute for DECL. + The attributes in ATTRIBUTES have previously been assigned to DECL. */ +extern int h8300_valid_machine_decl_attribute (); +#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \ +h8300_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS) + /* Compute the cost of computing a constant rtl expression RTX whose rtx-code is CODE. The body of this macro is a portion of a switch statement. If the code is computed here, @@ -1081,6 +1088,14 @@ dtors_section() \ } \ } +/* If we are referencing a function that is supposed to be called + through the function vector, the SYMBOL_REF_FLAG in the rtl + so the call patterns can generate the correct code. */ +#define ENCODE_SECTION_INFO(DECL) \ + if (TREE_CODE (DECL) == FUNCTION_DECL \ + && h8300_funcvec_function_p (DECL)) \ + SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1; + /* How to refer to registers in assembler output. This sequence is indexed by compiler's hard-register-number (see above). */ diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md index a68d54cf715..509c9600d5b 100644 --- a/gcc/config/h8300/h8300.md +++ b/gcc/config/h8300/h8300.md @@ -1312,10 +1312,20 @@ [(call (match_operand:QI 0 "call_insn_operand" "or") (match_operand:HI 1 "general_operand" "g"))] "" - "jsr %0" + "* +{ + if (GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF + && SYMBOL_REF_FLAG (XEXP (operands[0], 0))) + return \"jsr\\t\@%0:8\"; + else + return \"jsr\\t%0\"; +}" [(set_attr "type" "call") (set_attr "cc" "clobber") - (set_attr "length" "4")]) + (set (attr "length") + (if_then_else (match_operand:QI 0 "small_call_insn_operand" "") + (const_int 4) + (const_int 8)))]) ;; Call subroutine, returning value in operand 0 ;; (which must be a hard register). @@ -1327,10 +1337,20 @@ (call (match_operand:QI 1 "call_insn_operand" "or") (match_operand:HI 2 "general_operand" "g")))] "" - "jsr %1" + "* +{ + if (GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF + && SYMBOL_REF_FLAG (XEXP (operands[1], 0))) + return \"jsr\\t\@%1:8\"; + else + return \"jsr\\t%1\"; +}" [(set_attr "type" "call") (set_attr "cc" "clobber") - (set_attr "length" "4")]) + (set (attr "length") + (if_then_else (match_operand:QI 0 "small_call_insn_operand" "") + (const_int 4) + (const_int 8)))]) (define_insn "nop" [(const_int 0)]