--- 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 AT
 
       /* 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, cha
   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
 
 	 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);
     }
 
@@ -13928,6 +13944,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::";
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -633,6 +633,7 @@ i386_intel_operand (char *operand_string
   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);
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -188,6 +188,12 @@ extern operatorT i386_operator (const ch
 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[];
--- /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
--- /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
--- 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
--- /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
--- 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"
