mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-07 06:58:15 +01:00
backend_x64: Split emit_x64
This commit is contained in:
parent
2a493f8b50
commit
a554e4a329
7 changed files with 2829 additions and 2691 deletions
163
src/backend_x64/emit_x64_saturation.cpp
Normal file
163
src/backend_x64/emit_x64_saturation.cpp
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2016 MerryMage
|
||||
* This software may be used and distributed according to the terms of the GNU
|
||||
* General Public License version 2 or any later version.
|
||||
*/
|
||||
|
||||
#include "backend_x64/block_of_code.h"
|
||||
#include "backend_x64/emit_x64.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "frontend/ir/basic_block.h"
|
||||
#include "frontend/ir/microinstruction.h"
|
||||
#include "frontend/ir/opcodes.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
namespace BackendX64 {
|
||||
|
||||
using namespace Xbyak::util;
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitSignedSaturatedAdd(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
|
||||
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
||||
Xbyak::Reg32 addend = ctx.reg_alloc.UseGpr(args[1]).cvt32();
|
||||
Xbyak::Reg32 overflow = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
|
||||
code->mov(overflow, result);
|
||||
code->shr(overflow, 31);
|
||||
code->add(overflow, 0x7FFFFFFF);
|
||||
// overflow now contains 0x7FFFFFFF if a was positive, or 0x80000000 if a was negative
|
||||
code->add(result, addend);
|
||||
code->cmovo(result, overflow);
|
||||
|
||||
if (overflow_inst) {
|
||||
code->seto(overflow.cvt8());
|
||||
|
||||
ctx.reg_alloc.DefineValue(overflow_inst, overflow);
|
||||
ctx.EraseInstruction(overflow_inst);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitSignedSaturatedSub(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
|
||||
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
Xbyak::Reg32 result = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
||||
Xbyak::Reg32 subend = ctx.reg_alloc.UseGpr(args[1]).cvt32();
|
||||
Xbyak::Reg32 overflow = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
|
||||
code->mov(overflow, result);
|
||||
code->shr(overflow, 31);
|
||||
code->add(overflow, 0x7FFFFFFF);
|
||||
// overflow now contains 0x7FFFFFFF if a was positive, or 0x80000000 if a was negative
|
||||
code->sub(result, subend);
|
||||
code->cmovo(result, overflow);
|
||||
|
||||
if (overflow_inst) {
|
||||
code->seto(overflow.cvt8());
|
||||
|
||||
ctx.reg_alloc.DefineValue(overflow_inst, overflow);
|
||||
ctx.EraseInstruction(overflow_inst);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitUnsignedSaturation(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
|
||||
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
size_t N = args[1].GetImmediateU8();
|
||||
ASSERT(N <= 31);
|
||||
|
||||
u32 saturated_value = (1u << N) - 1;
|
||||
|
||||
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
Xbyak::Reg32 reg_a = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||
Xbyak::Reg32 overflow = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
|
||||
// Pseudocode: result = clamp(reg_a, 0, saturated_value);
|
||||
code->xor_(overflow, overflow);
|
||||
code->cmp(reg_a, saturated_value);
|
||||
code->mov(result, saturated_value);
|
||||
code->cmovle(result, overflow);
|
||||
code->cmovbe(result, reg_a);
|
||||
|
||||
if (overflow_inst) {
|
||||
code->seta(overflow.cvt8());
|
||||
|
||||
ctx.reg_alloc.DefineValue(overflow_inst, overflow);
|
||||
ctx.EraseInstruction(overflow_inst);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
template <typename JST>
|
||||
void EmitX64<JST>::EmitSignedSaturation(EmitContext& ctx, IR::Inst* inst) {
|
||||
auto overflow_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetOverflowFromOp);
|
||||
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
size_t N = args[1].GetImmediateU8();
|
||||
ASSERT(N >= 1 && N <= 32);
|
||||
|
||||
if (N == 32) {
|
||||
if (overflow_inst) {
|
||||
auto no_overflow = IR::Value(false);
|
||||
overflow_inst->ReplaceUsesWith(no_overflow);
|
||||
}
|
||||
ctx.reg_alloc.DefineValue(inst, args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 mask = (1u << N) - 1;
|
||||
u32 positive_saturated_value = (1u << (N - 1)) - 1;
|
||||
u32 negative_saturated_value = 1u << (N - 1);
|
||||
u32 sext_negative_satured_value = Common::SignExtend(N, negative_saturated_value);
|
||||
|
||||
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
Xbyak::Reg32 reg_a = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||
Xbyak::Reg32 overflow = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
|
||||
// overflow now contains a value between 0 and mask if it was originally between {negative,positive}_saturated_value.
|
||||
code->lea(overflow, code->ptr[reg_a.cvt64() + negative_saturated_value]);
|
||||
|
||||
// Put the appropriate saturated value in result
|
||||
code->cmp(reg_a, positive_saturated_value);
|
||||
code->mov(tmp, positive_saturated_value);
|
||||
code->mov(result, sext_negative_satured_value);
|
||||
code->cmovg(result, tmp);
|
||||
|
||||
// Do the saturation
|
||||
code->cmp(overflow, mask);
|
||||
code->cmovbe(result, reg_a);
|
||||
|
||||
if (overflow_inst) {
|
||||
code->seta(overflow.cvt8());
|
||||
|
||||
ctx.reg_alloc.DefineValue(overflow_inst, overflow);
|
||||
ctx.EraseInstruction(overflow_inst);
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
} // namespace BackendX64
|
||||
} // namespace Dynarmic
|
||||
|
||||
#include "backend_x64/a32_jitstate.h"
|
||||
#include "backend_x64/a64_jitstate.h"
|
||||
|
||||
template class Dynarmic::BackendX64::EmitX64<Dynarmic::BackendX64::A32JitState>;
|
||||
template class Dynarmic::BackendX64::EmitX64<Dynarmic::BackendX64::A64JitState>;
|
||||
Loading…
Add table
Add a link
Reference in a new issue