diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c index 5a2bf6d865c..f758bc59765 100644 --- a/gas/config/tc-i386-intel.c +++ b/gas/config/tc-i386-intel.c @@ -633,6 +633,7 @@ i386_intel_operand (char *operand_string, int got_a_float) input_line_pointer = buf = xstrdup (operand_string); intel_syntax = -1; + expr_mode = expr_operator_none; memset (&exp, 0, sizeof(exp)); exp_seg = expression (&exp); ret = i386_intel_simplify (&exp); diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 9efb1e58447..f9482a0ba4d 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -827,6 +827,14 @@ i386_cpu_flags cpu_arch_isa_flags; larger than a byte offset. */ static bool no_cond_jump_promotion = false; +/* This will be set from an expression parser hook if there's any + applicable operator involved in an expression. */ +static enum { + expr_operator_none, + expr_operator_present, + expr_large_value, +} expr_mode; + /* Encode SSE instructions with VEX prefix. */ static unsigned int sse2avx; @@ -6016,6 +6024,8 @@ optimize_imm (void) } else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) guess_suffix = WORD_MNEM_SUFFIX; + else if (flag_code != CODE_64BIT || !(i.prefix[REX_PREFIX] & REX_W)) + guess_suffix = LONG_MNEM_SUFFIX; for (op = i.operands; --op >= 0;) if (operand_type_check (i.types[op], imm)) @@ -10508,6 +10518,7 @@ x86_cons (expressionS *exp, int size) intel_syntax = -intel_syntax; exp->X_md = 0; + expr_mode = expr_operator_none; #if ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \ && !defined (LEX_AT)) \ @@ -10567,7 +10578,8 @@ x86_cons (expressionS *exp, int size) i386_intel_simplify (exp); /* If not 64bit, massage value, to account for wraparound when !BFD64. */ - if (size == 4 && exp->X_op == O_constant && !object_64bit) + if (size <= 4 && expr_mode == expr_operator_present + && exp->X_op == O_constant && !object_64bit) exp->X_add_number = extend_to_32bit_address (exp->X_add_number); return got_reloc; @@ -11626,6 +11638,7 @@ i386_immediate (char *imm_start) if (gotfree_input_line) input_line_pointer = gotfree_input_line; + expr_mode = expr_operator_none; exp_seg = expression (exp); /* For .insn immediates there may be a size specifier. */ @@ -11684,7 +11697,8 @@ i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, /* If not 64bit, sign/zero extend val, to account for wraparound when !BFD64. */ - if (flag_code != CODE_64BIT && !object_64bit) + if (expr_mode == expr_operator_present + && flag_code != CODE_64BIT && !object_64bit) exp->X_add_number = extend_to_32bit_address (exp->X_add_number); } #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) @@ -11906,6 +11920,7 @@ i386_displacement (char *disp_start, char *disp_end) if (gotfree_input_line) input_line_pointer = gotfree_input_line; + expr_mode = expr_operator_none; exp_seg = expression (exp); SKIP_WHITESPACE (); @@ -11976,7 +11991,8 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, If not 64bit, sign/zero extend val, to account for wraparound when !BFD64. */ - if (flag_code != CODE_64BIT && !object_64bit) + if (expr_mode == expr_operator_present + && flag_code != CODE_64BIT && !object_64bit) exp->X_add_number = extend_to_32bit_address (exp->X_add_number); } @@ -13923,6 +13939,41 @@ md_operand (expressionS *e) } } +#ifdef BFD64 +/* To maintain consistency with !BFD64 builds of gas record, whether any + (binary) operator was involved in an expression. As expressions are + evaluated in only 32 bits when !BFD64, we use this to decide whether to + truncate results. */ +bool i386_record_operator (operatorT op, + const expressionS *left, + const expressionS *right) +{ + if (op == O_absent) + return false; + + if (!left) + { + /* Since the expression parser applies unary operators fine to bignum + operands, we don't need to be concerned of respective operands not + fitting in 32 bits. */ + if (right->X_op == O_constant && right->X_unsigned + && !fits_in_unsigned_long (right->X_add_number)) + return false; + } + /* This isn't entirely right: The pattern can also result when constant + expressions are folded (e.g. 0xffffffff + 1). */ + else if ((left->X_op == O_constant && left->X_unsigned + && !fits_in_unsigned_long (left->X_add_number)) + || (right->X_op == O_constant && right->X_unsigned + && !fits_in_unsigned_long (right->X_add_number))) + expr_mode = expr_large_value; + + if (expr_mode != expr_large_value) + expr_mode = expr_operator_present; + + return false; +} +#endif #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) const char *md_shortopts = "kVQ:sqnO::"; diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index 9247cdeab8b..62b82227571 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -188,6 +188,12 @@ extern operatorT i386_operator (const char *name, unsigned int operands, char *) extern int i386_need_index_operator (void); #define md_need_index_operator i386_need_index_operator +#ifdef BFD64 +extern bool i386_record_operator + (operatorT, const expressionS *, const expressionS *); +#define md_optimize_expr(l, o, r) i386_record_operator (o, l, r) +#endif + #define md_register_arithmetic 0 extern const struct relax_type md_relax_table[]; diff --git a/gas/testsuite/gas/i386/cst-diag.l b/gas/testsuite/gas/i386/cst-diag.l new file mode 100644 index 00000000000..0f0eb082746 --- /dev/null +++ b/gas/testsuite/gas/i386/cst-diag.l @@ -0,0 +1,43 @@ +.*: Assembler messages: +.*:3: Warning: .* +.*:4: Warning: .* +.*:5: (Error|Warning): .* +.*:6: (Error|Warning): .* +.*:8: Warning: .* +.*:9: Warning: .* +.*:10: (Error|Warning): .* +.*:11: (Error|Warning): .* +.*:13: Warning: .* +.*:14: Warning: .* +.*:15: (Error|Warning): .* +.*:16: (Error|Warning): .* +.*:18: Warning: .* +.*:19: (Error|Warning): .* +.*:20: (Error|Warning): .* +.*:22: (Error|Warning): .* +.*:23: (Error|Warning): .* +.*:24: (Error|Warning): .* +.*:25: (Error|Warning): .* +.*:30: Warning: .* +.*:31: Warning: .* +.*:35: Warning: .* +.*:36: Warning: .* +.*:40: Warning: .* +.*:41: Warning: .* +.*:46: Warning: .* +.*:47: Warning: .* +.*:48: Warning: .* +.*:50: Warning: .* +.*:51: Warning: .* +.*:52: Warning: .* +.*:55: Warning: .* +.*:56: Warning: .* +.*:57: Warning: .* +.*:59: Warning: .* +.*:60: Warning: .* +.*:61: Warning: .* +.*:64: Warning: .* +.*:65: Warning: .* +.*:66: Warning: .* +GAS LISTING .* +#pass diff --git a/gas/testsuite/gas/i386/cst-diag.s b/gas/testsuite/gas/i386/cst-diag.s new file mode 100644 index 00000000000..d34ab3b50a2 --- /dev/null +++ b/gas/testsuite/gas/i386/cst-diag.s @@ -0,0 +1,79 @@ + .text +const: + add $0x101, %cl + add $0x10001, %cx + add $0x100000001, %ecx + add 0x100000001, %ecx + + add $0x100, %cl + add $0x10000, %cx + add $0x100000000, %ecx + add 0x100000000, %ecx + + add $-0x101, %cl + add $-0x10001, %cx + add $-0x100000001, %ecx + add -0x100000001, %ecx + + add $-0x100, %cl + add $-0x10000, %cx + add $-0x100000000, %ecx + + add $0xffffffffffffff00, %cl + add $0xffffffffffff0000, %cx + add $0xffffffff00000000, %ecx + add 0xffffffff00000000, %ecx + + # The next two might as well not have a disagnostic issued, but if + # there is one (as is the case now), then it should be independent + # of BFD64. + and $~0xff, %cl + and $~0xffff, %cx + and $~0xffffffff, %ecx + and ~0xffffffff, %ecx + + and $0xff+2, %cl + and $0xffff+2, %cx + and $0xffffffff+2, %ecx + and 0xffffffff+2, %ecx + + and $0xff*2, %cl + and $0xffff*2, %cx + and $0xffffffff*2, %ecx + and 0xffffffff*2, %ecx + + .data + .byte 0x101 + .byte -0x100 + .byte 0xffffffffffffff00 +# .byte ~0xffffffffffffff00 + .byte ~0xff + .byte 0xff+2 + .byte 0xff*2 + + .p2align 4 + .word 0x10001 + .word -0x10000 + .word 0xffffffffffff0000 +# .word ~0xffffffffffff0000 + .word ~0xffff + .word 0xffff+2 + .word 0xffff*2 + + .p2align 4 + .long 0x100000001 + .long -0x100000000 + .long 0xffffffff00000000 +# .long ~0xffffffff00000000 + .long ~0xffffffff +# .long 0xffffffff+2 +# .long 0xffffffff*2 + + .p2align 4 + .quad 0x100000001 + .quad -0x100000000 + .quad 0xffffffff00000000 +# .quad ~0xffffffff00000000 + .quad ~0xffffffff +# .quad 0xffffffff+2 +# .quad 0xffffffff*2 diff --git a/gas/testsuite/gas/i386/disp-imm-32.d b/gas/testsuite/gas/i386/disp-imm-32.d index dc712b96269..aa2e4a07d87 100644 --- a/gas/testsuite/gas/i386/disp-imm-32.d +++ b/gas/testsuite/gas/i386/disp-imm-32.d @@ -1,5 +1,6 @@ #objdump: -dw #name: i386 displacements / immediates (32-bit) +#warning_output: disp-imm-32.e .*: +file format .* @@ -15,7 +16,7 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 8b 40 ff mov -0x1\(%eax\),%eax [ ]*[a-f0-9]+: 62 f1 7c 48 28 40 ff vmovaps -0x40\(%eax\),%zmm0 [ ]*[a-f0-9]+: 83 c1 ff add \$0xffffffff,%ecx -[ ]*[a-f0-9]+: 8b 40 01 mov 0x1\(%eax\),%eax -[ ]*[a-f0-9]+: 62 f1 7c 48 28 40 01 vmovaps 0x40\(%eax\),%zmm0 -[ ]*[a-f0-9]+: 83 c1 01 add \$0x1,%ecx +[ ]*[a-f0-9]+: 8b (40 01 +|80 01 00 00 00) mov 0x1\(%eax\),%eax +[ ]*[a-f0-9]+: 62 f1 7c 48 28 (40 01|80 40 00 00 00) vmovaps 0x40\(%eax\),%zmm0 +[ ]*[a-f0-9]+: (83 c1 01 +|81 c1 01 00 00 00) add \$0x1,%ecx #pass diff --git a/gas/testsuite/gas/i386/disp-imm-32.e b/gas/testsuite/gas/i386/disp-imm-32.e new file mode 100644 index 00000000000..3da95b426d0 --- /dev/null +++ b/gas/testsuite/gas/i386/disp-imm-32.e @@ -0,0 +1,4 @@ +.*: Assembler messages: +.*:15: Warning: .* shortened to 0x1 +.*:16: Warning: .* shortened to 0x40 +.*:17: Warning: .* shortened to 0x1 diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 40e75ac6f88..62796c71551 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -100,6 +100,7 @@ if [gas_32_check] then { run_dump_test "suffix-intel" run_list_test "suffix-bad" run_dump_test "immed32" + run_list_test "cst-diag" "-al" run_dump_test "equ" run_list_test "equ-2" "-al" run_list_test "equ-bad"