*** empty log message ***
authorJames Van Artsdalen <jrv@gnu.org>
Sun, 12 Apr 1992 21:47:29 +0000 (21:47 +0000)
committerJames Van Artsdalen <jrv@gnu.org>
Sun, 12 Apr 1992 21:47:29 +0000 (21:47 +0000)
From-SVN: r731

gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/expr.c

index 21eee4845b901622ba65c6fed4f5012ae18eabf7..3495d1da6b11fe3fbf5a44f729b1f01c296a9a8a 100644 (file)
@@ -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);
index 5d8027edbd48f670980ebe7edaa661e5df795c50..561eb8f7173da1c9ec8032b43706c88457e15ab2 100644 (file)
 ;; 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.
 
 \f
-
 ;; "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".
 (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;
        (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;
 ;; 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);
 }")
 \f
 ;; Store-flag instructions.
index c617894ba74427f37e592220a1cb0ce55902bcc2..8d2a42439a2931588eda393d172f9e1304e85114 100644 (file)
@@ -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));