diff --git a/src/backend/llvm/branch_targets.cpp b/src/backend/llvm/branch_targets.cpp index 43ed05c..7b45280 100644 --- a/src/backend/llvm/branch_targets.cpp +++ b/src/backend/llvm/branch_targets.cpp @@ -89,12 +89,15 @@ BasicBlock *FunctionEmitter::externalDestination(const DolIRTerminator &term, builder_.CreateRetVoid(); } else { reloadCallCounters(); - for (u32 state = 0; state < DOLIR_STATE_COUNT; state++) { - if (!used_[state]) - continue; - auto stateSlot = static_cast(state); - builder_.CreateStore(loadContext(stateSlot), state_[state]); - } + // The callee can invalidate anything the emitter had concluded about + // guest state: whether MSR[FP] was already checked, which slots hold + // known constants, whether paired-single addressing was proven. + // Reloading the values without dropping those conclusions leaves + // stateValue() returning a constant the callee has since overwritten. + // The fallback resume path already uses reloadUsedState() for exactly + // this reason; this path reloaded values by hand and skipped the + // invalidation. + reloadUsedState(); builder_.CreateBr(blocks_[continuationBlock]); } builder_.restoreIP(saved); diff --git a/src/backend/llvm/register_state.cpp b/src/backend/llvm/register_state.cpp index 8de0335..4c692b9 100644 --- a/src/backend/llvm/register_state.cpp +++ b/src/backend/llvm/register_state.cpp @@ -58,6 +58,15 @@ void FunctionEmitter::noteStateWrite(DolIRStateSlot slot, Value *value) { } else if (slot == DOLIR_STATE_HID2) { psq_direct_proven_ = false; psq_indexed_proven_ = false; + } else if (slot == DOLIR_STATE_MSR) { + // MSR[FP] decides whether a floating-point instruction traps, and + // emitFPAvailable caches that answer for the rest of the region. A + // write to MSR can clear FP, so the cached answer has to go. Without + // this an mtmsr that disables FP mid-region leaves the FP + // instructions after it running unchecked, and the guest never takes + // the FP-unavailable exception its lazy FPU context switching is + // built on. + fp_available_checked_ = false; } }