backend/arm64: Update for new C flag representation

This commit is contained in:
Merry 2022-07-23 14:05:29 +01:00 committed by merry
parent d69582f548
commit 67df13f886
5 changed files with 67 additions and 36 deletions

View file

@ -83,7 +83,7 @@ void EmitIR<IR::Opcode::GetNZFromOp>(oaknut::CodeGenerator& code, EmitContext& c
auto flags = ctx.reg_alloc.WriteFlags(inst); auto flags = ctx.reg_alloc.WriteFlags(inst);
RegAlloc::Realize(Wvalue, flags); RegAlloc::Realize(Wvalue, flags);
code.CMP(*Wvalue, WZR); code.TST(*Wvalue, *Wvalue);
} }
template<> template<>
@ -98,6 +98,17 @@ void EmitIR<IR::Opcode::GetLowerFromOp>(oaknut::CodeGenerator&, EmitContext& ctx
ASSERT(ctx.reg_alloc.IsValueLive(inst)); ASSERT(ctx.reg_alloc.IsValueLive(inst));
} }
template<>
void EmitIR<IR::Opcode::GetCFlagFromNZCV>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Wc = ctx.reg_alloc.WriteW(inst);
auto Wnzcv = ctx.reg_alloc.ReadW(args[0]);
RegAlloc::Realize(Wc, Wnzcv);
code.AND(Wc, Wnzcv, 1 << 29);
}
template<> template<>
void EmitIR<IR::Opcode::NZCVFromPackedFlags>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::NZCVFromPackedFlags>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);

View file

@ -275,11 +275,12 @@ void EmitIR<IR::Opcode::A32SetCpsrNZC>(oaknut::CodeGenerator& code, EmitContext&
auto Wc = ctx.reg_alloc.ReadW(args[1]); auto Wc = ctx.reg_alloc.ReadW(args[1]);
RegAlloc::Realize(Wnz, Wc); RegAlloc::Realize(Wnz, Wc);
// TODO: Store in Flags // TODO: Track latent value
code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv)); code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv));
code.AND(Wscratch0, Wscratch0, 0x10000000); code.AND(Wscratch0, Wscratch0, 0x10000000);
code.ORR(Wscratch0, Wscratch0, Wnz); code.ORR(Wscratch0, Wscratch0, Wnz);
code.SBFX(Wscratch0, Wc, 29, 1); code.ORR(Wscratch0, Wscratch0, Wc);
code.STR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv)); code.STR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv));
} }
@ -288,11 +289,8 @@ void EmitIR<IR::Opcode::A32GetCFlag>(oaknut::CodeGenerator& code, EmitContext& c
auto Wflag = ctx.reg_alloc.WriteW(inst); auto Wflag = ctx.reg_alloc.WriteW(inst);
RegAlloc::Realize(Wflag); RegAlloc::Realize(Wflag);
// TODO: Store in Flags code.LDR(Wflag, Xstate, offsetof(A32JitState, cpsr_nzcv));
code.AND(Wflag, Wflag, 1 << 29);
code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv));
code.LSR(Wflag, Wscratch0, 29);
code.AND(Wflag, Wflag, 1);
} }
template<> template<>

View file

@ -117,7 +117,6 @@ void EmitIR<IR::Opcode::MostSignificantWord>(oaknut::CodeGenerator& code, EmitCo
template<> template<>
void EmitIR<IR::Opcode::MostSignificantBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::MostSignificantBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
// TODO: Use host flags
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Wresult = ctx.reg_alloc.WriteW(inst); auto Wresult = ctx.reg_alloc.WriteW(inst);
@ -129,12 +128,12 @@ void EmitIR<IR::Opcode::MostSignificantBit>(oaknut::CodeGenerator& code, EmitCon
template<> template<>
void EmitIR<IR::Opcode::IsZero32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::IsZero32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
// TODO: Use host flags
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Wresult = ctx.reg_alloc.WriteW(inst); auto Wresult = ctx.reg_alloc.WriteW(inst);
auto Woperand = ctx.reg_alloc.ReadW(args[0]); auto Woperand = ctx.reg_alloc.ReadW(args[0]);
RegAlloc::Realize(Wresult, Woperand); RegAlloc::Realize(Wresult, Woperand);
ctx.reg_alloc.SpillFlags();
code.CMP(Woperand, 0); code.CMP(Woperand, 0);
code.CSET(Wresult, EQ); code.CSET(Wresult, EQ);
@ -142,12 +141,12 @@ void EmitIR<IR::Opcode::IsZero32>(oaknut::CodeGenerator& code, EmitContext& ctx,
template<> template<>
void EmitIR<IR::Opcode::IsZero64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::IsZero64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
// TODO: Use host flags
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Wresult = ctx.reg_alloc.WriteW(inst); auto Wresult = ctx.reg_alloc.WriteW(inst);
auto Xoperand = ctx.reg_alloc.ReadX(args[0]); auto Xoperand = ctx.reg_alloc.ReadX(args[0]);
RegAlloc::Realize(Wresult, Xoperand); RegAlloc::Realize(Wresult, Xoperand);
ctx.reg_alloc.SpillFlags();
code.CMP(Xoperand, 0); code.CMP(Xoperand, 0);
code.CSET(Wresult, EQ); code.CSET(Wresult, EQ);
@ -221,26 +220,37 @@ void EmitIR<IR::Opcode::LogicalShiftLeft32>(oaknut::CodeGenerator& code, EmitCon
code.CSEL(Wresult, Wresult, WZR, LT); code.CSEL(Wresult, Wresult, WZR, LT);
} }
} else { } else {
if (shift_arg.IsImmediate()) { if (shift_arg.IsImmediate() && shift_arg.GetImmediateU8() == 0) {
auto Wresult = ctx.reg_alloc.WriteW(inst); ctx.reg_alloc.DefineAsExisting(inst, operand_arg);
auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst); ctx.reg_alloc.DefineAsExisting(carry_inst, carry_arg);
auto Woperand = ctx.reg_alloc.ReadW(operand_arg); } else if (shift_arg.IsImmediate()) {
auto Wcarry_in = ctx.reg_alloc.ReadW(carry_arg); // TODO: Use RMIF
RegAlloc::Realize(Wresult, Wcarry_out, Woperand, Wcarry_in);
const u8 shift = shift_arg.GetImmediateU8(); const u8 shift = shift_arg.GetImmediateU8();
if (shift == 0) { if (shift < 32) {
code.MOV(*Wresult, Woperand); auto Wresult = ctx.reg_alloc.WriteW(inst);
code.MOV(*Wcarry_out, Wcarry_in); auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst);
} else if (shift < 32) { auto Woperand = ctx.reg_alloc.ReadW(operand_arg);
RegAlloc::Realize(Wresult, Wcarry_out, Woperand);
code.UBFX(Wcarry_out, Woperand, 32 - shift, 1); code.UBFX(Wcarry_out, Woperand, 32 - shift, 1);
code.LSL(Wcarry_out, Wcarry_out, 29);
code.LSL(Wresult, Woperand, shift); code.LSL(Wresult, Woperand, shift);
} else if (shift > 32) { } else if (shift > 32) {
auto Wresult = ctx.reg_alloc.WriteW(inst);
auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst);
RegAlloc::Realize(Wresult, Wcarry_out);
code.MOV(Wresult, WZR); code.MOV(Wresult, WZR);
code.MOV(Wcarry_out, WZR); code.MOV(Wcarry_out, WZR);
} else { } else {
code.AND(Wcarry_out, Wresult, 1); auto Wresult = ctx.reg_alloc.WriteW(inst);
auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst);
auto Woperand = ctx.reg_alloc.ReadW(operand_arg);
RegAlloc::Realize(Wresult, Wcarry_out, Woperand);
code.UBFIZ(Wcarry_out, Woperand, 29, 1);
code.MOV(Wresult, WZR); code.MOV(Wresult, WZR);
} }
} else { } else {
@ -262,7 +272,7 @@ void EmitIR<IR::Opcode::LogicalShiftLeft32>(oaknut::CodeGenerator& code, EmitCon
code.NEG(Wscratch0, Wshift); code.NEG(Wscratch0, Wshift);
code.LSR(Wcarry_out, Woperand, Wscratch0); code.LSR(Wcarry_out, Woperand, Wscratch0);
code.LSL(Wresult, Woperand, Wshift); code.LSL(Wresult, Woperand, Wshift);
code.AND(Wcarry_out, Wcarry_out, 1); code.UBFIZ(Wcarry_out, Wcarry_out, 29, 1);
code.CMP(Wscratch1, 32); code.CMP(Wscratch1, 32);
code.CSEL(Wresult, Wresult, WZR, LT); code.CSEL(Wresult, Wresult, WZR, LT);
code.CSEL(Wcarry_out, Wcarry_out, WZR, LE); code.CSEL(Wcarry_out, Wcarry_out, WZR, LE);

View file

@ -27,6 +27,14 @@ static bool IsValuelessType(IR::Type type) {
} }
} }
Argument::~Argument() {
if (!IsImmediate()) {
if (auto host_loc = reg_alloc.ValueLocation(value.GetInst())) {
reg_alloc.ValueInfo(*host_loc).UpdateUses();
}
}
}
IR::Type Argument::GetType() const { IR::Type Argument::GetType() const {
return value.GetType(); return value.GetType();
} }
@ -101,6 +109,18 @@ bool HostLocInfo::IsOneRemainingUse() const {
return accumulated_uses + 1 == expected_uses && uses_this_inst == 1; return accumulated_uses + 1 == expected_uses && uses_this_inst == 1;
} }
void HostLocInfo::UpdateUses() {
accumulated_uses += uses_this_inst;
uses_this_inst = 0;
if (accumulated_uses == expected_uses) {
*this = {};
} else {
realized = false;
locked = false;
}
}
RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) { RegAlloc::ArgumentInfo RegAlloc::GetArgumentInfo(IR::Inst* inst) {
ArgumentInfo ret = {Argument{*this}, Argument{*this}, Argument{*this}, Argument{*this}}; ArgumentInfo ret = {Argument{*this}, Argument{*this}, Argument{*this}, Argument{*this}};
for (size_t i = 0; i < inst->NumArgs(); i++) { for (size_t i = 0; i < inst->NumArgs(); i++) {
@ -229,19 +249,8 @@ template int RegAlloc::RealizeWriteImpl<HostLoc::Kind::Flags>(const IR::Inst* va
void RegAlloc::Unlock(HostLoc host_loc) { void RegAlloc::Unlock(HostLoc host_loc) {
HostLocInfo& info = ValueInfo(host_loc); HostLocInfo& info = ValueInfo(host_loc);
if (!info.realized) { ASSERT(info.locked && info.realized);
return; info.UpdateUses();
}
info.accumulated_uses += info.uses_this_inst;
info.uses_this_inst = 0;
if (info.accumulated_uses == info.expected_uses) {
info = {};
} else {
info.realized = false;
info.locked = false;
}
} }
int RegAlloc::AllocateRegister(const std::array<HostLocInfo, 32>& regs, const std::vector<int>& order) const { int RegAlloc::AllocateRegister(const std::array<HostLocInfo, 32>& regs, const std::vector<int>& order) const {

View file

@ -39,6 +39,8 @@ struct Argument {
public: public:
using copyable_reference = std::reference_wrapper<Argument>; using copyable_reference = std::reference_wrapper<Argument>;
~Argument();
IR::Type GetType() const; IR::Type GetType() const;
bool IsImmediate() const; bool IsImmediate() const;
@ -124,6 +126,7 @@ struct HostLocInfo {
bool IsCompletelyEmpty() const; bool IsCompletelyEmpty() const;
bool IsImmediatelyAllocatable() const; bool IsImmediatelyAllocatable() const;
bool IsOneRemainingUse() const; bool IsOneRemainingUse() const;
void UpdateUses();
}; };
class RegAlloc { class RegAlloc {