https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121470
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|REOPENED |RESOLVED Resolution|--- |INVALID --- Comment #13 from Richard Biener <rguenth at gcc dot gnu.org> --- The bug is almost always a use of CONST_INT vs. trunc_int_for_mode where the latter seems missing in this case. You need to track that down, but I suspect the ASM processing doesn't know the "mode" of the value from the 'n' constraint? But even if that were word_mode we should have zero-extended. static void expand_asm_stmt (gasm *stmt) { ... ok = parse_input_constraint (&constraint, i, ninputs, noutputs, 0, constraints.address (), &allows_mem, &allows_reg, nullptr); gcc_assert (ok); /* EXPAND_INITIALIZER will not generate code for valid initializer constants, but will still generate code for other types of operand. This is the behavior we want for constant constraints. */ op = expand_expr (val, NULL_RTX, VOIDmode, allows_reg ? EXPAND_NORMAL : allows_mem ? EXPAND_MEMORY : EXPAND_INITIALIZER); so the result is as expected for a VOIDmode EXPAND_INITIALIZER result for unsigned short 0x8000. That is, the implicit mode of the operand is HImode here and as Andrew says we always sign-extend to HWI. All upper bits are "meaningless", but it appears HImode isn't the correct mode here. This is a bug in the asm() statement or how "parsing" of the argument works or how "n" is specified. Note asm()s do not get usual integer promotion applied. But it looks like the contraint expects an [unsigned] int type? So the fix is to write void f(void) { asm("ori 0,0,%0" : : "n"((int)(unsigned short)0x8000)); } or do as you did in g().