From 4af3895e739fefe2d158ab1c632d7d860abd4705 Mon Sep 17 00:00:00 2001 From: James Van Artsdalen Date: Sun, 12 Apr 1992 21:47:29 +0000 Subject: [PATCH] *** empty log message *** From-SVN: r731 --- gcc/config/i386/i386.c | 28 +++---- gcc/config/i386/i386.md | 169 +++++++++------------------------------- gcc/expr.c | 112 +++++++++++++++++++------- 3 files changed, 132 insertions(+), 177 deletions(-) diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 21eee4845b9..3495d1da6b1 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -976,8 +976,6 @@ print_operand (file, x, code) putc ('*', file); return; - case 'D': - PUT_OP_SIZE (code, 'l', file); case 'L': PUT_OP_SIZE (code, 'l', file); return; @@ -998,10 +996,6 @@ print_operand (file, x, code) PUT_OP_SIZE (code, 's', file); return; - case 'R': - fprintf (file, "%s", RP); - return; - case 'z': /* 387 opcodes don't get size suffixes if the operands are registers. */ @@ -1037,6 +1031,17 @@ print_operand (file, x, code) PUT_OP_SIZE ('Q', 'l', file); return; } + + case 'b': + case 'w': + case 'k': + case 'h': + case 'y': + case 'P': + break; + + default: + abort (); } } if (GET_CODE (x) == REG) @@ -1063,13 +1068,8 @@ print_operand (file, x, code) u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); u1.f = u.d; - if (code == 'f') - fprintf (file, "%.22e", u1.f); - else - { - PRINT_IMMED_PREFIX (file); - fprintf (file, "0x%x", u1.i); - } + PRINT_IMMED_PREFIX (file); + fprintf (file, "0x%x", u1.i); } else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode) { @@ -1080,7 +1080,7 @@ print_operand (file, x, code) } else { - if (code != 'c' && code != 'P') + if (code != 'P') { if (GET_CODE (x) == CONST_INT) PRINT_IMMED_PREFIX (file); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 5d8027edbd4..561eb8f7173 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -19,37 +19,41 @@ ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. -;;- instruction definitions +;; The original PO technology requires these to be ordered by speed, +;; so that assigner will pick the fastest. -;;- @@The original PO technology requires these to be ordered by speed, -;;- @@ so that assigner will pick the fastest. +;; See file "rtl.def" for documentation on define_insn, match_*, et. al. -;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code +;; updates for most instructions. -;;- When naming insn's (operand 0 of define_insn) be careful about using -;;- names from other targets machine descriptions. - -;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code -;;- updates for most instructions. - -;;- Operand classes for the register allocator: -;;- 'a' for eax -;;- 'd' for edx -;;- 'c' for ecx -;;- 'b' for ebx -;;- 'f' for anything in FLOAT_REGS -;;- 'r' any (non-floating-point) register -;;- 'q' regs that allow byte operations (A, B, C and D) -;;- 'A' A and D registers +;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register +;; constraint letters. ;; the special asm out single letter directives following a '%' are: -;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of operands[1] -;; 's' output a '*' -;; 'w' If the operand is a REG, it uses the mode size to determine the -;; printing of the reg +;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of +;; operands[1]. +;; 'L' Print the opcode suffix for a 32-bit integer opcode. +;; 'W' Print the opcode suffix for a 16-bit integer opcode. +;; 'B' Print the opcode suffix for an 8-bit integer opcode. +;; 'S' Print the opcode suffix for a 32-bit float opcode. +;; 'Q' Print the opcode suffix for a 64-bit float opcode. + +;; 'b' Print the QImode name of the register for the indicated operand. +;; %b0 would print %al if operands[0] is reg 0. +;; 'w' Likewise, print the HImode name of the register. +;; 'k' Likewise, print the SImode name of the register. +;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh. +;; 'y' Print "st(0)" instead of "st" as a register. + +;; UNSPEC usage: +;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode. +;; operand 0 is the memory address to scan. +;; operand 1 is a register containing the value to scan for. The mode +;; of the scas opcode will be the same as the mode of this operand. +;; operand 2 is the known alignment of operand 0. - ;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM". ;; But restricting MEM here would mean that gcc could not remove a redundant ;; test in cases like "incl MEM / je TARGET". @@ -2573,9 +2577,9 @@ (define_insn "" [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm") (const_int 1) - (match_operand:SI 2 "nonimmediate_operand" "r")) + (match_operand:SI 2 "general_operand" "r")) (match_operand:SI 3 "immediate_operand" "i"))] - "! TARGET_486" + "! TARGET_486 && GET_CODE (operands[2]) != CONST_INT" "* { CC_STATUS_INIT; @@ -2593,7 +2597,7 @@ (xor:SI (ashift:SI (const_int 1) (match_operand:SI 1 "general_operand" "r")) (match_dup 0)))] - "! TARGET_486" + "! TARGET_486 && GET_CODE (operands[1]) != CONST_INT" "* { CC_STATUS_INIT; @@ -2628,118 +2632,15 @@ ;; don't allow a MEM in the operand predicate without allowing it in the ;; constraint. -(define_insn "" - [(set (cc0) (zero_extract (match_operand:QI 0 "register_operand" "q") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] - "" - "* -{ - if (GET_CODE (operands[1]) == CONST_INT) - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (operands[1])); - output_asm_insn (AS2 (test%B0,%1,%0), operands); - } - else - { - operands[0] = gen_rtx (REG, SImode, REGNO (operands[0])); - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%L0,%1,%0), operands); - } - RET; -}") - -;; ??? The first argument of a zero_extract must not be reloaded, so -;; don't allow a MEM in the operand predicate without allowing it in the -;; constraint. - -(define_insn "" - [(set (cc0) (zero_extract (match_operand:HI 0 "register_operand" "r") - (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] - "" - "* -{ - if (GET_CODE (operands[1]) == CONST_INT) - { - if (QI_REG_P (operands[0]) && INTVAL (operands[1]) < 8) - { - cc_status.flags |= CC_NOT_NEGATIVE; - operands[1] = gen_rtx (CONST_INT, VOIDmode, - 1 << INTVAL (operands[1])); - - output_asm_insn (AS2 (test%B0,%1,%b0), operands); - } - else if (QI_REG_P (operands[0])) - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, - 1 << (INTVAL (operands[1]) - 8)); - - output_asm_insn (AS2 (test%B0,%1,%h0), operands); - } - else - { - /* ??? This will never set CC to negative, even if we test - the sign bit of the HImode reg. But CC0 is only tested - for EQ and NE after this insn. */ - - operands[1] = gen_rtx (CONST_INT, VOIDmode, - 1 << INTVAL (operands[1])); - - output_asm_insn (AS2 (test%L0,%1,%k0), operands); - } - } - else - { - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%W0,%1,%0), operands); - } - RET; -}") - -;; ??? The first argument of a zero_extract must not be reloaded, so -;; don't allow a MEM in the operand predicate without allowing it in the -;; constraint. - (define_insn "" [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r") (const_int 1) - (match_operand:SI 1 "general_operand" "ri")))] - "" + (match_operand:SI 1 "general_operand" "r")))] + "GET_CODE (operands[1]) != CONST_INT" "* { - if (GET_CODE (operands[1]) == CONST_INT) - { - if (QI_REG_P (operands[0]) && INTVAL (operands[1]) < 8) - { - cc_status.flags |= CC_NOT_NEGATIVE; - operands[1] = gen_rtx (CONST_INT, VOIDmode, - 1 << INTVAL (operands[1])); - - output_asm_insn (AS2 (test%B0,%1,%b0), operands); - } - else if (QI_REG_P (operands[0]) && INTVAL (operands[1]) < 16) - { - cc_status.flags |= CC_NOT_NEGATIVE; - operands[1] = gen_rtx (CONST_INT, VOIDmode, - 1 << (INTVAL (operands[1]) - 8)); - - output_asm_insn (AS2 (test%B0,%1,%h0), operands); - } - else - { - operands[1] = gen_rtx (CONST_INT, VOIDmode, - 1 << INTVAL (operands[1])); - - output_asm_insn (AS2 (test%L0,%1,%0), operands); - } - } - else - { - cc_status.flags |= CC_Z_IN_NOT_C; - output_asm_insn (AS2 (bt%L0,%1,%0), operands); - } - RET; + cc_status.flags |= CC_Z_IN_NOT_C; + return AS2 (bt%L0,%1,%0); }") ;; Store-flag instructions. diff --git a/gcc/expr.c b/gcc/expr.c index c617894ba74..8d2a42439a2 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2204,6 +2204,8 @@ store_constructor (exp, target) tree exp; rtx target; { + tree type = TREE_TYPE (exp); + /* We know our target cannot conflict, since safe_from_p has been called. */ #if 0 /* Don't try copying piece by piece into a hard register @@ -2218,19 +2220,25 @@ store_constructor (exp, target) } #endif - if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE - || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE) + if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE) { register tree elt; - if (TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE) - /* Inform later passes that the whole union value is dead. */ + /* Inform later passes that the whole union value is dead. */ + if (TREE_CODE (type) == UNION_TYPE) emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); + + /* If we are building a static constructor into a register, + set the initial value as zero so we can fold the value into + a constant. */ + else if (GET_CODE (target) == REG && TREE_STATIC (exp)) + emit_move_insn (target, const0_rtx); + /* If the constructor has fewer fields than the structure, clear the whole structure first. */ else if (list_length (CONSTRUCTOR_ELTS (exp)) - != list_length (TYPE_FIELDS (TREE_TYPE (exp)))) - clear_storage (target, int_size_in_bytes (TREE_TYPE (exp))); + != list_length (TYPE_FIELDS (type))) + clear_storage (target, int_size_in_bytes (type)); else /* Inform later passes that the old value is dead. */ emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); @@ -2262,23 +2270,25 @@ store_constructor (exp, target) /* The alignment of TARGET is at least what its type requires. */ VOIDmode, 0, - TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT, - int_size_in_bytes (TREE_TYPE (exp))); + TYPE_ALIGN (type) / BITS_PER_UNIT, + int_size_in_bytes (type)); } } - else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) + else if (TREE_CODE (type) == ARRAY_TYPE) { register tree elt; register int i; - tree domain = TYPE_DOMAIN (TREE_TYPE (exp)); + tree domain = TYPE_DOMAIN (type); int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain)); int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain)); - tree elttype = TREE_TYPE (TREE_TYPE (exp)); + tree elttype = TREE_TYPE (type); /* If the constructor has fewer fields than the structure, - clear the whole structure first. */ + clear the whole structure first. Similarly if this this is + static constructor of a non-BLKmode object. */ - if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1) + if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1 + || (GET_CODE (target) == REG && TREE_STATIC (exp))) clear_storage (target, maxelt - minelt + 1); else /* Inform later passes that the old value is dead. */ @@ -2306,8 +2316,8 @@ store_constructor (exp, target) /* The alignment of TARGET is at least what its type requires. */ VOIDmode, 0, - TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT, - int_size_in_bytes (TREE_TYPE (exp))); + TYPE_ALIGN (type) / BITS_PER_UNIT, + int_size_in_bytes (type)); } } @@ -2930,7 +2940,7 @@ expand_expr (exp, target, tmode, modifier) if (DECL_RTL (exp) == 0) { error_with_decl (exp, "prior parameter's size depends on `%s'"); - return const0_rtx; + return CONST0_RTX (mode); } case FUNCTION_DECL: @@ -2968,6 +2978,7 @@ expand_expr (exp, target, tmode, modifier) addr = fix_lexical_addr (addr, exp); return change_address (DECL_RTL (exp), mode, addr); } + /* This is the case of an array whose size is to be determined from its initializer, while the initializer is still being parsed. See expand_decl. */ @@ -3125,10 +3136,11 @@ expand_expr (exp, target, tmode, modifier) return RTL_EXPR_RTL (exp); case CONSTRUCTOR: - /* All elts simple constants => refer to a constant in memory. */ - if (TREE_STATIC (exp)) - /* For aggregate types with non-BLKmode modes, - this should ideally construct a CONST_INT. */ + /* All elts simple constants => refer to a constant in memory. But + if this is a non-BLKmode mode, let it store a field at a time + since that should make a CONST_INT or CONST_DOUBLE when we + fold. */ + if (TREE_STATIC (exp) && (mode == BLKmode || TREE_ADDRESSABLE (exp))) { rtx constructor = output_constant_def (exp); if (! memory_address_p (GET_MODE (constructor), @@ -3290,13 +3302,36 @@ expand_expr (exp, target, tmode, modifier) } /* If this is a constant index into a constant array, - just get the value from the array. */ - if (TREE_READONLY (TREE_OPERAND (exp, 0)) - && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == ARRAY_TYPE - && TREE_CODE (TREE_OPERAND (exp, 0)) == VAR_DECL - && DECL_INITIAL (TREE_OPERAND (exp, 0)) - && TREE_CODE (DECL_INITIAL (TREE_OPERAND (exp, 0))) != ERROR_MARK) + just get the value from the array. Handle both the cases when + we have an explicit constructor and when our operand is a variable + that was declared const. */ + + if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))) + { + tree index = fold (TREE_OPERAND (exp, 1)); + if (TREE_CODE (index) == INTEGER_CST + && TREE_INT_CST_HIGH (index) == 0) + { + int i = TREE_INT_CST_LOW (index); + tree elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); + + while (elem && i--) + elem = TREE_CHAIN (elem); + if (elem) + return expand_expr (fold (TREE_VALUE (elem)), target, + tmode, modifier); + } + } + + else if (TREE_READONLY (TREE_OPERAND (exp, 0)) + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == ARRAY_TYPE + && TREE_CODE (TREE_OPERAND (exp, 0)) == VAR_DECL + && DECL_INITIAL (TREE_OPERAND (exp, 0)) + && optimize >= 1 + && (TREE_CODE (DECL_INITIAL (TREE_OPERAND (exp, 0))) + != ERROR_MARK)) { tree index = fold (TREE_OPERAND (exp, 1)); if (TREE_CODE (index) == INTEGER_CST @@ -3328,6 +3363,19 @@ expand_expr (exp, target, tmode, modifier) case COMPONENT_REF: case BIT_FIELD_REF: + /* If the operand is a CONSTRUCTOR, we can just extract the + appropriate field if it is present. */ + if (code != ARRAY_REF + && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR) + { + tree elt; + + for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt; + elt = TREE_CHAIN (elt)) + if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)) + return expand_expr (TREE_VALUE (elt), target, tmode, modifier); + } + { enum machine_mode mode1; int bitsize; @@ -4736,7 +4784,10 @@ expand_builtin (exp, target, subtarget, mode, ignore) lab2 = gen_label_rtx (); /* By default check the arguments. If flag_fast_math is turned on, - then assume sqrt will always be called with valid arguments. */ + then assume sqrt will always be called with valid arguments. + Note changing the test below from "> 0" to ">= 0" would cause + incorrect results when computing sqrt(-0.0). */ + if (! flag_fast_math) { /* By checking op > 0 we are able to catch all of the @@ -4745,8 +4796,11 @@ expand_builtin (exp, target, subtarget, mode, ignore) GET_MODE (op0), 0, 0); emit_jump_insn (gen_bgt (lab1)); - /* The argument was not in the domain; do this via library call. */ + /* The argument was not in the domain; do this via library call. + Pop the arguments right away in case the call gets deleted. */ + NO_DEFER_POP; expand_call (exp, target, 0, 0); + OK_DEFER_POP; /* Branch around open coded version */ emit_jump_insn (gen_jump (lab2)); -- 2.30.2