diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 857a126699..1917fc0a20 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -837,6 +837,9 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) unlock_user_struct(fpstate, fpstate_addr, 0); #ifdef CONFIG_LATX load_xmm_from_env(env); + if (option_softfpu) { + cpu_x86_set_host_rounding_from_mxcsr(env); + } #endif } else { err = 0; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7a3f8aeb89..444cdd80de 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1934,6 +1934,9 @@ void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr); void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr); void cpu_x86_xsave(CPUX86State *s, target_ulong ptr); void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr); +#ifdef CONFIG_LATX +void cpu_x86_set_host_rounding_from_mxcsr(CPUX86State *s); +#endif /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target/i386/latx/include/translate.h b/target/i386/latx/include/translate.h index 38200bc429..ff709c4e5b 100644 --- a/target/i386/latx/include/translate.h +++ b/target/i386/latx/include/translate.h @@ -1728,6 +1728,8 @@ void tr_lat_spin_unlock(IR2_OPND lat_lock_addr); void gen_softfpu_helper_prologue(IR1_INST *pir1); void gen_softfpu_helper_epilogue(IR1_INST *pir1); +void gen_softfpu_x87_fcsr_enter(void); +void gen_softfpu_x87_fcsr_exit(void); void update_fcsr_rm(IR2_OPND control_word, IR2_OPND fcsr); bool ir1_need_reserve_h128(IR1_INST *ir1); diff --git a/target/i386/latx/translator/tr-fctrl.c b/target/i386/latx/translator/tr-fctrl.c index 36773c5f27..d017a2c5ba 100644 --- a/target/i386/latx/translator/tr-fctrl.c +++ b/target/i386/latx/translator/tr-fctrl.c @@ -111,6 +111,24 @@ void update_fcsr_rm(IR2_OPND control_word, IR2_OPND fcsr) ra_free_temp(temp_cw); } +void gen_softfpu_x87_fcsr_exit(void) +{ + IR2_OPND mxcsr_opnd = ra_alloc_itemp(); + IR2_OPND cw_opnd = ra_alloc_itemp(); + IR2_OPND fcsr_opnd = ra_alloc_itemp(); + + la_ld_wu(mxcsr_opnd, env_ir2_opnd, lsenv_offset_of_mxcsr(lsenv)); + la_bstrpick_d(cw_opnd, mxcsr_opnd, 14, 13); + la_slli_d(cw_opnd, cw_opnd, 10); + la_movfcsr2gr(fcsr_opnd, fcsr_ir2_opnd); + update_fcsr_rm(cw_opnd, fcsr_opnd); + la_movgr2fcsr(fcsr_ir2_opnd, fcsr_opnd); + + ra_free_temp(mxcsr_opnd); + ra_free_temp(cw_opnd); + ra_free_temp(fcsr_opnd); +} + void update_fcsr_by_sw(IR2_OPND sw) { IR2_OPND old_fcsr = ra_alloc_itemp(); @@ -234,6 +252,9 @@ bool translate_ldmxcsr(IR1_INST *pir1) tr_gen_call_to_helper1((ADDR)update_mxcsr_status, 1, LOAD_HELPER_UPDATE_MXCSR_STATUS); + if (option_softfpu) { + gen_softfpu_x87_fcsr_exit(); + } return true; } diff --git a/target/i386/latx/translator/tr-softfpu.c b/target/i386/latx/translator/tr-softfpu.c index 849cb968d0..f63ffbd95c 100644 --- a/target/i386/latx/translator/tr-softfpu.c +++ b/target/i386/latx/translator/tr-softfpu.c @@ -338,7 +338,9 @@ static void la_update_fp_status(IR2_OPND cw_opnd) IR2_OPND itemp = ra_alloc_itemp(); IR2_OPND tmp_fcsr = ra_alloc_itemp(); - IR2_OPND label_float64_float80 = ra_alloc_label(); + IR2_OPND label_float32 = ra_alloc_label(); + IR2_OPND label_float64 = ra_alloc_label(); + IR2_OPND label_precision_done = ra_alloc_label(); int fp_status_offset = lsenv_offset_of_fp_status(lsenv); int round_mode_offset = fp_status_offset + @@ -359,24 +361,59 @@ static void la_update_fp_status(IR2_OPND cw_opnd) * x86 env * * 32 00 10 + * reserved 01 00 * 64 10 01 - * 80 11 10 + * 80 11 00 * */ /* Precision Control (9, 8)*/ la_bstrpick_d(itemp, cw_opnd, 9, 8); - la_bne(itemp, zero_ir2_opnd, label_float64_float80); - li_wu(itemp, 1); + la_beq(itemp, zero_ir2_opnd, label_float32); + li_wu(tmp_fcsr, 2); + la_beq(itemp, tmp_fcsr, label_float64); + li_wu(itemp, floatx80_precision_x); + la_b(label_precision_done); - la_label(label_float64_float80); - la_xori(itemp, itemp, 3); + la_label(label_float32); + li_wu(itemp, floatx80_precision_s); + la_b(label_precision_done); + + la_label(label_float64); + li_wu(itemp, floatx80_precision_d); + + la_label(label_precision_done); la_st_b(itemp, env_ir2_opnd, round_precision_offset); ra_free_temp(itemp); ra_free_temp(tmp_fcsr); } +static void la_update_fp_status_from_env(void) +{ + IR2_OPND cw_opnd = ra_alloc_itemp(); + + la_ld_hu(cw_opnd, env_ir2_opnd, + lsenv_offset_of_control_word(lsenv)); + la_update_fp_status(cw_opnd); + ra_free_temp(cw_opnd); +} + +void gen_softfpu_x87_fcsr_enter(void) +{ + IR2_OPND cw_opnd = ra_alloc_itemp(); + IR2_OPND fcsr_opnd = ra_alloc_itemp(); + + la_ld_hu(cw_opnd, env_ir2_opnd, + lsenv_offset_of_control_word(lsenv)); + la_movfcsr2gr(fcsr_opnd, fcsr_ir2_opnd); + update_fcsr_rm(cw_opnd, fcsr_opnd); + la_movgr2fcsr(fcsr_ir2_opnd, fcsr_opnd); + + ra_free_temp(cw_opnd); + ra_free_temp(fcsr_opnd); +} + __attribute__((unused)) void gen_softfpu_helper_prologue(IR1_INST *pir1) { @@ -1924,17 +1961,12 @@ static bool translate_fldcw_softfpu(IR1_INST *pir1) { IR1_OPND *opnd0 = ir1_get_opnd(pir1, 0); IR2_OPND mem_opnd = convert_mem_no_offset(opnd0); + IR2_OPND new_cw = ra_alloc_itemp(); - if (option_softfpu == 2) { - IR2_OPND new_cw = ra_alloc_itemp(); - la_ld_hu(new_cw, mem_opnd, 0); - la_st_h(new_cw, env_ir2_opnd, lsenv_offset_of_control_word(lsenv)); - la_update_fp_status(new_cw); - ra_free_temp(new_cw); - - } else { - gen_softfpu_helper2m_16u((ADDR)helper_fldcw, mem_opnd); - } + la_ld_hu(new_cw, mem_opnd, 0); + la_st_h(new_cw, env_ir2_opnd, lsenv_offset_of_control_word(lsenv)); + la_update_fp_status(new_cw); + ra_free_temp(new_cw); return true; } @@ -2020,6 +2052,7 @@ static bool translate_fldenv_softfpu(IR1_INST *pir1) } else { gen_softfpu_helper3i((ADDR)helper_fldenv, mem_opnd, data32); + la_update_fp_status_from_env(); } return true; } @@ -2325,6 +2358,7 @@ static bool translate_fninit_softfpu(IR1_INST *pir1) ra_free_temp(temp); } else { gen_softfpu_helper1((ADDR)helper_fninit); + la_update_fp_status_from_env(); } return true; } @@ -2474,6 +2508,7 @@ static bool translate_fnsave_softfpu(IR1_INST *pir1) } else { IR2_OPND mem_opnd = convert_mem_no_offset(opnd0); gen_softfpu_helper3i((ADDR)helper_fsave, mem_opnd, data32); + la_update_fp_status_from_env(); } return true; } @@ -2618,6 +2653,7 @@ static bool translate_frstor_softfpu(IR1_INST *pir1) } else { IR2_OPND mem_opnd = convert_mem_no_offset(opnd0); gen_softfpu_helper3i((ADDR)helper_frstor, mem_opnd, data32); + la_update_fp_status_from_env(); } return true; @@ -3131,6 +3167,7 @@ static bool translate_fxrstor_softfpu(IR1_INST *pir1) IR2_OPND mem_opnd = convert_mem_no_offset(opnd0); gen_softfpu_helper2m_ptr((ADDR)helper_fxrstor, mem_opnd); + la_update_fp_status_from_env(); return true; } @@ -3227,6 +3264,7 @@ static bool translate_xrstor_softfpu(IR1_INST *pir1) la_bstrins_d(temp_rfbm, eax_opnd, 31, 0); la_bstrins_d(temp_rfbm, edx_opnd, 63, 32); gen_softfpu_helper3_ll((ADDR)helper_xrstor, mem_opnd, temp_rfbm); + gen_softfpu_x87_fcsr_exit(); return true; } #endif @@ -3268,7 +3306,7 @@ TRANS_FPU_WRAP_GEN(fisub); TRANS_FPU_WRAP_GEN(fisubr); TRANS_FPU_WRAP_GEN(fld1); TRANS_FPU_WRAP_GEN(fld); -TRANS_FPU_WRAP_GEN(fldcw); +TRANS_FPU_WRAP_GEN_NO_PROLOGUE(fldcw); TRANS_FPU_WRAP_GEN(fldenv); TRANS_FPU_WRAP_GEN(fldl2e); TRANS_FPU_WRAP_GEN(fldl2t); diff --git a/target/i386/latx/translator/translate.c b/target/i386/latx/translator/translate.c index 38266d7bbc..75a1aa739b 100644 --- a/target/i386/latx/translator/translate.c +++ b/target/i386/latx/translator/translate.c @@ -2101,6 +2101,108 @@ typedef enum SoftFPURegionClass { SOFTFPU_REGION_TRANSPARENT, } SoftFPURegionClass; +static bool is_softfpu_x87_insn(IR1_OPCODE opcode) +{ + switch (opcode) { + case dt_X86_INS_WAIT: + case dt_X86_INS_F2XM1: + case dt_X86_INS_FABS: + case dt_X86_INS_FADD: + case dt_X86_INS_FADDP: + case dt_X86_INS_FBLD: + case dt_X86_INS_FBSTP: + case dt_X86_INS_FCHS: + case dt_X86_INS_FCMOVB: + case dt_X86_INS_FCMOVBE: + case dt_X86_INS_FCMOVE: + case dt_X86_INS_FCMOVNB: + case dt_X86_INS_FCMOVNBE: + case dt_X86_INS_FCMOVNE: + case dt_X86_INS_FCMOVNU: + case dt_X86_INS_FCMOVU: + case dt_X86_INS_FCOM: + case dt_X86_INS_FCOMI: + case dt_X86_INS_FCOMIP: + case dt_X86_INS_FCOMP: + case dt_X86_INS_FCOMPP: + case dt_X86_INS_FCOS: + case dt_X86_INS_FDECSTP: + case dt_X86_INS_FDIV: + case dt_X86_INS_FDIVP: + case dt_X86_INS_FDIVR: + case dt_X86_INS_FDIVRP: + case dt_X86_INS_FFREE: + case dt_X86_INS_FFREEP: + case dt_X86_INS_FIADD: + case dt_X86_INS_FICOM: + case dt_X86_INS_FICOMP: + case dt_X86_INS_FIDIV: + case dt_X86_INS_FIDIVR: + case dt_X86_INS_FILD: + case dt_X86_INS_FIMUL: + case dt_X86_INS_FINCSTP: + case dt_X86_INS_FIST: + case dt_X86_INS_FISTP: + case dt_X86_INS_FISTTP: + case dt_X86_INS_FISUB: + case dt_X86_INS_FISUBR: + case dt_X86_INS_FLD1: + case dt_X86_INS_FLD: + case dt_X86_INS_FLDCW: + case dt_X86_INS_FLDENV: + case dt_X86_INS_FLDL2E: + case dt_X86_INS_FLDL2T: + case dt_X86_INS_FLDLG2: + case dt_X86_INS_FLDLN2: + case dt_X86_INS_FLDPI: + case dt_X86_INS_FLDZ: + case dt_X86_INS_FMUL: + case dt_X86_INS_FMULP: + case dt_X86_INS_FNCLEX: + case dt_X86_INS_FNINIT: + case dt_X86_INS_FNOP: + case dt_X86_INS_FNSAVE: + case dt_X86_INS_FNSTCW: + case dt_X86_INS_FNSTENV: + case dt_X86_INS_FNSTSW: + case dt_X86_INS_FPATAN: + case dt_X86_INS_FPREM1: + case dt_X86_INS_FPREM: + case dt_X86_INS_FPTAN: + case dt_X86_INS_FRNDINT: + case dt_X86_INS_FRSTOR: + case dt_X86_INS_FSCALE: + case dt_X86_INS_FSETPM: + case dt_X86_INS_FSIN: + case dt_X86_INS_FSINCOS: + case dt_X86_INS_FSQRT: + case dt_X86_INS_FST: + case dt_X86_INS_FSTP: + case dt_X86_INS_FSUB: + case dt_X86_INS_FSUBP: + case dt_X86_INS_FSUBR: + case dt_X86_INS_FSUBRP: + case dt_X86_INS_FTST: + case dt_X86_INS_FUCOM: + case dt_X86_INS_FUCOMI: + case dt_X86_INS_FUCOMIP: + case dt_X86_INS_FUCOMP: + case dt_X86_INS_FUCOMPP: + case dt_X86_INS_FXAM: + case dt_X86_INS_FXCH: + case dt_X86_INS_FXRSTOR: + case dt_X86_INS_FXRSTOR64: + case dt_X86_INS_FXSAVE: + case dt_X86_INS_FXSAVE64: + case dt_X86_INS_FXTRACT: + case dt_X86_INS_FYL2X: + case dt_X86_INS_FYL2XP1: + return true; + default: + return false; + } +} + static uint32_t softfpu_fast_mask(IR1_OPCODE opcode) { switch (opcode) { @@ -2310,6 +2412,7 @@ int tr_ir2_generate(struct TranslationBlock *tb) IR1_INST *pir1 = tb_ir1_inst(tb, 0); bool reduce_proepo = false; + bool x87_fcsr_active = false; int softfpu_region_end = -1; lsenv->tr_data->softfpu_region_active = false; @@ -2419,6 +2522,16 @@ int tr_ir2_generate(struct TranslationBlock *tb) } #endif + bool x87_insn = option_softfpu && + is_softfpu_x87_insn(ir1_opcode(pir1)); + if (x87_insn && !x87_fcsr_active) { + gen_softfpu_x87_fcsr_enter(); + x87_fcsr_active = true; + } else if (!x87_insn && x87_fcsr_active) { + gen_softfpu_x87_fcsr_exit(); + x87_fcsr_active = false; + } + if (option_softfpu == 2 && !reduce_proepo && softfpu_region_class(ir1_opcode(pir1)) == SOFTFPU_REGION_REQUIRED) { @@ -2455,6 +2568,9 @@ int tr_ir2_generate(struct TranslationBlock *tb) pir1++; } + if (x87_fcsr_active) { + gen_softfpu_x87_fcsr_exit(); + } #ifdef CONFIG_LATX_DEBUG if (option_dump_ir1) { pir1 = tb_ir1_inst(tb, 0); diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 1efc9d70b7..1af410363b 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -763,6 +763,34 @@ uint32_t helper_fnstcw(CPUX86State *env) return env->fpuc; } +static int x86_rounding_mode_to_host(unsigned mode) +{ + static int host_round_mode[4] = { + FE_TONEAREST, + FE_DOWNWARD, + FE_UPWARD, + FE_TOWARDZERO + }; + + assert(mode < ARRAY_SIZE(host_round_mode)); + return host_round_mode[mode]; +} + +#ifdef CONFIG_LATX +static unsigned x86_rounding_mode_to_fcsr(unsigned mode) +{ + static const unsigned fcsr_round_mode[4] = { + 0, /* round to nearest */ + 3, /* round down */ + 2, /* round up */ + 1, /* round toward zero */ + }; + + assert(mode < ARRAY_SIZE(fcsr_round_mode)); + return fcsr_round_mode[mode]; +} +#endif + static void set_x86_rounding_mode(unsigned mode, float_status *status) { static FloatRoundMode x86_round_mode[4] = { @@ -774,13 +802,7 @@ static void set_x86_rounding_mode(unsigned mode, float_status *status) assert(mode < ARRAY_SIZE(x86_round_mode)); set_float_rounding_mode(x86_round_mode[mode], status); if (option_set_rounding_opt) { - static int round_mode_enum[4] = { - FE_TONEAREST, - FE_DOWNWARD, - FE_UPWARD, - FE_TOWARDZERO - }; - fesetround(round_mode_enum[mode]); + fesetround(x86_rounding_mode_to_host(mode)); } } @@ -2856,7 +2878,7 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr) do_xsave_fpu(env, ptr, ra); if (env->cr[4] & CR4_OSFXSR_MASK) { - cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra); + do_xsave_mxcsr(env, ptr, ra); /* Fast FXSAVE leaves out the XMM registers */ if (!(env->efer & MSR_EFER_FFXSR) || (env->hflags & HF_CPL_MASK) @@ -3312,6 +3334,17 @@ void update_mxcsr_status(CPUX86State *env) set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } +#ifdef CONFIG_LATX +void cpu_x86_set_host_rounding_from_mxcsr(CPUX86State *env) +{ + unsigned mode = (env->mxcsr & SSE_RC_MASK) >> SSE_RC_SHIFT; + + env->fcsr = (env->fcsr & ~(3U << 8)) | + (x86_rounding_mode_to_fcsr(mode) << 8); + fesetround(x86_rounding_mode_to_host(mode)); +} +#endif + void update_mxcsr_from_sse_status(CPUX86State *env) { uint8_t flags = get_float_exception_flags(&env->sse_status); diff --git a/tests/integration/registrations/process/meson.build b/tests/integration/registrations/process/meson.build index bf2f8406bc..5fee4cf1c9 100644 --- a/tests/integration/registrations/process/meson.build +++ b/tests/integration/registrations/process/meson.build @@ -1,4 +1,20 @@ if 'x86_64-linux-user' in target_dirs + latx_integration_tests += [{ + 'name': 'test-softfpu-control-rounding-x86_64', + 'runner': find_program('../../test-softfpu-control-rounding-x86_64.sh'), + 'args': [ + emulators['latx-x86_64'], + files('../../softfpu-control-rounding-x86_64.S'), + ], + }] + latx_integration_tests += [{ + 'name': 'test-softfpu-signal-rounding-x86_64', + 'runner': find_program('../../test-softfpu-signal-rounding-x86_64.sh'), + 'args': [ + emulators['latx-x86_64'], + files('../../softfpu-signal-rounding-x86_64.S'), + ], + }] latx_integration_tests += [{ 'name': 'test-proc-readdir', 'runner': find_program('../../test-proc-readdir.sh'), @@ -86,6 +102,48 @@ if 'x86_64-linux-user' in target_dirs endif if 'i386-linux-user' in target_dirs + latx_integration_tests += [{ + 'name': 'test-softfpu-ldmxcsr-rounding-i386', + 'runner': find_program('../../test-softfpu-ldmxcsr-rounding-i386.sh'), + 'args': [ + emulators['latx-i386'], + files('../../softfpu-ldmxcsr-rounding-i386.S'), + ], + }] + latx_integration_tests += [{ + 'name': 'test-softfpu-fxsave-mxcsr-i386', + 'runner': find_program('../../test-softfpu-fxsave-mxcsr-i386.sh'), + 'args': [ + emulators['latx-i386'], + files('../../softfpu-fxsave-mxcsr-i386.S'), + ], + }] + latx_integration_tests += [{ + 'name': 'test-softfpu-control-rounding-i386', + 'runner': find_program('../../test-softfpu-control-rounding-i386.sh'), + 'args': [ + emulators['latx-i386'], + files('../../softfpu-control-rounding-i386.S'), + ], + }] + if 'CONFIG_LATX_AVX_OPT' in config_host + latx_integration_tests += [{ + 'name': 'test-softfpu-xrstor-rounding-i386', + 'runner': find_program('../../test-softfpu-xrstor-rounding-i386.sh'), + 'args': [ + emulators['latx-i386'], + files('../../softfpu-xrstor-rounding-i386.S'), + ], + }] + endif + latx_integration_tests += [{ + 'name': 'test-softfpu-signal-rounding-i386', + 'runner': find_program('../../test-softfpu-signal-rounding-i386.sh'), + 'args': [ + emulators['latx-i386'], + files('../../softfpu-signal-rounding-i386.S'), + ], + }] latx_integration_tests += [{ 'name': 'test-softfpu-eflags-region-i386', 'runner': find_program('../../test-softfpu-eflags-region-i386.sh'), diff --git a/tests/integration/softfpu-control-rounding-i386.S b/tests/integration/softfpu-control-rounding-i386.S new file mode 100644 index 0000000000..8b6dc948f3 --- /dev/null +++ b/tests/integration/softfpu-control-rounding-i386.S @@ -0,0 +1,145 @@ +.equ __NR_exit, 1 + +.macro check_down fail + fldl 8(%esp) + fcos + fstps 4(%esp) + cmpl $0x3f7fffff, 4(%esp) + jne \fail +.endm + +.macro check_sse_up fail + movss 16(%esp), %xmm0 + addss 20(%esp), %xmm0 + movss %xmm0, 4(%esp) + cmpl $0x3f800001, 4(%esp) + jne \fail +.endm + +.macro check_nearest fail + fldl 8(%esp) + fcos + fstps 4(%esp) + cmpl $0x3f800000, 4(%esp) + jne \fail +.endm + +.section .text +.global _start +.type _start, @function +_start: + and $-16, %esp + sub $2048, %esp + + movw $0x077f, 0(%esp) + movl $0, 8(%esp) + movl $0x3d700000, 12(%esp) + movl $0x3f800000, 16(%esp) + movl $0x33800000, 20(%esp) + + /* Reserved PC=01 follows QEMU's default extended-precision behavior. */ + movw $0x017f, 128(%esp) + fldcw 128(%esp) + fld1 + fldl 8(%esp) + faddp + fstpl 136(%esp) + cmpl $0x00001000, 136(%esp) + jne .Lfail_reserved_pc + cmpl $0x3ff00000, 140(%esp) + jne .Lfail_reserved_pc + + /* FLDCW must update both softfloat state and the host FCSR. */ + fninit + fldcw 0(%esp) + check_down .Lfail_fldcw + + /* FNINIT restores round-to-nearest. */ + fldcw 0(%esp) + fninit + check_nearest .Lfail_fninit + + /* FLDENV restores the x87 control word. */ + fldcw 0(%esp) + fnstenv 32(%esp) + fninit + fldenv 32(%esp) + check_down .Lfail_fldenv + + /* FNSAVE resets the x87 control word; FRSTOR restores it. */ + fldcw 0(%esp) + fnsave 64(%esp) + check_nearest .Lfail_fnsave + frstor 64(%esp) + check_down .Lfail_frstor + + /* FXRSTOR restores independent x87 and MXCSR rounding controls. */ + fldcw 0(%esp) + movl $0x5f80, 24(%esp) + ldmxcsr 24(%esp) + stmxcsr 28(%esp) + movl 28(%esp), %eax + and $0x6000, %eax + cmp $0x4000, %eax + jne .Lfail_ldmxcsr + fxsave 512(%esp) + movl 536(%esp), %eax + and $0x6000, %eax + cmp $0x4000, %eax + jne .Lfail_fxsave_mxcsr + fninit + movl $0x3f80, 24(%esp) + ldmxcsr 24(%esp) + fxrstor 512(%esp) + check_down .Lfail_fxrstor + stmxcsr 28(%esp) + movl 28(%esp), %eax + and $0x6000, %eax + cmp $0x4000, %eax + jne .Lfail_fxrstor_saved_mxcsr + check_sse_up .Lfail_fxrstor_mxcsr + check_down .Lfail_fxrstor_x87_again + + xor %ebx, %ebx + jmp .Lexit +.Lfail_fldcw: + mov $1, %ebx + jmp .Lexit +.Lfail_fninit: + mov $2, %ebx + jmp .Lexit +.Lfail_fldenv: + mov $3, %ebx + jmp .Lexit +.Lfail_fnsave: + mov $4, %ebx + jmp .Lexit +.Lfail_frstor: + mov $5, %ebx + jmp .Lexit +.Lfail_fxrstor: + mov $6, %ebx + jmp .Lexit +.Lfail_ldmxcsr: + mov $7, %ebx + jmp .Lexit +.Lfail_fxsave_mxcsr: + mov $8, %ebx + jmp .Lexit +.Lfail_fxrstor_saved_mxcsr: + mov $9, %ebx + jmp .Lexit +.Lfail_fxrstor_mxcsr: + mov $10, %ebx + jmp .Lexit +.Lfail_fxrstor_x87_again: + mov $11, %ebx + jmp .Lexit +.Lfail_reserved_pc: + mov $12, %ebx +.Lexit: + mov $__NR_exit, %eax + int $0x80 +.size _start, .-_start + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/softfpu-control-rounding-x86_64.S b/tests/integration/softfpu-control-rounding-x86_64.S new file mode 100644 index 0000000000..6907b6ca49 --- /dev/null +++ b/tests/integration/softfpu-control-rounding-x86_64.S @@ -0,0 +1,78 @@ +.equ __NR_exit, 60 + +.macro check_down fail + fldl 8(%rsp) + fcos + fstps 4(%rsp) + cmpl $0x3f7fffff, 4(%rsp) + jne \fail +.endm + +.macro check_sse_up fail + movss 16(%rsp), %xmm0 + addss 20(%rsp), %xmm0 + movss %xmm0, 4(%rsp) + cmpl $0x3f800001, 4(%rsp) + jne \fail +.endm + +.section .text +.global _start +.type _start, @function +_start: + and $-64, %rsp + sub $2048, %rsp + + movw $0x077f, 0(%rsp) + movl $0, 8(%rsp) + movl $0x3d700000, 12(%rsp) + movl $0x3f800000, 16(%rsp) + movl $0x33800000, 20(%rsp) + + /* Reserved PC=01 follows QEMU's default extended-precision behavior. */ + movw $0x017f, 128(%rsp) + fldcw 128(%rsp) + fld1 + fldl 8(%rsp) + faddp + fstpl 136(%rsp) + cmpl $0x00001000, 136(%rsp) + jne .Lfail_reserved_pc + cmpl $0x3ff00000, 140(%rsp) + jne .Lfail_reserved_pc + + fldcw 0(%rsp) + movl $0x5f80, 24(%rsp) + ldmxcsr 24(%rsp) + fxsave64 512(%rsp) + movl 536(%rsp), %eax + and $0x6000, %eax + cmp $0x4000, %eax + jne .Lfail_fxsave_mxcsr + + fninit + movl $0x3f80, 24(%rsp) + ldmxcsr 24(%rsp) + fxrstor64 512(%rsp) + check_down .Lfail_fxrstor + check_sse_up .Lfail_fxrstor_mxcsr + + xor %edi, %edi + jmp .Lexit +.Lfail_fxsave_mxcsr: + mov $1, %edi + jmp .Lexit +.Lfail_fxrstor: + mov $2, %edi + jmp .Lexit +.Lfail_fxrstor_mxcsr: + mov $3, %edi + jmp .Lexit +.Lfail_reserved_pc: + mov $4, %edi +.Lexit: + mov $__NR_exit, %eax + syscall +.size _start, .-_start + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/softfpu-fxsave-mxcsr-i386.S b/tests/integration/softfpu-fxsave-mxcsr-i386.S new file mode 100644 index 0000000000..1680355268 --- /dev/null +++ b/tests/integration/softfpu-fxsave-mxcsr-i386.S @@ -0,0 +1,29 @@ +.equ __NR_exit, 1 + +.section .text +.global _start +.type _start, @function +_start: + and $-16, %esp + sub $1024, %esp + + movl $0x5f80, 0(%esp) + ldmxcsr 0(%esp) + movl $0, 536(%esp) + fxsave 512(%esp) + + movl 536(%esp), %eax + and $0x6000, %eax + cmp $0x4000, %eax + jne .Lfail + + xor %ebx, %ebx + jmp .Lexit +.Lfail: + mov $1, %ebx +.Lexit: + mov $__NR_exit, %eax + int $0x80 +.size _start, .-_start + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/softfpu-ldmxcsr-rounding-i386.S b/tests/integration/softfpu-ldmxcsr-rounding-i386.S new file mode 100644 index 0000000000..4db5726309 --- /dev/null +++ b/tests/integration/softfpu-ldmxcsr-rounding-i386.S @@ -0,0 +1,30 @@ +.equ __NR_exit, 1 + +.section .text +.global _start +.type _start, @function +_start: + and $-16, %esp + sub $32, %esp + + movl $0x3f800000, 0(%esp) + movl $0x33800000, 4(%esp) + movl $0x5f80, 8(%esp) + ldmxcsr 8(%esp) + + movss 0(%esp), %xmm0 + addss 4(%esp), %xmm0 + movss %xmm0, 12(%esp) + cmpl $0x3f800001, 12(%esp) + jne .Lfail + + xor %ebx, %ebx + jmp .Lexit +.Lfail: + mov $1, %ebx +.Lexit: + mov $__NR_exit, %eax + int $0x80 +.size _start, .-_start + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/softfpu-signal-rounding-i386.S b/tests/integration/softfpu-signal-rounding-i386.S new file mode 100644 index 0000000000..a994652651 --- /dev/null +++ b/tests/integration/softfpu-signal-rounding-i386.S @@ -0,0 +1,108 @@ +.equ __NR_exit, 1 +.equ __NR_getpid, 20 +.equ __NR_kill, 37 +.equ __NR_rt_sigreturn, 173 +.equ __NR_rt_sigaction, 174 + +.equ SIGUSR1, 10 +.equ SA_SIGINFO, 4 +.equ SA_RESTORER, 0x04000000 + +.macro check_down fail + fldl 8(%esp) + fcos + fstps 4(%esp) + cmpl $0x3f7fffff, 4(%esp) + jne \fail +.endm + +.macro check_sse_up fail + movss 16(%esp), %xmm0 + addss 20(%esp), %xmm0 + movss %xmm0, 4(%esp) + cmpl $0x3f800001, 4(%esp) + jne \fail +.endm + +.section .text +.global _start +.type _start, @function +_start: + and $-16, %esp + sub $64, %esp + + movw $0x077f, 0(%esp) + movl $0, 8(%esp) + movl $0x3d700000, 12(%esp) + movl $0x3f800000, 16(%esp) + movl $0x33800000, 20(%esp) + movl $0x5f80, 24(%esp) + + mov $__NR_rt_sigaction, %eax + mov $SIGUSR1, %ebx + mov $signal_action, %ecx + xor %edx, %edx + mov $8, %esi + int $0x80 + test %eax, %eax + js .Lfail_sigaction + + fldcw 0(%esp) + ldmxcsr 24(%esp) + mov $__NR_getpid, %eax + int $0x80 + mov %eax, %ebx + mov $SIGUSR1, %ecx + mov $__NR_kill, %eax + int $0x80 + test %eax, %eax + js .Lfail_signal + + check_sse_up .Lfail_mxcsr + check_down .Lfail_x87 + xor %ebx, %ebx + jmp .Lexit +.Lfail_sigaction: + mov $1, %ebx + jmp .Lexit +.Lfail_signal: + mov $2, %ebx + jmp .Lexit +.Lfail_x87: + mov $3, %ebx + jmp .Lexit +.Lfail_mxcsr: + mov $4, %ebx +.Lexit: + mov $__NR_exit, %eax + int $0x80 +.size _start, .-_start + +.type signal_handler, @function +signal_handler: + fldcw signal_nearest_cw + ldmxcsr signal_down_mxcsr + ret +.size signal_handler, .-signal_handler + +.type signal_restorer, @function +signal_restorer: + mov $__NR_rt_sigreturn, %eax + int $0x80 + ud2 +.size signal_restorer, .-signal_restorer + +.section .data +.align 8 +signal_action: + .long signal_handler + .long SA_SIGINFO | SA_RESTORER + .long signal_restorer + .quad 0 +signal_nearest_cw: + .short 0x037f +.align 4 +signal_down_mxcsr: + .long 0x3f80 + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/softfpu-signal-rounding-x86_64.S b/tests/integration/softfpu-signal-rounding-x86_64.S new file mode 100644 index 0000000000..cd6d9db990 --- /dev/null +++ b/tests/integration/softfpu-signal-rounding-x86_64.S @@ -0,0 +1,108 @@ +.equ __NR_rt_sigaction, 13 +.equ __NR_rt_sigreturn, 15 +.equ __NR_getpid, 39 +.equ __NR_kill, 62 +.equ __NR_exit, 60 + +.equ SIGUSR1, 10 +.equ SA_SIGINFO, 4 +.equ SA_RESTORER, 0x04000000 + +.macro check_down fail + fldl 8(%rsp) + fcos + fstps 4(%rsp) + cmpl $0x3f7fffff, 4(%rsp) + jne \fail +.endm + +.macro check_sse_up fail + movss 16(%rsp), %xmm0 + addss 20(%rsp), %xmm0 + movss %xmm0, 4(%rsp) + cmpl $0x3f800001, 4(%rsp) + jne \fail +.endm + +.section .text +.global _start +.type _start, @function +_start: + and $-16, %rsp + sub $64, %rsp + + movw $0x077f, 0(%rsp) + movl $0, 8(%rsp) + movl $0x3d700000, 12(%rsp) + movl $0x3f800000, 16(%rsp) + movl $0x33800000, 20(%rsp) + movl $0x5f80, 24(%rsp) + + mov $__NR_rt_sigaction, %eax + mov $SIGUSR1, %edi + lea signal_action(%rip), %rsi + xor %edx, %edx + mov $8, %r10d + syscall + test %rax, %rax + js .Lfail_sigaction + + fldcw 0(%rsp) + ldmxcsr 24(%rsp) + mov $__NR_getpid, %eax + syscall + mov %eax, %edi + mov $SIGUSR1, %esi + mov $__NR_kill, %eax + syscall + test %rax, %rax + js .Lfail_signal + + check_sse_up .Lfail_mxcsr + check_down .Lfail_x87 + xor %edi, %edi + jmp .Lexit +.Lfail_sigaction: + mov $1, %edi + jmp .Lexit +.Lfail_signal: + mov $2, %edi + jmp .Lexit +.Lfail_x87: + mov $3, %edi + jmp .Lexit +.Lfail_mxcsr: + mov $4, %edi +.Lexit: + mov $__NR_exit, %eax + syscall +.size _start, .-_start + +.type signal_handler, @function +signal_handler: + fldcw signal_nearest_cw(%rip) + ldmxcsr signal_down_mxcsr(%rip) + ret +.size signal_handler, .-signal_handler + +.type signal_restorer, @function +signal_restorer: + mov $__NR_rt_sigreturn, %eax + syscall + ud2 +.size signal_restorer, .-signal_restorer + +.section .data +.align 8 +signal_action: + .quad signal_handler + .quad SA_SIGINFO | SA_RESTORER + .quad signal_restorer + .quad 0 +signal_nearest_cw: + .short 0x037f +.align 4 +signal_down_mxcsr: + .long 0x3f80 + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/softfpu-xrstor-rounding-i386.S b/tests/integration/softfpu-xrstor-rounding-i386.S new file mode 100644 index 0000000000..bca0883f4d --- /dev/null +++ b/tests/integration/softfpu-xrstor-rounding-i386.S @@ -0,0 +1,98 @@ +.equ __NR_exit, 1 + +.macro check_down fail + fldl 8(%esp) + fcos + fstps 4(%esp) + cmpl $0x3f7fffff, 4(%esp) + jne \fail +.endm + +.macro check_sse_nearest fail + movss 16(%esp), %xmm0 + addss 20(%esp), %xmm0 + movss %xmm0, 4(%esp) + cmpl $0x3f800000, 4(%esp) + jne \fail +.endm + +.macro check_sse_up fail + movss 16(%esp), %xmm0 + addss 20(%esp), %xmm0 + movss %xmm0, 4(%esp) + cmpl $0x3f800001, 4(%esp) + jne \fail +.endm + +.section .text +.global _start +.type _start, @function +_start: + and $-64, %esp + sub $2048, %esp + + movw $0x077f, 0(%esp) + movl $0, 8(%esp) + movl $0x3d700000, 12(%esp) + movl $0x3f800000, 16(%esp) + movl $0x33800000, 20(%esp) + + xor %ecx, %ecx + xgetbv + and $3, %eax + cmp $3, %eax + jne .Lfail_xcr0 + + fldcw 0(%esp) + movl $0x5f80, 24(%esp) + ldmxcsr 24(%esp) + xor %ecx, %ecx + xgetbv + xsave 512(%esp) + + movl 536(%esp), %ecx + and $0x6000, %ecx + cmp $0x4000, %ecx + jne .Lfail_xsave_mxcsr + + fninit + movl $0x1f80, 24(%esp) + ldmxcsr 24(%esp) + mov $1, %eax + xor %edx, %edx + xrstor 512(%esp) + /* Check SSE before an x87 exit can repair a stale host FCSR. */ + check_sse_nearest .Lfail_xrstor_mask + check_down .Lfail_xrstor_fp + + mov $3, %eax + xor %edx, %edx + xrstor 512(%esp) + check_sse_up .Lfail_xrstor_both_mxcsr + check_down .Lfail_xrstor_both_x87 + + xor %ebx, %ebx + jmp .Lexit +.Lfail_xcr0: + mov $1, %ebx + jmp .Lexit +.Lfail_xsave_mxcsr: + mov $2, %ebx + jmp .Lexit +.Lfail_xrstor_fp: + mov $3, %ebx + jmp .Lexit +.Lfail_xrstor_mask: + mov $4, %ebx + jmp .Lexit +.Lfail_xrstor_both_x87: + mov $5, %ebx + jmp .Lexit +.Lfail_xrstor_both_mxcsr: + mov $6, %ebx +.Lexit: + mov $__NR_exit, %eax + int $0x80 +.size _start, .-_start + +.section .note.GNU-stack,"",@progbits diff --git a/tests/integration/test-softfpu-control-rounding-i386.sh b/tests/integration/test-softfpu-control-rounding-i386.sh new file mode 100755 index 0000000000..75dec8bb6f --- /dev/null +++ b/tests/integration/test-softfpu-control-rounding-i386.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the i386 guest" + exit 77 +fi +if ! "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the i386 guest" + exit 77 +fi + +"$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-control-rounding-i386" + +for mode in 1 2; do + LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=$mode LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-control-rounding-i386" +done +LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=2 LATX_SOFTFPU_FAST=-1 \ + "$emulator" "$workdir/softfpu-control-rounding-i386" + +echo "PASS: softfpu restores independent x87 and SSE rounding state" diff --git a/tests/integration/test-softfpu-control-rounding-x86_64.sh b/tests/integration/test-softfpu-control-rounding-x86_64.sh new file mode 100755 index 0000000000..173b779306 --- /dev/null +++ b/tests/integration/test-softfpu-control-rounding-x86_64.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the x86_64 guest" + exit 77 +fi +if ! "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the x86_64 guest" + exit 77 +fi + +"$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-control-rounding-x86_64" + +for mode in 1 2; do + LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=$mode LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-control-rounding-x86_64" +done +LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=2 LATX_SOFTFPU_FAST=-1 \ + "$emulator" "$workdir/softfpu-control-rounding-x86_64" + +echo "PASS: x86_64 softfpu restores independent rounding state" diff --git a/tests/integration/test-softfpu-eflags-region-i386.sh b/tests/integration/test-softfpu-eflags-region-i386.sh index 534f279d1d..25de724a75 100755 --- a/tests/integration/test-softfpu-eflags-region-i386.sh +++ b/tests/integration/test-softfpu-eflags-region-i386.sh @@ -14,6 +14,12 @@ else echo "SKIP: clang is required to build the i386 guest" exit 77 fi +if ! "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the i386 guest" + exit 77 +fi "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ -Wl,--build-id=none "$source_file" \ diff --git a/tests/integration/test-softfpu-fxsave-mxcsr-i386.sh b/tests/integration/test-softfpu-fxsave-mxcsr-i386.sh new file mode 100755 index 0000000000..44f4c8f0bf --- /dev/null +++ b/tests/integration/test-softfpu-fxsave-mxcsr-i386.sh @@ -0,0 +1,33 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the i386 guest" + exit 77 +fi +if ! "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the i386 guest" + exit 77 +fi + +"$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-fxsave-mxcsr-i386" + +for mode in 1 2; do + LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=$mode LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-fxsave-mxcsr-i386" +done + +echo "PASS: softfpu FXSAVE records MXCSR" diff --git a/tests/integration/test-softfpu-helper-store-gpr-x86_64.sh b/tests/integration/test-softfpu-helper-store-gpr-x86_64.sh index 1a5b0872d0..6052b89401 100755 --- a/tests/integration/test-softfpu-helper-store-gpr-x86_64.sh +++ b/tests/integration/test-softfpu-helper-store-gpr-x86_64.sh @@ -14,6 +14,12 @@ else echo "SKIP: clang is required to build the x86_64 guest" exit 77 fi +if ! "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the x86_64 guest" + exit 77 +fi "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ -Wl,--build-id=none "$source_file" \ diff --git a/tests/integration/test-softfpu-ldmxcsr-rounding-i386.sh b/tests/integration/test-softfpu-ldmxcsr-rounding-i386.sh new file mode 100755 index 0000000000..fc731811af --- /dev/null +++ b/tests/integration/test-softfpu-ldmxcsr-rounding-i386.sh @@ -0,0 +1,33 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the i386 guest" + exit 77 +fi +if ! "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the i386 guest" + exit 77 +fi + +"$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-ldmxcsr-rounding-i386" + +for mode in 1 2; do + LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=$mode LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-ldmxcsr-rounding-i386" +done + +echo "PASS: softfpu LDMXCSR updates host rounding" diff --git a/tests/integration/test-softfpu-region-planner-x86_64.sh b/tests/integration/test-softfpu-region-planner-x86_64.sh index a6d1b3ac6c..eaa716caf6 100755 --- a/tests/integration/test-softfpu-region-planner-x86_64.sh +++ b/tests/integration/test-softfpu-region-planner-x86_64.sh @@ -14,6 +14,12 @@ else echo "SKIP: clang is required to build the x86_64 guest" exit 77 fi +if ! "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the x86_64 guest" + exit 77 +fi "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ -Wl,--build-id=none "$source_file" \ diff --git a/tests/integration/test-softfpu-shared-region-gpr-x86_64.sh b/tests/integration/test-softfpu-shared-region-gpr-x86_64.sh index 636c43169a..b9d98fecc2 100755 --- a/tests/integration/test-softfpu-shared-region-gpr-x86_64.sh +++ b/tests/integration/test-softfpu-shared-region-gpr-x86_64.sh @@ -14,6 +14,12 @@ else echo "SKIP: clang is required to build the x86_64 guest" exit 77 fi +if ! "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the x86_64 guest" + exit 77 +fi "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ -Wl,--build-id=none "$source_file" \ diff --git a/tests/integration/test-softfpu-signal-rounding-i386.sh b/tests/integration/test-softfpu-signal-rounding-i386.sh new file mode 100755 index 0000000000..fc7cb9f138 --- /dev/null +++ b/tests/integration/test-softfpu-signal-rounding-i386.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the i386 guest" + exit 77 +fi +if ! "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the i386 guest" + exit 77 +fi + +"$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-signal-rounding-i386" + +for mode in 1 2; do + LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=$mode LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-signal-rounding-i386" +done +LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=2 LATX_SOFTFPU_FAST=-1 \ + "$emulator" "$workdir/softfpu-signal-rounding-i386" + +echo "PASS: i386 sigreturn restores softfpu rounding state" diff --git a/tests/integration/test-softfpu-signal-rounding-x86_64.sh b/tests/integration/test-softfpu-signal-rounding-x86_64.sh new file mode 100755 index 0000000000..a3fe0310a5 --- /dev/null +++ b/tests/integration/test-softfpu-signal-rounding-x86_64.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the x86_64 guest" + exit 77 +fi +if ! "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the x86_64 guest" + exit 77 +fi + +"$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-signal-rounding-x86_64" + +for mode in 1 2; do + LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=$mode LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-signal-rounding-x86_64" +done +LATX_AOT=0 LATX_MT=0 LATX_SOFTFPU=2 LATX_SOFTFPU_FAST=-1 \ + "$emulator" "$workdir/softfpu-signal-rounding-x86_64" + +echo "PASS: x86_64 sigreturn restores softfpu rounding state" diff --git a/tests/integration/test-softfpu-xgetbv-gpr-x86_64.sh b/tests/integration/test-softfpu-xgetbv-gpr-x86_64.sh index a763c05d2d..e8d3da9ce5 100755 --- a/tests/integration/test-softfpu-xgetbv-gpr-x86_64.sh +++ b/tests/integration/test-softfpu-xgetbv-gpr-x86_64.sh @@ -14,6 +14,12 @@ else echo "SKIP: clang is required to build the x86_64 guest" exit 77 fi +if ! "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the x86_64 guest" + exit 77 +fi "$clang" --target=x86_64-linux-gnu -fuse-ld=lld -nostdlib -static \ -Wl,--build-id=none "$source_file" \ diff --git a/tests/integration/test-softfpu-xrstor-rounding-i386.sh b/tests/integration/test-softfpu-xrstor-rounding-i386.sh new file mode 100755 index 0000000000..06d0be445b --- /dev/null +++ b/tests/integration/test-softfpu-xrstor-rounding-i386.sh @@ -0,0 +1,37 @@ +#!/bin/sh +set -eu + +emulator=$(readlink -f "$1") +source_file=$(readlink -f "$2") +workdir=$(mktemp -d) +trap 'rm -rf "$workdir"' EXIT HUP INT TERM + +if command -v clang-19 >/dev/null 2>&1; then + clang=clang-19 +elif command -v clang >/dev/null 2>&1; then + clang=clang +else + echo "SKIP: clang is required to build the i386 guest" + exit 77 +fi +if ! "$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none -x assembler /dev/null \ + -o "$workdir/linker-check" >/dev/null 2>&1; then + echo "SKIP: clang with ld.lld is required to build the i386 guest" + exit 77 +fi + +"$clang" --target=i386-linux-gnu -fuse-ld=lld -nostdlib -static \ + -Wl,--build-id=none "$source_file" \ + -o "$workdir/softfpu-xrstor-rounding-i386" + +for mode in 1 2; do + LATX_AOT=0 LATX_AVX_CPUID=1 LATX_MT=0 LATX_SOFTFPU=$mode \ + LATX_SOFTFPU_FAST=0 \ + "$emulator" "$workdir/softfpu-xrstor-rounding-i386" +done +LATX_AOT=0 LATX_AVX_CPUID=1 LATX_MT=0 LATX_SOFTFPU=2 \ + LATX_SOFTFPU_FAST=-1 \ + "$emulator" "$workdir/softfpu-xrstor-rounding-i386" + +echo "PASS: softfpu XRSTOR preserves independent rounding controls"