From b6f7b8babd8ab0f930ca0e1bd3fa98ad2a823000 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Wed, 23 Nov 2016 19:44:27 +0000 Subject: [PATCH] ir: Implement GetGEFlags, SetGEFlags --- src/backend_x64/emit_x64.cpp | 25 +++++++++++++++++++++++++ src/frontend/ir/ir_emitter.cpp | 8 ++++++++ src/frontend/ir/ir_emitter.h | 2 ++ src/frontend/ir/microinstruction.cpp | 2 ++ src/frontend/ir/opcodes.inc | 2 ++ src/ir_opt/get_set_elimination_pass.cpp | 9 +++++++++ 6 files changed, 48 insertions(+) diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 671330ef..3bd0e9b4 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -278,6 +278,31 @@ void EmitX64::EmitOrQFlag(IR::Block&, IR::Inst* inst) { } } +void EmitX64::EmitGetGEFlags(IR::Block&, IR::Inst* inst) { + Xbyak::Reg32 result = reg_alloc.DefGpr(inst).cvt32(); + code->mov(result, MJitStateCpsr()); + code->shr(result, 16); + code->and_(result, 0xF); +} + +void EmitX64::EmitSetGEFlags(IR::Block&, IR::Inst* inst) { + constexpr size_t flag_bit = 16; + constexpr u32 flag_mask = 0xFu << flag_bit; + IR::Value arg = inst->GetArg(0); + if (arg.IsImmediate()) { + u32 imm = (arg.GetU32() << flag_bit) & flag_mask; + code->and_(MJitStateCpsr(), ~flag_mask); + code->or_(MJitStateCpsr(), imm); + } else { + Xbyak::Reg32 to_store = reg_alloc.UseScratchGpr(arg).cvt32(); + + code->shl(to_store, flag_bit); + code->and_(to_store, flag_mask); + code->and_(MJitStateCpsr(), ~flag_mask); + code->or_(MJitStateCpsr(), to_store); + } +} + void EmitX64::EmitBXWritePC(IR::Block&, IR::Inst* inst) { const u32 T_bit = 1 << 5; auto arg = inst->GetArg(0); diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 3e7f37a4..ab459e3b 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -137,6 +137,14 @@ void IREmitter::OrQFlag(const Value& value) { Inst(Opcode::OrQFlag, {value}); } +Value IREmitter::GetGEFlags() { + return Inst(Opcode::GetGEFlags, {}); +} + +void IREmitter::SetGEFlags(const Value& value) { + Inst(Opcode::SetGEFlags, {value}); +} + Value IREmitter::GetFpscr() { return Inst(Opcode::GetFpscr, {}); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index c839f883..32b1a51b 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -77,6 +77,8 @@ public: void SetCFlag(const Value& value); void SetVFlag(const Value& value); void OrQFlag(const Value& value); + Value GetGEFlags(); + void SetGEFlags(const Value& value); Value GetFpscr(); void SetFpscr(const Value& new_fpscr); diff --git a/src/frontend/ir/microinstruction.cpp b/src/frontend/ir/microinstruction.cpp index bfcb2fd0..92f5dbbc 100644 --- a/src/frontend/ir/microinstruction.cpp +++ b/src/frontend/ir/microinstruction.cpp @@ -99,6 +99,7 @@ bool Inst::ReadsFromCPSR() const { case Opcode::GetZFlag: case Opcode::GetCFlag: case Opcode::GetVFlag: + case Opcode::GetGEFlags: return true; default: @@ -114,6 +115,7 @@ bool Inst::WritesToCPSR() const { case Opcode::SetCFlag: case Opcode::SetVFlag: case Opcode::OrQFlag: + case Opcode::SetGEFlags: return true; default: diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index 04f2b52e..171e7a94 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -21,6 +21,8 @@ OPCODE(SetCFlag, T::Void, T::U1 OPCODE(GetVFlag, T::U1, ) OPCODE(SetVFlag, T::Void, T::U1 ) OPCODE(OrQFlag, T::Void, T::U1 ) +OPCODE(GetGEFlags, T::U32, ) +OPCODE(SetGEFlags, T::Void, T::U32 ) OPCODE(BXWritePC, T::Void, T::U32 ) OPCODE(CallSupervisor, T::Void, T::U32 ) OPCODE(GetFpscr, T::U32, ) diff --git a/src/ir_opt/get_set_elimination_pass.cpp b/src/ir_opt/get_set_elimination_pass.cpp index 3ee980dd..2fbefabb 100644 --- a/src/ir_opt/get_set_elimination_pass.cpp +++ b/src/ir_opt/get_set_elimination_pass.cpp @@ -30,6 +30,7 @@ void GetSetElimination(IR::Block& block) { RegisterInfo z; RegisterInfo c; RegisterInfo v; + RegisterInfo ge; } cpsr_info; const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst) { @@ -146,6 +147,14 @@ void GetSetElimination(IR::Block& block) { do_get(cpsr_info.v, inst); break; } + case IR::Opcode::SetGEFlags: { + do_set(cpsr_info.ge, inst->GetArg(0), inst); + break; + } + case IR::Opcode::GetGEFlags: { + do_get(cpsr_info.ge, inst); + break; + } default: { if (inst->ReadsFromCPSR() || inst->WritesToCPSR()) { cpsr_info = {};