Hello! When x87 rounding bits are changed in x87 control word, the calculation clears precision bits in the new control word in certain cases. While precision bits are not used for frndint and fist[p] instructions, let's play safe and change only rounding bits. Also note, that for !TARGET_PARTIAL_REG_STALL, 16bit logic operations are later changed to 8bit operations on high register parts by generic x86 code.
2018-04-03 Uros Bizjak <ubiz...@gmail.com> * config/i386/i386.c (emit_i387_cw_initialization): Always use logic instructions when changing rounding bits to preserve precision bits in the x87 control word. Patch was bootstrapped and regression tested on x86_64-linux-gnu {,-m32}. I'll commit the patch to mainline SVN later today. Uros.
Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 259017) +++ config/i386/i386.c (working copy) @@ -19678,74 +19678,38 @@ emit_i387_cw_initialization (int mode) emit_insn (gen_x86_fnstcw_1 (stored_mode)); emit_move_insn (reg, copy_rtx (stored_mode)); - if (TARGET_64BIT || TARGET_PARTIAL_REG_STALL - || optimize_insn_for_size_p ()) + switch (mode) { - switch (mode) - { - case I387_CW_TRUNC: - /* round toward zero (truncate) */ - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0c00))); - slot = SLOT_CW_TRUNC; - break; + case I387_CW_TRUNC: + /* round toward zero (truncate) */ + emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0c00))); + slot = SLOT_CW_TRUNC; + break; - case I387_CW_FLOOR: - /* round down toward -oo */ - emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00))); - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0400))); - slot = SLOT_CW_FLOOR; - break; + case I387_CW_FLOOR: + /* round down toward -oo */ + emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00))); + emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0400))); + slot = SLOT_CW_FLOOR; + break; - case I387_CW_CEIL: - /* round up toward +oo */ - emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00))); - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0800))); - slot = SLOT_CW_CEIL; - break; + case I387_CW_CEIL: + /* round up toward +oo */ + emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00))); + emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0800))); + slot = SLOT_CW_CEIL; + break; - case I387_CW_MASK_PM: - /* mask precision exception for nearbyint() */ - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020))); - slot = SLOT_CW_MASK_PM; - break; + case I387_CW_MASK_PM: + /* mask precision exception for nearbyint() */ + emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020))); + slot = SLOT_CW_MASK_PM; + break; - default: - gcc_unreachable (); - } + default: + gcc_unreachable (); } - else - { - switch (mode) - { - case I387_CW_TRUNC: - /* round toward zero (truncate) */ - emit_insn (gen_insvsi_1 (reg, GEN_INT (0xc))); - slot = SLOT_CW_TRUNC; - break; - case I387_CW_FLOOR: - /* round down toward -oo */ - emit_insn (gen_insvsi_1 (reg, GEN_INT (0x4))); - slot = SLOT_CW_FLOOR; - break; - - case I387_CW_CEIL: - /* round up toward +oo */ - emit_insn (gen_insvsi_1 (reg, GEN_INT (0x8))); - slot = SLOT_CW_CEIL; - break; - - case I387_CW_MASK_PM: - /* mask precision exception for nearbyint() */ - emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020))); - slot = SLOT_CW_MASK_PM; - break; - - default: - gcc_unreachable (); - } - } - gcc_assert (slot < MAX_386_STACK_LOCALS); new_mode = assign_386_stack_local (HImode, slot);