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);
RegAlloc::Realize(Wvalue, flags);
code.CMP(*Wvalue, WZR);
code.TST(*Wvalue, *Wvalue);
}
template<>
@ -98,6 +98,17 @@ void EmitIR<IR::Opcode::GetLowerFromOp>(oaknut::CodeGenerator&, EmitContext& ctx
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<>
void EmitIR<IR::Opcode::NZCVFromPackedFlags>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* 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]);
RegAlloc::Realize(Wnz, Wc);
// TODO: Store in Flags
// TODO: Track latent value
code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv));
code.AND(Wscratch0, Wscratch0, 0x10000000);
code.ORR(Wscratch0, Wscratch0, Wnz);
code.SBFX(Wscratch0, Wc, 29, 1);
code.ORR(Wscratch0, Wscratch0, Wc);
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);
RegAlloc::Realize(Wflag);
// TODO: Store in Flags
code.LDR(Wscratch0, Xstate, offsetof(A32JitState, cpsr_nzcv));
code.LSR(Wflag, Wscratch0, 29);
code.AND(Wflag, Wflag, 1);
code.LDR(Wflag, Xstate, offsetof(A32JitState, cpsr_nzcv));
code.AND(Wflag, Wflag, 1 << 29);
}
template<>

View file

@ -117,7 +117,6 @@ void EmitIR<IR::Opcode::MostSignificantWord>(oaknut::CodeGenerator& code, EmitCo
template<>
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 Wresult = ctx.reg_alloc.WriteW(inst);
@ -129,12 +128,12 @@ void EmitIR<IR::Opcode::MostSignificantBit>(oaknut::CodeGenerator& code, EmitCon
template<>
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 Wresult = ctx.reg_alloc.WriteW(inst);
auto Woperand = ctx.reg_alloc.ReadW(args[0]);
RegAlloc::Realize(Wresult, Woperand);
ctx.reg_alloc.SpillFlags();
code.CMP(Woperand, 0);
code.CSET(Wresult, EQ);
@ -142,12 +141,12 @@ void EmitIR<IR::Opcode::IsZero32>(oaknut::CodeGenerator& code, EmitContext& ctx,
template<>
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 Wresult = ctx.reg_alloc.WriteW(inst);
auto Xoperand = ctx.reg_alloc.ReadX(args[0]);
RegAlloc::Realize(Wresult, Xoperand);
ctx.reg_alloc.SpillFlags();
code.CMP(Xoperand, 0);
code.CSET(Wresult, EQ);
@ -221,26 +220,37 @@ void EmitIR<IR::Opcode::LogicalShiftLeft32>(oaknut::CodeGenerator& code, EmitCon
code.CSEL(Wresult, Wresult, WZR, LT);
}
} else {
if (shift_arg.IsImmediate()) {
auto Wresult = ctx.reg_alloc.WriteW(inst);
auto Wcarry_out = ctx.reg_alloc.WriteW(carry_inst);
auto Woperand = ctx.reg_alloc.ReadW(operand_arg);
auto Wcarry_in = ctx.reg_alloc.ReadW(carry_arg);
RegAlloc::Realize(Wresult, Wcarry_out, Woperand, Wcarry_in);
if (shift_arg.IsImmediate() && shift_arg.GetImmediateU8() == 0) {
ctx.reg_alloc.DefineAsExisting(inst, operand_arg);
ctx.reg_alloc.DefineAsExisting(carry_inst, carry_arg);
} else if (shift_arg.IsImmediate()) {
// TODO: Use RMIF
const u8 shift = shift_arg.GetImmediateU8();
if (shift == 0) {
code.MOV(*Wresult, Woperand);
code.MOV(*Wcarry_out, Wcarry_in);
} else if (shift < 32) {
if (shift < 32) {
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.UBFX(Wcarry_out, Woperand, 32 - shift, 1);
code.LSL(Wcarry_out, Wcarry_out, 29);
code.LSL(Wresult, Woperand, shift);
} 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(Wcarry_out, WZR);
} 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);
}
} else {
@ -262,7 +272,7 @@ void EmitIR<IR::Opcode::LogicalShiftLeft32>(oaknut::CodeGenerator& code, EmitCon
code.NEG(Wscratch0, Wshift);
code.LSR(Wcarry_out, Woperand, Wscratch0);
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.CSEL(Wresult, Wresult, WZR, LT);
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 {
return value.GetType();
}
@ -101,6 +109,18 @@ bool HostLocInfo::IsOneRemainingUse() const {
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) {
ArgumentInfo ret = {Argument{*this}, Argument{*this}, Argument{*this}, Argument{*this}};
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) {
HostLocInfo& info = ValueInfo(host_loc);
if (!info.realized) {
return;
}
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;
}
ASSERT(info.locked && info.realized);
info.UpdateUses();
}
int RegAlloc::AllocateRegister(const std::array<HostLocInfo, 32>& regs, const std::vector<int>& order) const {

View file

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