backend/arm64: Update for new C flag representation
This commit is contained in:
parent
d69582f548
commit
67df13f886
5 changed files with 67 additions and 36 deletions
|
@ -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);
|
||||
|
|
|
@ -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<>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue