mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-12 02:58:59 +02:00
attempt use std::list instead
This commit is contained in:
parent
844e0360c7
commit
541dfe6805
24 changed files with 116 additions and 225 deletions
|
|
@ -405,8 +405,8 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
|
|||
}
|
||||
|
||||
void A32AddressSpace::RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo&) {
|
||||
const A32::LocationDescriptor descriptor{block.Location()};
|
||||
const A32::LocationDescriptor end_location{block.EndLocation()};
|
||||
const A32::LocationDescriptor descriptor{block.location};
|
||||
const A32::LocationDescriptor end_location{block.end_location};
|
||||
const auto range = boost::icl::discrete_interval<u32>::closed(descriptor.PC(), end_location.PC() - 1);
|
||||
block_ranges.AddRange(range, descriptor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -579,8 +579,8 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
|
|||
}
|
||||
|
||||
void A64AddressSpace::RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo&) {
|
||||
const A64::LocationDescriptor descriptor{block.Location()};
|
||||
const A64::LocationDescriptor end_location{block.EndLocation()};
|
||||
const A64::LocationDescriptor descriptor{block.location};
|
||||
const A64::LocationDescriptor end_location{block.end_location};
|
||||
const auto range = boost::icl::discrete_interval<u64>::closed(descriptor.PC(), end_location.PC() - 1);
|
||||
block_ranges.AddRange(range, descriptor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,12 +115,12 @@ EmittedBlockInfo AddressSpace::Emit(IR::Block block) {
|
|||
|
||||
EmittedBlockInfo block_info = EmitArm64(code, std::move(block), GetEmitConfig(), fastmem_manager);
|
||||
|
||||
ASSERT(block_entries.insert({block.Location(), block_info.entry_point}).second);
|
||||
ASSERT(reverse_block_entries.insert({block_info.entry_point, block.Location()}).second);
|
||||
ASSERT(block_entries.insert({block.location, block_info.entry_point}).second);
|
||||
ASSERT(reverse_block_entries.insert({block_info.entry_point, block.location}).second);
|
||||
ASSERT(block_infos.insert({block_info.entry_point, block_info}).second);
|
||||
|
||||
Link(block_info);
|
||||
RelinkForDescriptor(block.Location(), block_info.entry_point);
|
||||
RelinkForDescriptor(block.location, block_info.entry_point);
|
||||
|
||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||
ProtectCodeMemory();
|
||||
|
|
|
|||
|
|
@ -205,14 +205,14 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
|
|||
|
||||
ebi.entry_point = code.xptr<CodePtr>();
|
||||
|
||||
if (ctx.block.GetCondition() == IR::Cond::AL) {
|
||||
if (ctx.block.cond == IR::Cond::AL) {
|
||||
ASSERT(!ctx.block.HasConditionFailedLocation());
|
||||
} else {
|
||||
ASSERT(ctx.block.HasConditionFailedLocation());
|
||||
oaknut::Label pass;
|
||||
|
||||
pass = conf.emit_cond(code, ctx, ctx.block.GetCondition());
|
||||
EmitAddCycles(code, ctx, ctx.block.ConditionFailedCycleCount());
|
||||
pass = conf.emit_cond(code, ctx, ctx.block.cond);
|
||||
EmitAddCycles(code, ctx, ctx.block.cond_failed_cycle_count);
|
||||
conf.emit_condition_failed_terminal(code, ctx);
|
||||
|
||||
code.l(pass);
|
||||
|
|
@ -254,7 +254,7 @@ EmittedBlockInfo EmitArm64(oaknut::CodeGenerator& code, IR::Block block, const E
|
|||
|
||||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
EmitAddCycles(code, ctx, block.CycleCount());
|
||||
EmitAddCycles(code, ctx, block.cycle_count);
|
||||
conf.emit_terminal(code, ctx);
|
||||
code.BRK(0);
|
||||
|
||||
|
|
|
|||
|
|
@ -153,13 +153,13 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Te
|
|||
}
|
||||
|
||||
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
|
||||
const A32::LocationDescriptor location{ctx.block.Location()};
|
||||
EmitA32Terminal(code, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping());
|
||||
const A32::LocationDescriptor location{ctx.block.location};
|
||||
EmitA32Terminal(code, ctx, ctx.block.terminal, location.SetSingleStepping(false), location.SingleStepping());
|
||||
}
|
||||
|
||||
void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
|
||||
const A32::LocationDescriptor location{ctx.block.Location()};
|
||||
EmitA32Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping());
|
||||
const A32::LocationDescriptor location{ctx.block.location};
|
||||
EmitA32Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.cond_failed}, location.SetSingleStepping(false), location.SingleStepping());
|
||||
}
|
||||
|
||||
void EmitA32CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end) {
|
||||
|
|
@ -172,7 +172,7 @@ void EmitA32CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::
|
|||
code.LDAR(Xscratch0, Xhalt);
|
||||
code.TST(Xscratch0, static_cast<u32>(HaltReason::MemoryAbort));
|
||||
code.B(EQ, end);
|
||||
EmitSetUpperLocationDescriptor(code, ctx, current_location, ctx.block.Location());
|
||||
EmitSetUpperLocationDescriptor(code, ctx, current_location, ctx.block.location);
|
||||
code.MOV(Wscratch0, current_location.PC());
|
||||
code.STR(Wscratch0, Xstate, offsetof(A32JitState, regs) + sizeof(u32) * 15);
|
||||
EmitRelocation(code, ctx, LinkTarget::ReturnFromRunCode);
|
||||
|
|
@ -550,7 +550,7 @@ template<>
|
|||
void EmitIR<IR::Opcode::A32BXWritePC>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
||||
const u32 upper_without_t = (A32::LocationDescriptor{ctx.block.EndLocation()}.SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
const u32 upper_without_t = (A32::LocationDescriptor{ctx.block.end_location}.SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
|
||||
static_assert(offsetof(A32JitState, regs) + 16 * sizeof(u32) == offsetof(A32JitState, upper_location_descriptor));
|
||||
|
||||
|
|
@ -581,7 +581,7 @@ void EmitIR<IR::Opcode::A32UpdateUpperLocationDescriptor>(oaknut::CodeGenerator&
|
|||
for (auto& inst : ctx.block.instructions)
|
||||
if (inst.GetOpcode() == IR::Opcode::A32BXWritePC)
|
||||
return;
|
||||
EmitSetUpperLocationDescriptor(code, ctx, ctx.block.EndLocation(), ctx.block.Location());
|
||||
EmitSetUpperLocationDescriptor(code, ctx, ctx.block.end_location, ctx.block.location);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -136,13 +136,13 @@ void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Te
|
|||
}
|
||||
|
||||
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
|
||||
const A64::LocationDescriptor location{ctx.block.Location()};
|
||||
EmitA64Terminal(code, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping());
|
||||
const A64::LocationDescriptor location{ctx.block.location};
|
||||
EmitA64Terminal(code, ctx, ctx.block.terminal, location.SetSingleStepping(false), location.SingleStepping());
|
||||
}
|
||||
|
||||
void EmitA64ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx) {
|
||||
const A64::LocationDescriptor location{ctx.block.Location()};
|
||||
EmitA64Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping());
|
||||
const A64::LocationDescriptor location{ctx.block.location};
|
||||
EmitA64Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.cond_failed}, location.SetSingleStepping(false), location.SingleStepping());
|
||||
}
|
||||
|
||||
void EmitA64CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end) {
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ std::optional<DoNotFastmemMarker> ShouldFastmem(EmitContext& ctx, IR::Inst* inst
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto marker = std::make_tuple(ctx.block.Location(), inst->GetName());
|
||||
const auto marker = std::make_tuple(ctx.block.location, inst->GetName());
|
||||
if (ctx.fastmem.ShouldFastmem(marker)) {
|
||||
return marker;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct EmitContext {
|
|||
std::vector<std::function<void()>> deferred_emits;
|
||||
|
||||
FP::FPCR FPCR(bool fpcr_controlled = true) const {
|
||||
const FP::FPCR fpcr = conf.descriptor_to_fpcr(block.Location());
|
||||
const FP::FPCR fpcr = conf.descriptor_to_fpcr(block.location);
|
||||
return fpcr_controlled ? fpcr : fpcr.ASIMDStandardValue();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ EmittedBlockInfo EmitRV64(biscuit::Assembler& as, IR::Block block, const EmitCon
|
|||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
if (emit_conf.enable_cycle_counting) {
|
||||
const size_t cycles_to_add = block.CycleCount();
|
||||
const size_t cycles_to_add = block.cycle_count;
|
||||
as.LD(Xscratch0, offsetof(StackLayout, cycles_remaining), sp);
|
||||
if (mcl::bit::sign_extend<12>(-cycles_to_add) == -cycles_to_add) {
|
||||
as.ADDI(Xscratch0, Xscratch0, -cycles_to_add);
|
||||
|
|
|
|||
|
|
@ -199,8 +199,8 @@ void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Termina
|
|||
}
|
||||
|
||||
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx) {
|
||||
const A32::LocationDescriptor location{ctx.block.Location()};
|
||||
EmitA32Terminal(as, ctx, ctx.block.GetTerminal(), location.SetSingleStepping(false), location.SingleStepping());
|
||||
const A32::LocationDescriptor location{ctx.block.location};
|
||||
EmitA32Terminal(as, ctx, ctx.block.terminal, location.SetSingleStepping(false), location.SingleStepping());
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
|||
|
|
@ -64,11 +64,11 @@ A32EmitContext::A32EmitContext(const A32::UserConfig& conf, RegAlloc& reg_alloc,
|
|||
: EmitContext(reg_alloc, block), conf(conf) {}
|
||||
|
||||
A32::LocationDescriptor A32EmitContext::Location() const {
|
||||
return A32::LocationDescriptor{block.Location()};
|
||||
return A32::LocationDescriptor{block.location};
|
||||
}
|
||||
|
||||
A32::LocationDescriptor A32EmitContext::EndLocation() const {
|
||||
return A32::LocationDescriptor{block.EndLocation()};
|
||||
return A32::LocationDescriptor{block.end_location};
|
||||
}
|
||||
|
||||
bool A32EmitContext::IsSingleStep() const {
|
||||
|
|
@ -148,9 +148,9 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
|||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
if (conf.enable_cycle_counting) {
|
||||
EmitAddCycles(block.CycleCount());
|
||||
EmitAddCycles(block.cycle_count);
|
||||
}
|
||||
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
code.int3();
|
||||
|
||||
for (auto& deferred_emit : ctx.deferred_emits) {
|
||||
|
|
@ -160,8 +160,8 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) {
|
|||
|
||||
const size_t size = size_t(code.getCurr() - entrypoint);
|
||||
|
||||
const A32::LocationDescriptor descriptor{block.Location()};
|
||||
const A32::LocationDescriptor end_location{block.EndLocation()};
|
||||
const A32::LocationDescriptor descriptor{block.location};
|
||||
const A32::LocationDescriptor end_location{block.end_location};
|
||||
|
||||
const auto range = boost::icl::discrete_interval<u32>::closed(descriptor.PC(), end_location.PC() - 1);
|
||||
block_ranges.AddRange(range, descriptor);
|
||||
|
|
@ -183,18 +183,17 @@ void A32EmitX64::InvalidateCacheRanges(const boost::icl::interval_set<u32>& rang
|
|||
}
|
||||
|
||||
void A32EmitX64::EmitCondPrelude(const A32EmitContext& ctx) {
|
||||
if (ctx.block.GetCondition() == IR::Cond::AL) {
|
||||
if (ctx.block.cond == IR::Cond::AL) {
|
||||
ASSERT(!ctx.block.HasConditionFailedLocation());
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(ctx.block.HasConditionFailedLocation());
|
||||
|
||||
Xbyak::Label pass = EmitCond(ctx.block.GetCondition());
|
||||
Xbyak::Label pass = EmitCond(ctx.block.cond);
|
||||
if (conf.enable_cycle_counting) {
|
||||
EmitAddCycles(ctx.block.ConditionFailedCycleCount());
|
||||
EmitAddCycles(ctx.block.cond_failed_cycle_count);
|
||||
}
|
||||
EmitTerminal(IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
EmitTerminal(IR::Term::LinkBlock{ctx.block.cond_failed}, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
code.L(pass);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ A64EmitContext::A64EmitContext(const A64::UserConfig& conf, RegAlloc& reg_alloc,
|
|||
: EmitContext(reg_alloc, block), conf(conf) {}
|
||||
|
||||
A64::LocationDescriptor A64EmitContext::Location() const {
|
||||
return A64::LocationDescriptor{block.Location()};
|
||||
return A64::LocationDescriptor{block.location};
|
||||
}
|
||||
|
||||
bool A64EmitContext::IsSingleStep() const {
|
||||
|
|
@ -90,7 +90,7 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept {
|
|||
code.align();
|
||||
const auto* const entrypoint = code.getCurr();
|
||||
|
||||
DEBUG_ASSERT(block.GetCondition() == IR::Cond::AL);
|
||||
DEBUG_ASSERT(block.cond == IR::Cond::AL);
|
||||
typedef void (EmitX64::*EmitHandlerFn)(EmitContext& context, IR::Inst* inst);
|
||||
constexpr EmitHandlerFn opcode_handlers[] = {
|
||||
#define OPCODE(name, type, ...) &EmitX64::Emit##name,
|
||||
|
|
@ -142,9 +142,9 @@ finish_this_inst:
|
|||
reg_alloc.AssertNoMoreUses();
|
||||
|
||||
if (conf.enable_cycle_counting) {
|
||||
EmitAddCycles(block.CycleCount());
|
||||
EmitAddCycles(block.cycle_count);
|
||||
}
|
||||
EmitTerminal(block.GetTerminal(), ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
EmitTerminal(block.terminal, ctx.Location().SetSingleStepping(false), ctx.IsSingleStep());
|
||||
code.int3();
|
||||
|
||||
for (auto& deferred_emit : ctx.deferred_emits) {
|
||||
|
|
@ -154,8 +154,8 @@ finish_this_inst:
|
|||
|
||||
const size_t size = size_t(code.getCurr() - entrypoint);
|
||||
|
||||
const A64::LocationDescriptor descriptor{block.Location()};
|
||||
const A64::LocationDescriptor end_location{block.EndLocation()};
|
||||
const A64::LocationDescriptor descriptor{block.location};
|
||||
const A64::LocationDescriptor end_location{block.end_location};
|
||||
|
||||
const auto range = boost::icl::discrete_interval<u64>::closed(descriptor.PC(), end_location.PC() - 1);
|
||||
block_ranges.AddRange(range, descriptor);
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) {
|
|||
}
|
||||
|
||||
if (v.cond_state == ConditionalState::Translating) {
|
||||
if (v.ir.block.ConditionFailedLocation() != v.ir.current_location || cond == IR::Cond::AL) {
|
||||
if (v.ir.block.cond_failed != v.ir.current_location || cond == IR::Cond::AL) {
|
||||
v.cond_state = ConditionalState::Trailing;
|
||||
} else {
|
||||
if (cond == v.ir.block.GetCondition()) {
|
||||
v.ir.block.SetConditionFailedLocation(v.ir.current_location.AdvancePC(static_cast<int>(v.current_instruction_size)).AdvanceIT());
|
||||
v.ir.block.ConditionFailedCycleCount()++;
|
||||
if (cond == v.ir.block.cond) {
|
||||
v.ir.block.cond_failed = v.ir.current_location.AdvancePC(static_cast<int>(v.current_instruction_size)).AdvanceIT();
|
||||
v.ir.block.cond_failed_cycle_count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -77,9 +77,9 @@ bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) {
|
|||
// We'll emit one instruction, and set the block-entry conditional appropriately.
|
||||
|
||||
v.cond_state = ConditionalState::Translating;
|
||||
v.ir.block.SetCondition(cond);
|
||||
v.ir.block.SetConditionFailedLocation(v.ir.current_location.AdvancePC(static_cast<int>(v.current_instruction_size)).AdvanceIT());
|
||||
v.ir.block.ConditionFailedCycleCount() = v.ir.block.CycleCount() + 1;
|
||||
v.ir.block.cond = cond;
|
||||
v.ir.block.cond_failed = v.ir.current_location.AdvancePC(int(v.current_instruction_size)).AdvanceIT();
|
||||
v.ir.block.cond_failed_cycle_count = v.ir.block.cycle_count + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCall
|
|||
}
|
||||
|
||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
|
||||
block.CycleCount() += ticks_for_instruction;
|
||||
block.cycle_count += ticks_for_instruction;
|
||||
} while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step);
|
||||
|
||||
if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) {
|
||||
|
|
@ -74,7 +74,7 @@ void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCall
|
|||
}
|
||||
}
|
||||
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
||||
block.SetEndLocation(visitor.ir.current_location);
|
||||
block.end_location = visitor.ir.current_location;
|
||||
}
|
||||
|
||||
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 arm_instruction) {
|
||||
|
|
@ -101,10 +101,8 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript
|
|||
// TODO: Feedback resulting cond status to caller somehow.
|
||||
|
||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4);
|
||||
block.CycleCount() += ticks_for_instruction;
|
||||
|
||||
block.SetEndLocation(visitor.ir.current_location);
|
||||
|
||||
block.cycle_count += ticks_for_instruction;
|
||||
block.end_location = visitor.ir.current_location;
|
||||
return should_continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCa
|
|||
}
|
||||
|
||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(static_cast<int>(visitor.current_instruction_size)).AdvanceIT();
|
||||
block.CycleCount() += ticks_for_instruction;
|
||||
block.cycle_count += ticks_for_instruction;
|
||||
} while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step);
|
||||
|
||||
if (visitor.cond_state == ConditionalState::Translating || visitor.cond_state == ConditionalState::Trailing || single_step) {
|
||||
|
|
@ -174,7 +174,7 @@ void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCa
|
|||
}
|
||||
}
|
||||
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
||||
block.SetEndLocation(visitor.ir.current_location);
|
||||
block.end_location = visitor.ir.current_location;
|
||||
}
|
||||
|
||||
bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descriptor, u32 thumb_instruction) {
|
||||
|
|
@ -214,10 +214,8 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri
|
|||
|
||||
const s32 advance_pc = is_thumb_16 ? 2 : 4;
|
||||
visitor.ir.current_location = visitor.ir.current_location.AdvancePC(advance_pc);
|
||||
block.CycleCount() += ticks_for_instruction;
|
||||
|
||||
block.SetEndLocation(visitor.ir.current_location);
|
||||
|
||||
block.cycle_count += ticks_for_instruction;
|
||||
block.end_location = visitor.ir.current_location;
|
||||
return should_continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu
|
|||
should_continue = visitor.RaiseException(Exception::NoExecuteFault);
|
||||
}
|
||||
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
|
||||
block.CycleCount()++;
|
||||
block.cycle_count++;
|
||||
} while (should_continue && !single_step);
|
||||
|
||||
if (single_step && should_continue) {
|
||||
visitor.ir.SetTerm(IR::Term::LinkBlock{*visitor.ir.current_location});
|
||||
}
|
||||
ASSERT(block.HasTerminal() && "Terminal has not been set");
|
||||
block.SetEndLocation(*visitor.ir.current_location);
|
||||
block.end_location = *visitor.ir.current_location;
|
||||
}
|
||||
|
||||
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
|
||||
|
|
@ -48,10 +48,9 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
|
|||
should_continue = decoder.get().call(visitor, instruction);
|
||||
|
||||
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
|
||||
block.CycleCount()++;
|
||||
|
||||
block.SetEndLocation(*visitor.ir.current_location);
|
||||
block.cycle_count++;
|
||||
|
||||
block.end_location = *visitor.ir.current_location;
|
||||
return should_continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
|
|||
case SystemRegisterEncoding::CNTPCT_EL0:
|
||||
// HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date.
|
||||
if (!ir.block.instructions.empty() && !options.wall_clock_cntpct) {
|
||||
ir.block.CycleCount()--;
|
||||
ir.block.cycle_count--;
|
||||
ir.SetTerm(IR::Term::LinkBlock{*ir.current_location});
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,46 +23,35 @@
|
|||
namespace Dynarmic::IR {
|
||||
|
||||
Block::Block(LocationDescriptor location) noexcept
|
||||
: location{location}
|
||||
: cond_failed(0)
|
||||
, location{location}
|
||||
, end_location{location}
|
||||
{}
|
||||
|
||||
/// Prepends a new instruction to this basic block before the insertion point,
|
||||
/// handling any allocations necessary to do so.
|
||||
/// @param insertion_point Where to insert the new instruction.
|
||||
/// @param op Opcode representing the instruction to add.
|
||||
/// @param args A sequence of Value instances used as arguments for the instruction.
|
||||
/// @param op Opcode representing the instruction to add.
|
||||
/// @param args A sequence of Value instances used as arguments for the instruction.
|
||||
/// @returns Iterator to the newly created instruction.
|
||||
Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, std::initializer_list<Value> args) noexcept {
|
||||
Block::iterator Block::PrependNewInst(Block::const_iterator insertion_point, Opcode opcode, std::initializer_list<Value> args) noexcept {
|
||||
// First try using the "inline" buffer, otherwise fallback to a slower slab-like allocation scheme
|
||||
// purpouse is to avoid many calls to new/delete which invoke malloc which invokes mmap
|
||||
// just pool it!!! - reason why there is an inline buffer is because many small blocks are created
|
||||
// with few instructions due to subpar optimisations on other passes... plus branch-heavy code will
|
||||
// hugely benefit from the coherency of faster allocations...
|
||||
IR::Inst* inst;
|
||||
if (inlined_inst.size() < inlined_inst.max_size()) {
|
||||
inlined_inst.emplace_back(opcode);
|
||||
inst = &inlined_inst[inlined_inst.size() - 1];
|
||||
} else {
|
||||
if (pooled_inst.empty() || pooled_inst.back().size() == pooled_inst.back().max_size())
|
||||
pooled_inst.emplace_back();
|
||||
pooled_inst.back().emplace_back(opcode);
|
||||
inst = &pooled_inst.back()[pooled_inst.back().size() - 1];
|
||||
}
|
||||
DEBUG_ASSERT(args.size() == inst->NumArgs());
|
||||
std::for_each(args.begin(), args.end(), [&inst, index = size_t(0)](const auto& arg) mutable {
|
||||
inst->SetArg(index, arg);
|
||||
auto it = instructions.insert(insertion_point, Inst(opcode));
|
||||
DEBUG_ASSERT(args.size() == it->NumArgs());
|
||||
std::for_each(args.begin(), args.end(), [&it, index = size_t(0)](const auto& arg) mutable {
|
||||
it->SetArg(index, arg);
|
||||
index++;
|
||||
});
|
||||
return instructions.insert_before(insertion_point, inst);
|
||||
return it;
|
||||
}
|
||||
|
||||
void Block::Reset(LocationDescriptor location_) noexcept {
|
||||
mcl::intrusive_list<IR::Inst> tmp = {};
|
||||
instructions.swap(tmp);
|
||||
inlined_inst.clear();
|
||||
pooled_inst.clear();
|
||||
cond_failed.reset();
|
||||
instructions.clear();
|
||||
cond_failed = LocationDescriptor(0);
|
||||
location = location_;
|
||||
end_location = location_;
|
||||
cond = Cond::AL;
|
||||
|
|
@ -106,11 +95,11 @@ static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
|||
}
|
||||
|
||||
std::string DumpBlock(const IR::Block& block) noexcept {
|
||||
std::string ret = fmt::format("Block: location={}-{}\n", block.Location(), block.EndLocation())
|
||||
+ fmt::format("cycles={}", block.CycleCount())
|
||||
+ fmt::format(", entry_cond={}", A64::CondToString(block.GetCondition()));
|
||||
if (block.GetCondition() != Cond::AL)
|
||||
ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation());
|
||||
std::string ret = fmt::format("Block: location={}-{}\n", block.location, block.end_location)
|
||||
+ fmt::format("cycles={}", block.cycle_count)
|
||||
+ fmt::format(", entry_cond={}", A64::CondToString(block.cond));
|
||||
if (block.cond != Cond::AL)
|
||||
ret += fmt::format(", cond_fail={}", block.cond_failed);
|
||||
ret += '\n';
|
||||
|
||||
const auto arg_to_string = [](const IR::Value& arg) -> std::string {
|
||||
|
|
@ -173,7 +162,7 @@ std::string DumpBlock(const IR::Block& block) noexcept {
|
|||
|
||||
ret += fmt::format(" (uses: {})", inst.UseCount()) + '\n';
|
||||
}
|
||||
ret += "terminal = " + TerminalToString(block.GetTerminal()) + '\n';
|
||||
ret += "terminal = " + TerminalToString(block.terminal) + '\n';
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@
|
|||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <boost/container/container_fwd.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/container/stable_vector.hpp>
|
||||
#include <mcl/container/intrusive_list.hpp>
|
||||
#include "dynarmic/common/common_types.h"
|
||||
|
||||
#include "dynarmic/ir/location_descriptor.h"
|
||||
|
|
@ -33,15 +33,12 @@ enum class Opcode;
|
|||
/// Note that this is a linear IR and not a pure tree-based IR: i.e.: there is an ordering to
|
||||
/// the microinstructions. This only matters before chaining is done in order to correctly
|
||||
/// order memory accesses.
|
||||
class alignas(4096) Block final {
|
||||
class Block final {
|
||||
public:
|
||||
//using instruction_list_type = dense_list<Inst>;
|
||||
using instruction_list_type = mcl::intrusive_list<Inst>;
|
||||
using size_type = instruction_list_type::size_type;
|
||||
using instruction_list_type = std::list<Inst>;
|
||||
using iterator = instruction_list_type::iterator;
|
||||
using const_iterator = instruction_list_type::const_iterator;
|
||||
using reverse_iterator = instruction_list_type::reverse_iterator;
|
||||
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
||||
|
||||
Block(LocationDescriptor location) noexcept;
|
||||
~Block() = default;
|
||||
|
|
@ -50,105 +47,23 @@ public:
|
|||
Block(Block&&) = default;
|
||||
Block& operator=(Block&&) = default;
|
||||
|
||||
/// Appends a new instruction to the end of this basic block,
|
||||
/// handling any allocations necessary to do so.
|
||||
/// @param op Opcode representing the instruction to add.
|
||||
/// @param args A sequence of Value instances used as arguments for the instruction.
|
||||
inline iterator AppendNewInst(const Opcode opcode, const std::initializer_list<IR::Value> args) noexcept {
|
||||
return PrependNewInst(instructions.end(), opcode, args);
|
||||
}
|
||||
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
||||
[[nodiscard]] iterator PrependNewInst(const_iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
||||
void Reset(LocationDescriptor location_) noexcept;
|
||||
|
||||
/// Gets a mutable reference to the instruction list for this basic block.
|
||||
inline instruction_list_type& Instructions() noexcept {
|
||||
return instructions;
|
||||
}
|
||||
/// Gets an immutable reference to the instruction list for this basic block.
|
||||
inline const instruction_list_type& Instructions() const noexcept {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
/// Gets the starting location for this basic block.
|
||||
inline LocationDescriptor Location() const noexcept {
|
||||
return location;
|
||||
}
|
||||
/// Gets the end location for this basic block.
|
||||
inline LocationDescriptor EndLocation() const noexcept {
|
||||
return end_location;
|
||||
}
|
||||
/// Sets the end location for this basic block.
|
||||
inline void SetEndLocation(const LocationDescriptor& descriptor) noexcept {
|
||||
end_location = descriptor;
|
||||
}
|
||||
|
||||
/// Gets the condition required to pass in order to execute this block.
|
||||
inline Cond GetCondition() const noexcept {
|
||||
return cond;
|
||||
}
|
||||
/// Sets the condition required to pass in order to execute this block.
|
||||
inline void SetCondition(Cond condition) noexcept {
|
||||
cond = condition;
|
||||
}
|
||||
|
||||
/// Gets the location of the block to execute if the predicated condition fails.
|
||||
inline LocationDescriptor ConditionFailedLocation() const noexcept {
|
||||
return *cond_failed;
|
||||
}
|
||||
/// Sets the location of the block to execute if the predicated condition fails.
|
||||
inline void SetConditionFailedLocation(LocationDescriptor fail_location) noexcept {
|
||||
cond_failed = fail_location;
|
||||
}
|
||||
/// Determines whether or not a predicated condition failure block is present.
|
||||
inline bool HasConditionFailedLocation() const noexcept {
|
||||
return cond_failed.has_value();
|
||||
[[nodiscard]] inline bool HasConditionFailedLocation() const noexcept {
|
||||
return cond_failed.Value() > 0;
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the condition failed cycle count.
|
||||
inline size_t& ConditionFailedCycleCount() noexcept {
|
||||
return cond_failed_cycle_count;
|
||||
}
|
||||
/// Gets an immutable reference to the condition failed cycle count.
|
||||
inline const size_t& ConditionFailedCycleCount() const noexcept {
|
||||
return cond_failed_cycle_count;
|
||||
}
|
||||
|
||||
/// Gets the terminal instruction for this basic block.
|
||||
inline Terminal GetTerminal() const noexcept {
|
||||
return terminal;
|
||||
}
|
||||
/// Sets the terminal instruction for this basic block.
|
||||
inline void SetTerminal(Terminal term) noexcept {
|
||||
ASSERT(!HasTerminal() && "Terminal has already been set.");
|
||||
terminal = std::move(term);
|
||||
}
|
||||
/// Replaces the terminal instruction for this basic block.
|
||||
inline void ReplaceTerminal(Terminal term) noexcept {
|
||||
ASSERT(HasTerminal() && "Terminal has not been set.");
|
||||
terminal = std::move(term);
|
||||
}
|
||||
/// Determines whether or not this basic block has a terminal instruction.
|
||||
inline bool HasTerminal() const noexcept {
|
||||
[[nodiscard]] inline bool HasTerminal() const noexcept {
|
||||
return terminal.which() != 0;
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the cycle count for this basic block.
|
||||
inline size_t& CycleCount() noexcept {
|
||||
return cycle_count;
|
||||
}
|
||||
/// Gets an immutable reference to the cycle count for this basic block.
|
||||
inline const size_t& CycleCount() const noexcept {
|
||||
return cycle_count;
|
||||
}
|
||||
|
||||
/// "Hot cache" for small blocks so we don't call global allocator
|
||||
boost::container::static_vector<Inst, 30> inlined_inst;
|
||||
/// List of instructions in this block.
|
||||
instruction_list_type instructions;
|
||||
/// "Long/far" memory pool
|
||||
boost::container::stable_vector<boost::container::static_vector<Inst, 32>> pooled_inst;
|
||||
/// Block to execute next if `cond` did not pass.
|
||||
std::optional<LocationDescriptor> cond_failed = {};
|
||||
LocationDescriptor cond_failed;
|
||||
/// Description of the starting location of this block
|
||||
LocationDescriptor location;
|
||||
/// Description of the end location of this block
|
||||
|
|
@ -162,7 +77,7 @@ public:
|
|||
/// Number of cycles this block takes to execute.
|
||||
size_t cycle_count = 0;
|
||||
};
|
||||
static_assert(sizeof(Block) == 4096);
|
||||
//static_assert(sizeof(Block) == 120);
|
||||
|
||||
/// Returns a string representation of the contents of block. Intended for debugging.
|
||||
std::string DumpBlock(const IR::Block& block) noexcept;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,10 @@ enum class MemOp {
|
|||
/// The user of this class updates `current_location` as appropriate.
|
||||
class IREmitter {
|
||||
public:
|
||||
explicit IREmitter(Block& block) : block(block), insertion_point(block.instructions.end()) {}
|
||||
explicit IREmitter(Block& block) noexcept
|
||||
: block(block)
|
||||
, insertion_point(block.instructions.end())
|
||||
{}
|
||||
|
||||
Block& block;
|
||||
|
||||
|
|
@ -2944,22 +2947,14 @@ public:
|
|||
}
|
||||
|
||||
void SetTerm(const Terminal& terminal) {
|
||||
block.SetTerminal(terminal);
|
||||
}
|
||||
|
||||
void SetInsertionPointBefore(IR::Inst* new_insertion_point) {
|
||||
insertion_point = IR::Block::iterator{*new_insertion_point};
|
||||
ASSERT(!block.HasTerminal() && "Terminal has already been set.");
|
||||
block.terminal = std::move(terminal);
|
||||
}
|
||||
|
||||
void SetInsertionPointBefore(IR::Block::iterator new_insertion_point) {
|
||||
insertion_point = new_insertion_point;
|
||||
}
|
||||
|
||||
void SetInsertionPointAfter(IR::Inst* new_insertion_point) {
|
||||
insertion_point = IR::Block::iterator{*new_insertion_point};
|
||||
++insertion_point;
|
||||
}
|
||||
|
||||
void SetInsertionPointAfter(IR::Block::iterator new_insertion_point) {
|
||||
insertion_point = new_insertion_point;
|
||||
++insertion_point;
|
||||
|
|
@ -2970,7 +2965,9 @@ protected:
|
|||
|
||||
template<typename T = Value, typename... Args>
|
||||
T Inst(Opcode op, Args... args) {
|
||||
auto const offset = std::distance(block.instructions.begin(), insertion_point);
|
||||
auto iter = block.PrependNewInst(insertion_point, op, {Value(args)...});
|
||||
insertion_point = std::next(block.instructions.begin(), offset + 1);
|
||||
return T(Value(&*iter));
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
#include <mcl/container/intrusive_list.hpp>
|
||||
#include "dynarmic/common/common_types.h"
|
||||
|
||||
#include "dynarmic/ir/value.h"
|
||||
#include "dynarmic/ir/opcodes.h"
|
||||
|
||||
|
|
@ -25,8 +23,7 @@ constexpr size_t max_arg_count = 4;
|
|||
|
||||
/// A representation of a microinstruction. A single ARM/Thumb instruction may be
|
||||
/// converted into zero or more microinstructions.
|
||||
//class Inst final {
|
||||
class Inst final : public mcl::intrusive_list_node<Inst> {
|
||||
class Inst final {
|
||||
public:
|
||||
explicit Inst(Opcode op) : op(op) {}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,12 +86,10 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
|||
}
|
||||
|
||||
static void FlagsPass(IR::Block& block) {
|
||||
using Iterator = typename std::reverse_iterator<IR::Block::iterator>;
|
||||
|
||||
struct FlagInfo {
|
||||
bool set_not_required = false;
|
||||
bool has_value_request = false;
|
||||
Iterator value_request = {};
|
||||
IR::Block::reverse_iterator value_request = {};
|
||||
};
|
||||
struct ValuelessFlagInfo {
|
||||
bool set_not_required = false;
|
||||
|
|
@ -102,7 +100,7 @@ static void FlagsPass(IR::Block& block) {
|
|||
FlagInfo c_flag;
|
||||
FlagInfo ge;
|
||||
|
||||
auto do_set = [&](FlagInfo& info, IR::Value value, Iterator inst) {
|
||||
auto do_set = [&](FlagInfo& info, IR::Value value, IR::Block::reverse_iterator inst) {
|
||||
if (info.has_value_request) {
|
||||
info.value_request->ReplaceUsesWith(value);
|
||||
}
|
||||
|
|
@ -114,14 +112,14 @@ static void FlagsPass(IR::Block& block) {
|
|||
info.set_not_required = true;
|
||||
};
|
||||
|
||||
auto do_set_valueless = [&](ValuelessFlagInfo& info, Iterator inst) {
|
||||
auto do_set_valueless = [](ValuelessFlagInfo& info, IR::Block::reverse_iterator inst) {
|
||||
if (info.set_not_required) {
|
||||
inst->Invalidate();
|
||||
}
|
||||
info.set_not_required = true;
|
||||
};
|
||||
|
||||
auto do_get = [](FlagInfo& info, Iterator inst) {
|
||||
auto do_get = [](FlagInfo& info, IR::Block::reverse_iterator inst) {
|
||||
if (info.has_value_request) {
|
||||
info.value_request->ReplaceUsesWith(IR::Value{&*inst});
|
||||
}
|
||||
|
|
@ -129,7 +127,7 @@ static void FlagsPass(IR::Block& block) {
|
|||
info.value_request = inst;
|
||||
};
|
||||
|
||||
A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}};
|
||||
A32::IREmitter ir{block, A32::LocationDescriptor{block.location}, {}};
|
||||
|
||||
for (auto inst = block.instructions.rbegin(); inst != block.instructions.rend(); ++inst) {
|
||||
auto const opcode = inst->GetOpcode();
|
||||
|
|
@ -316,7 +314,7 @@ static void RegisterPass(IR::Block& block) {
|
|||
};
|
||||
|
||||
// Location and version don't matter here.
|
||||
A32::IREmitter ir{block, A32::LocationDescriptor{block.Location()}, {}};
|
||||
A32::IREmitter ir{block, A32::LocationDescriptor{block.location}, {}};
|
||||
|
||||
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
|
||||
auto const opcode = inst->GetOpcode();
|
||||
|
|
@ -448,7 +446,8 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf)
|
|||
return;
|
||||
}
|
||||
|
||||
for (auto& inst : block.instructions) {
|
||||
for (auto it = block.instructions.begin(); it != block.instructions.end(); it++) {
|
||||
auto& inst = *it;
|
||||
if (inst.GetOpcode() != IR::Opcode::A64DataCacheOperationRaised) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -457,7 +456,7 @@ static void A64CallbackConfigPass(IR::Block& block, const A64::UserConfig& conf)
|
|||
if (op == A64::DataCacheOperation::ZeroByVA) {
|
||||
A64::IREmitter ir{block};
|
||||
ir.current_location = A64::LocationDescriptor{IR::LocationDescriptor{inst.GetArg(0).GetU64()}};
|
||||
ir.SetInsertionPointBefore(&inst);
|
||||
ir.SetInsertionPointBefore(it);
|
||||
|
||||
size_t bytes = 4 << static_cast<size_t>(conf.dczid_el0 & 0b1111);
|
||||
IR::U64 addr{inst.GetArg(2)};
|
||||
|
|
@ -522,7 +521,7 @@ static void A64GetSetElimination(IR::Block& block) {
|
|||
const auto do_set = [&block](RegisterInfo& info, IR::Value value, Iterator set_inst, TrackingType tracking_type) {
|
||||
if (info.set_instruction_present) {
|
||||
info.last_set_instruction->Invalidate();
|
||||
block.Instructions().erase(info.last_set_instruction);
|
||||
block.instructions.erase(info.last_set_instruction);
|
||||
}
|
||||
info.register_value = value;
|
||||
info.tracking_type = tracking_type;
|
||||
|
|
@ -541,7 +540,7 @@ static void A64GetSetElimination(IR::Block& block) {
|
|||
ReplaceUsesWith(*get_inst, true, u32(info.register_value.GetImmediateAsU64()));
|
||||
} else {
|
||||
A64::IREmitter ir{block};
|
||||
ir.SetInsertionPointBefore(&*get_inst);
|
||||
ir.SetInsertionPointBefore(get_inst);
|
||||
get_inst->ReplaceUsesWith(ir.LeastSignificantWord(IR::U64{info.register_value}));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1210,7 +1209,7 @@ static void IdentityRemovalPass(IR::Block& block) {
|
|||
}
|
||||
if (it->GetOpcode() == IR::Opcode::Identity || it->GetOpcode() == IR::Opcode::Void) {
|
||||
to_invalidate.push_back(&*it);
|
||||
it = block.Instructions().erase(it);
|
||||
it = block.instructions.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
|
|
@ -1370,9 +1369,9 @@ static void PolyfillPass(IR::Block& block, const PolyfillOptions& polyfill) {
|
|||
|
||||
IR::IREmitter ir{block};
|
||||
|
||||
for (auto& inst : block.instructions) {
|
||||
ir.SetInsertionPointBefore(&inst);
|
||||
|
||||
for (auto it = block.instructions.begin(); it != block.instructions.end(); it++) {
|
||||
auto& inst = *it;
|
||||
ir.SetInsertionPointBefore(it);
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::SHA256MessageSchedule0:
|
||||
if (polyfill.sha256) {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A
|
|||
return false;
|
||||
}
|
||||
|
||||
if (AnyLocationDescriptorForTerminalHas(block.GetTerminal(), [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) {
|
||||
if (AnyLocationDescriptorForTerminalHas(block.terminal, [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn<Th
|
|||
printf("\n\nIR:\n%s", IR::DumpBlock(ir_block).c_str());
|
||||
printf("\n\nx86_64:\n");
|
||||
printf("%s", jit.Disassemble().c_str());
|
||||
num_insts += ir_block.CycleCount();
|
||||
num_insts += ir_block.cycle_count;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue