putc ('*', file);
return;
- case 'D':
- PUT_OP_SIZE (code, 'l', file);
case 'L':
PUT_OP_SIZE (code, 'l', file);
return;
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. */
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)
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)
{
}
else
{
- if (code != 'c' && code != 'P')
+ if (code != 'P')
{
if (GET_CODE (x) == CONST_INT)
PRINT_IMMED_PREFIX (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.
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
}
#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));
/* 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. */
/* 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));
}
}
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:
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. */
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),
}
/* 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
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;
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
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));