bool-ifying xe::cpu
This commit is contained in:
parent
a38b05db24
commit
ade5388728
|
@ -17,7 +17,7 @@ Assembler::Assembler(Backend* backend) : backend_(backend) {}
|
||||||
|
|
||||||
Assembler::~Assembler() { Reset(); }
|
Assembler::~Assembler() { Reset(); }
|
||||||
|
|
||||||
int Assembler::Initialize() { return 0; }
|
bool Assembler::Initialize() { return true; }
|
||||||
|
|
||||||
void Assembler::Reset() {}
|
void Assembler::Reset() {}
|
||||||
|
|
||||||
|
|
|
@ -34,14 +34,14 @@ class Assembler {
|
||||||
Assembler(Backend* backend);
|
Assembler(Backend* backend);
|
||||||
virtual ~Assembler();
|
virtual ~Assembler();
|
||||||
|
|
||||||
virtual int Initialize();
|
virtual bool Initialize();
|
||||||
|
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
|
||||||
virtual int Assemble(FunctionInfo* symbol_info, hir::HIRBuilder* builder,
|
virtual bool Assemble(FunctionInfo* symbol_info, hir::HIRBuilder* builder,
|
||||||
uint32_t debug_info_flags,
|
uint32_t debug_info_flags,
|
||||||
std::unique_ptr<DebugInfo> debug_info,
|
std::unique_ptr<DebugInfo> debug_info,
|
||||||
uint32_t trace_flags, Function** out_function) = 0;
|
uint32_t trace_flags, Function** out_function) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Backend* backend_;
|
Backend* backend_;
|
||||||
|
|
|
@ -19,7 +19,7 @@ Backend::Backend(Processor* processor) : processor_(processor) {
|
||||||
|
|
||||||
Backend::~Backend() = default;
|
Backend::~Backend() = default;
|
||||||
|
|
||||||
int Backend::Initialize() { return 0; }
|
bool Backend::Initialize() { return true; }
|
||||||
|
|
||||||
void* Backend::AllocThreadData() { return nullptr; }
|
void* Backend::AllocThreadData() { return nullptr; }
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Backend {
|
||||||
Processor* processor() const { return processor_; }
|
Processor* processor() const { return processor_; }
|
||||||
const MachineInfo* machine_info() const { return &machine_info_; }
|
const MachineInfo* machine_info() const { return &machine_info_; }
|
||||||
|
|
||||||
virtual int Initialize();
|
virtual bool Initialize();
|
||||||
|
|
||||||
virtual void* AllocThreadData();
|
virtual void* AllocThreadData();
|
||||||
virtual void FreeThreadData(void* thread_data);
|
virtual void FreeThreadData(void* thread_data);
|
||||||
|
|
|
@ -41,16 +41,15 @@ X64Assembler::~X64Assembler() {
|
||||||
allocator_.reset();
|
allocator_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int X64Assembler::Initialize() {
|
bool X64Assembler::Initialize() {
|
||||||
int result = Assembler::Initialize();
|
if (!Assembler::Initialize()) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator_.reset(new XbyakAllocator());
|
allocator_.reset(new XbyakAllocator());
|
||||||
emitter_.reset(new X64Emitter(x64_backend_, allocator_.get()));
|
emitter_.reset(new X64Emitter(x64_backend_, allocator_.get()));
|
||||||
|
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X64Assembler::Reset() {
|
void X64Assembler::Reset() {
|
||||||
|
@ -58,10 +57,10 @@ void X64Assembler::Reset() {
|
||||||
Assembler::Reset();
|
Assembler::Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
|
bool X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
|
||||||
uint32_t debug_info_flags,
|
uint32_t debug_info_flags,
|
||||||
std::unique_ptr<DebugInfo> debug_info,
|
std::unique_ptr<DebugInfo> debug_info,
|
||||||
uint32_t trace_flags, Function** out_function) {
|
uint32_t trace_flags, Function** out_function) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
// Reset when we leave.
|
// Reset when we leave.
|
||||||
|
@ -70,10 +69,9 @@ int X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
|
||||||
// Lower HIR -> x64.
|
// Lower HIR -> x64.
|
||||||
void* machine_code = 0;
|
void* machine_code = 0;
|
||||||
size_t code_size = 0;
|
size_t code_size = 0;
|
||||||
int result = emitter_->Emit(builder, debug_info_flags, debug_info.get(),
|
if (!emitter_->Emit(builder, debug_info_flags, debug_info.get(), trace_flags,
|
||||||
trace_flags, machine_code, code_size);
|
machine_code, code_size)) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash generated machine code.
|
// Stash generated machine code.
|
||||||
|
@ -91,7 +89,7 @@ int X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
|
||||||
*out_function = fn;
|
*out_function = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X64Assembler::DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
void X64Assembler::DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
||||||
|
|
|
@ -29,13 +29,14 @@ class X64Assembler : public Assembler {
|
||||||
X64Assembler(X64Backend* backend);
|
X64Assembler(X64Backend* backend);
|
||||||
~X64Assembler() override;
|
~X64Assembler() override;
|
||||||
|
|
||||||
int Initialize() override;
|
bool Initialize() override;
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
|
|
||||||
int Assemble(FunctionInfo* symbol_info, hir::HIRBuilder* builder,
|
bool Assemble(FunctionInfo* symbol_info, hir::HIRBuilder* builder,
|
||||||
uint32_t debug_info_flags, std::unique_ptr<DebugInfo> debug_info,
|
uint32_t debug_info_flags,
|
||||||
uint32_t trace_flags, Function** out_function) override;
|
std::unique_ptr<DebugInfo> debug_info, uint32_t trace_flags,
|
||||||
|
Function** out_function) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
void DumpMachineCode(DebugInfo* debug_info, void* machine_code,
|
||||||
|
|
|
@ -24,10 +24,9 @@ X64Backend::X64Backend(Processor* processor)
|
||||||
|
|
||||||
X64Backend::~X64Backend() { delete code_cache_; }
|
X64Backend::~X64Backend() { delete code_cache_; }
|
||||||
|
|
||||||
int X64Backend::Initialize() {
|
bool X64Backend::Initialize() {
|
||||||
int result = Backend::Initialize();
|
if (!Backend::Initialize()) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterSequences();
|
RegisterSequences();
|
||||||
|
@ -42,9 +41,8 @@ int X64Backend::Initialize() {
|
||||||
};
|
};
|
||||||
|
|
||||||
code_cache_ = new X64CodeCache();
|
code_cache_ = new X64CodeCache();
|
||||||
result = code_cache_->Initialize();
|
if (!code_cache_->Initialize()) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate thunks used to transition between jitted code and host code.
|
// Generate thunks used to transition between jitted code and host code.
|
||||||
|
@ -53,7 +51,7 @@ int X64Backend::Initialize() {
|
||||||
host_to_guest_thunk_ = thunk_emitter->EmitHostToGuestThunk();
|
host_to_guest_thunk_ = thunk_emitter->EmitHostToGuestThunk();
|
||||||
guest_to_host_thunk_ = thunk_emitter->EmitGuestToHostThunk();
|
guest_to_host_thunk_ = thunk_emitter->EmitGuestToHostThunk();
|
||||||
|
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Assembler> X64Backend::CreateAssembler() {
|
std::unique_ptr<Assembler> X64Backend::CreateAssembler() {
|
||||||
|
|
|
@ -33,7 +33,7 @@ class X64Backend : public Backend {
|
||||||
HostToGuestThunk host_to_guest_thunk() const { return host_to_guest_thunk_; }
|
HostToGuestThunk host_to_guest_thunk() const { return host_to_guest_thunk_; }
|
||||||
GuestToHostThunk guest_to_host_thunk() const { return guest_to_host_thunk_; }
|
GuestToHostThunk guest_to_host_thunk() const { return guest_to_host_thunk_; }
|
||||||
|
|
||||||
int Initialize() override;
|
bool Initialize() override;
|
||||||
|
|
||||||
std::unique_ptr<Assembler> CreateAssembler() override;
|
std::unique_ptr<Assembler> CreateAssembler() override;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class X64CodeCache {
|
||||||
X64CodeCache(size_t chunk_size = DEFAULT_CHUNK_SIZE);
|
X64CodeCache(size_t chunk_size = DEFAULT_CHUNK_SIZE);
|
||||||
virtual ~X64CodeCache();
|
virtual ~X64CodeCache();
|
||||||
|
|
||||||
int Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
// TODO(benvanik): ELF serialization/etc
|
// TODO(benvanik): ELF serialization/etc
|
||||||
// TODO(benvanik): keep track of code blocks
|
// TODO(benvanik): keep track of code blocks
|
||||||
|
|
|
@ -57,7 +57,7 @@ X64CodeCache::~X64CodeCache() {
|
||||||
head_chunk_ = NULL;
|
head_chunk_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int X64CodeCache::Initialize() { return 0; }
|
bool X64CodeCache::Initialize() { return true; }
|
||||||
|
|
||||||
void* X64CodeCache::PlaceCode(void* machine_code, size_t code_size,
|
void* X64CodeCache::PlaceCode(void* machine_code, size_t code_size,
|
||||||
size_t stack_size) {
|
size_t stack_size) {
|
||||||
|
|
|
@ -70,13 +70,11 @@ X64Emitter::X64Emitter(X64Backend* backend, XbyakAllocator* allocator)
|
||||||
trace_flags_(0),
|
trace_flags_(0),
|
||||||
cpu_() {}
|
cpu_() {}
|
||||||
|
|
||||||
X64Emitter::~X64Emitter() {}
|
X64Emitter::~X64Emitter() = default;
|
||||||
|
|
||||||
int X64Emitter::Initialize() { return 0; }
|
bool X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
|
||||||
|
DebugInfo* debug_info, uint32_t trace_flags,
|
||||||
int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
|
void*& out_code_address, size_t& out_code_size) {
|
||||||
DebugInfo* debug_info, uint32_t trace_flags,
|
|
||||||
void*& out_code_address, size_t& out_code_size) {
|
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
// Reset.
|
// Reset.
|
||||||
|
@ -88,9 +86,8 @@ int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
|
||||||
|
|
||||||
// Fill the generator with code.
|
// Fill the generator with code.
|
||||||
size_t stack_size = 0;
|
size_t stack_size = 0;
|
||||||
int result = Emit(builder, stack_size);
|
if (!Emit(builder, stack_size)) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the final code to the cache and relocate it.
|
// Copy the final code to the cache and relocate it.
|
||||||
|
@ -103,7 +100,7 @@ int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
|
||||||
source_map_count_, (SourceMapEntry*)source_map_arena_.CloneContents());
|
source_map_count_, (SourceMapEntry*)source_map_arena_.CloneContents());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* X64Emitter::Emplace(size_t stack_size) {
|
void* X64Emitter::Emplace(size_t stack_size) {
|
||||||
|
@ -120,7 +117,7 @@ void* X64Emitter::Emplace(size_t stack_size) {
|
||||||
return new_address;
|
return new_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
|
bool X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
|
||||||
// Calculate stack size. We need to align things to their natural sizes.
|
// Calculate stack size. We need to align things to their natural sizes.
|
||||||
// This could be much better (sort by type/etc).
|
// This could be much better (sort by type/etc).
|
||||||
auto locals = builder->locals();
|
auto locals = builder->locals();
|
||||||
|
@ -204,7 +201,7 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
|
||||||
nop();
|
nop();
|
||||||
#endif // XE_DEBUG
|
#endif // XE_DEBUG
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void X64Emitter::MarkSourceOffset(const Instr* i) {
|
void X64Emitter::MarkSourceOffset(const Instr* i) {
|
||||||
|
|
|
@ -105,11 +105,9 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
X64Backend* backend() const { return backend_; }
|
X64Backend* backend() const { return backend_; }
|
||||||
const Xbyak::util::Cpu* cpu() const { return &cpu_; }
|
const Xbyak::util::Cpu* cpu() const { return &cpu_; }
|
||||||
|
|
||||||
int Initialize();
|
bool Emit(hir::HIRBuilder* builder, uint32_t debug_info_flags,
|
||||||
|
DebugInfo* debug_info, uint32_t trace_flags,
|
||||||
int Emit(hir::HIRBuilder* builder, uint32_t debug_info_flags,
|
void*& out_code_address, size_t& out_code_size);
|
||||||
DebugInfo* debug_info, uint32_t trace_flags, void*& out_code_address,
|
|
||||||
size_t& out_code_size);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Reserved: rsp
|
// Reserved: rsp
|
||||||
|
@ -182,7 +180,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void* Emplace(size_t stack_size);
|
void* Emplace(size_t stack_size);
|
||||||
int Emit(hir::HIRBuilder* builder, size_t& out_stack_size);
|
bool Emit(hir::HIRBuilder* builder, size_t& out_stack_size);
|
||||||
void EmitGetCurrentThreadId();
|
void EmitGetCurrentThreadId();
|
||||||
void EmitTraceUserCallReturn();
|
void EmitTraceUserCallReturn();
|
||||||
|
|
||||||
|
|
|
@ -30,19 +30,21 @@ void X64Function::Setup(void* machine_code, size_t code_size) {
|
||||||
code_size_ = code_size;
|
code_size_ = code_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int X64Function::AddBreakpointImpl(debug::Breakpoint* breakpoint) { return 0; }
|
bool X64Function::AddBreakpointImpl(debug::Breakpoint* breakpoint) {
|
||||||
|
return false;
|
||||||
int X64Function::RemoveBreakpointImpl(debug::Breakpoint* breakpoint) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int X64Function::CallImpl(ThreadState* thread_state, uint32_t return_address) {
|
bool X64Function::RemoveBreakpointImpl(debug::Breakpoint* breakpoint) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool X64Function::CallImpl(ThreadState* thread_state, uint32_t return_address) {
|
||||||
auto backend =
|
auto backend =
|
||||||
reinterpret_cast<X64Backend*>(thread_state->processor()->backend());
|
reinterpret_cast<X64Backend*>(thread_state->processor()->backend());
|
||||||
auto thunk = backend->host_to_guest_thunk();
|
auto thunk = backend->host_to_guest_thunk();
|
||||||
thunk(machine_code_, thread_state->context(),
|
thunk(machine_code_, thread_state->context(),
|
||||||
reinterpret_cast<void*>(uintptr_t(return_address)));
|
reinterpret_cast<void*>(uintptr_t(return_address)));
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace x64
|
} // namespace x64
|
||||||
|
|
|
@ -30,9 +30,9 @@ class X64Function : public Function {
|
||||||
void Setup(void* machine_code, size_t code_size);
|
void Setup(void* machine_code, size_t code_size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int AddBreakpointImpl(debug::Breakpoint* breakpoint);
|
virtual bool AddBreakpointImpl(debug::Breakpoint* breakpoint);
|
||||||
virtual int RemoveBreakpointImpl(debug::Breakpoint* breakpoint);
|
virtual bool RemoveBreakpointImpl(debug::Breakpoint* breakpoint);
|
||||||
virtual int CallImpl(ThreadState* thread_state, uint32_t return_address);
|
virtual bool CallImpl(ThreadState* thread_state, uint32_t return_address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* machine_code_;
|
void* machine_code_;
|
||||||
|
|
|
@ -27,18 +27,18 @@ void Compiler::AddPass(std::unique_ptr<CompilerPass> pass) {
|
||||||
|
|
||||||
void Compiler::Reset() {}
|
void Compiler::Reset() {}
|
||||||
|
|
||||||
int Compiler::Compile(xe::cpu::hir::HIRBuilder* builder) {
|
bool Compiler::Compile(xe::cpu::hir::HIRBuilder* builder) {
|
||||||
// TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they
|
// TODO(benvanik): sophisticated stuff. Run passes in parallel, run until they
|
||||||
// stop changing things, etc.
|
// stop changing things, etc.
|
||||||
for (size_t i = 0; i < passes_.size(); ++i) {
|
for (size_t i = 0; i < passes_.size(); ++i) {
|
||||||
auto& pass = passes_[i];
|
auto& pass = passes_[i];
|
||||||
scratch_arena_.Reset();
|
scratch_arena_.Reset();
|
||||||
if (pass->Run(builder)) {
|
if (!pass->Run(builder)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace compiler
|
} // namespace compiler
|
||||||
|
|
|
@ -40,7 +40,7 @@ class Compiler {
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
int Compile(hir::HIRBuilder* builder);
|
bool Compile(hir::HIRBuilder* builder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Processor* processor_;
|
Processor* processor_;
|
||||||
|
|
|
@ -19,10 +19,10 @@ CompilerPass::CompilerPass() : processor_(nullptr), compiler_(nullptr) {}
|
||||||
|
|
||||||
CompilerPass::~CompilerPass() = default;
|
CompilerPass::~CompilerPass() = default;
|
||||||
|
|
||||||
int CompilerPass::Initialize(Compiler* compiler) {
|
bool CompilerPass::Initialize(Compiler* compiler) {
|
||||||
processor_ = compiler->processor();
|
processor_ = compiler->processor();
|
||||||
compiler_ = compiler;
|
compiler_ = compiler;
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arena* CompilerPass::scratch_arena() const {
|
Arena* CompilerPass::scratch_arena() const {
|
||||||
|
|
|
@ -30,9 +30,9 @@ class CompilerPass {
|
||||||
CompilerPass();
|
CompilerPass();
|
||||||
virtual ~CompilerPass();
|
virtual ~CompilerPass();
|
||||||
|
|
||||||
virtual int Initialize(Compiler* compiler);
|
virtual bool Initialize(Compiler* compiler);
|
||||||
|
|
||||||
virtual int Run(hir::HIRBuilder* builder) = 0;
|
virtual bool Run(hir::HIRBuilder* builder) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Arena* scratch_arena() const;
|
Arena* scratch_arena() const;
|
||||||
|
|
|
@ -30,7 +30,7 @@ ConstantPropagationPass::ConstantPropagationPass() : CompilerPass() {}
|
||||||
|
|
||||||
ConstantPropagationPass::~ConstantPropagationPass() {}
|
ConstantPropagationPass::~ConstantPropagationPass() {}
|
||||||
|
|
||||||
int ConstantPropagationPass::Run(HIRBuilder* builder) {
|
bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
// Once ContextPromotion has run there will likely be a whole slew of
|
// Once ContextPromotion has run there will likely be a whole slew of
|
||||||
// constants that can be pushed through the function.
|
// constants that can be pushed through the function.
|
||||||
// Example:
|
// Example:
|
||||||
|
@ -98,7 +98,7 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
case OPCODE_CALL_INDIRECT:
|
case OPCODE_CALL_INDIRECT:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
if (processor_->LookupFunctionInfo(
|
if (!processor_->LookupFunctionInfo(
|
||||||
(uint32_t)i->src1.value->constant.i32, &symbol_info)) {
|
(uint32_t)i->src1.value->constant.i32, &symbol_info)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -468,7 +468,7 @@ int ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstantPropagationPass::PropagateCarry(Value* v, bool did_carry) {
|
void ConstantPropagationPass::PropagateCarry(Value* v, bool did_carry) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ConstantPropagationPass : public CompilerPass {
|
||||||
ConstantPropagationPass();
|
ConstantPropagationPass();
|
||||||
~ConstantPropagationPass() override;
|
~ConstantPropagationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PropagateCarry(hir::Value* v, bool did_carry);
|
void PropagateCarry(hir::Value* v, bool did_carry);
|
||||||
|
|
|
@ -36,9 +36,9 @@ ContextPromotionPass::ContextPromotionPass() : CompilerPass() {}
|
||||||
|
|
||||||
ContextPromotionPass::~ContextPromotionPass() {}
|
ContextPromotionPass::~ContextPromotionPass() {}
|
||||||
|
|
||||||
int ContextPromotionPass::Initialize(Compiler* compiler) {
|
bool ContextPromotionPass::Initialize(Compiler* compiler) {
|
||||||
if (CompilerPass::Initialize(compiler)) {
|
if (!CompilerPass::Initialize(compiler)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a terrible implementation.
|
// This is a terrible implementation.
|
||||||
|
@ -46,10 +46,10 @@ int ContextPromotionPass::Initialize(Compiler* compiler) {
|
||||||
context_values_.resize(context_info->size());
|
context_values_.resize(context_info->size());
|
||||||
context_validity_.resize(static_cast<uint32_t>(context_info->size()));
|
context_validity_.resize(static_cast<uint32_t>(context_info->size()));
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ContextPromotionPass::Run(HIRBuilder* builder) {
|
bool ContextPromotionPass::Run(HIRBuilder* builder) {
|
||||||
// Like mem2reg, but because context memory is unaliasable it's easier to
|
// Like mem2reg, but because context memory is unaliasable it's easier to
|
||||||
// check and convert LoadContext/StoreContext into value operations.
|
// check and convert LoadContext/StoreContext into value operations.
|
||||||
// Example of load->value promotion:
|
// Example of load->value promotion:
|
||||||
|
@ -82,7 +82,7 @@ int ContextPromotionPass::Run(HIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextPromotionPass::PromoteBlock(Block* block) {
|
void ContextPromotionPass::PromoteBlock(Block* block) {
|
||||||
|
|
|
@ -34,9 +34,9 @@ class ContextPromotionPass : public CompilerPass {
|
||||||
ContextPromotionPass();
|
ContextPromotionPass();
|
||||||
virtual ~ContextPromotionPass() override;
|
virtual ~ContextPromotionPass() override;
|
||||||
|
|
||||||
int Initialize(Compiler* compiler) override;
|
bool Initialize(Compiler* compiler) override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PromoteBlock(hir::Block* block);
|
void PromoteBlock(hir::Block* block);
|
||||||
|
|
|
@ -29,7 +29,7 @@ ControlFlowAnalysisPass::ControlFlowAnalysisPass() : CompilerPass() {}
|
||||||
|
|
||||||
ControlFlowAnalysisPass::~ControlFlowAnalysisPass() {}
|
ControlFlowAnalysisPass::~ControlFlowAnalysisPass() {}
|
||||||
|
|
||||||
int ControlFlowAnalysisPass::Run(HIRBuilder* builder) {
|
bool ControlFlowAnalysisPass::Run(HIRBuilder* builder) {
|
||||||
// Reset edges for all blocks. Needed to be re-runnable.
|
// Reset edges for all blocks. Needed to be re-runnable.
|
||||||
// Note that this wastes a bunch of arena memory, so we shouldn't
|
// Note that this wastes a bunch of arena memory, so we shouldn't
|
||||||
// re-run too often.
|
// re-run too often.
|
||||||
|
@ -71,7 +71,7 @@ int ControlFlowAnalysisPass::Run(HIRBuilder* builder) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ControlFlowAnalysisPass : public CompilerPass {
|
||||||
ControlFlowAnalysisPass();
|
ControlFlowAnalysisPass();
|
||||||
~ControlFlowAnalysisPass() override;
|
~ControlFlowAnalysisPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,7 @@ ControlFlowSimplificationPass::ControlFlowSimplificationPass()
|
||||||
|
|
||||||
ControlFlowSimplificationPass::~ControlFlowSimplificationPass() {}
|
ControlFlowSimplificationPass::~ControlFlowSimplificationPass() {}
|
||||||
|
|
||||||
int ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
|
bool ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
|
||||||
// Walk backwards and merge blocks if possible.
|
// Walk backwards and merge blocks if possible.
|
||||||
bool merged_any = false;
|
bool merged_any = false;
|
||||||
auto block = builder->last_block();
|
auto block = builder->last_block();
|
||||||
|
@ -52,7 +52,7 @@ int ControlFlowSimplificationPass::Run(HIRBuilder* builder) {
|
||||||
block = prev_block;
|
block = prev_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ControlFlowSimplificationPass : public CompilerPass {
|
||||||
ControlFlowSimplificationPass();
|
ControlFlowSimplificationPass();
|
||||||
~ControlFlowSimplificationPass() override;
|
~ControlFlowSimplificationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,14 +42,14 @@ DataFlowAnalysisPass::DataFlowAnalysisPass() : CompilerPass() {}
|
||||||
|
|
||||||
DataFlowAnalysisPass::~DataFlowAnalysisPass() {}
|
DataFlowAnalysisPass::~DataFlowAnalysisPass() {}
|
||||||
|
|
||||||
int DataFlowAnalysisPass::Run(HIRBuilder* builder) {
|
bool DataFlowAnalysisPass::Run(HIRBuilder* builder) {
|
||||||
// Linearize blocks so that we can detect cycles and propagate dependencies.
|
// Linearize blocks so that we can detect cycles and propagate dependencies.
|
||||||
uint32_t block_count = LinearizeBlocks(builder);
|
uint32_t block_count = LinearizeBlocks(builder);
|
||||||
|
|
||||||
// Analyze value flow and add locals as needed.
|
// Analyze value flow and add locals as needed.
|
||||||
AnalyzeFlow(builder, block_count);
|
AnalyzeFlow(builder, block_count);
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t DataFlowAnalysisPass::LinearizeBlocks(HIRBuilder* builder) {
|
uint32_t DataFlowAnalysisPass::LinearizeBlocks(HIRBuilder* builder) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class DataFlowAnalysisPass : public CompilerPass {
|
||||||
DataFlowAnalysisPass();
|
DataFlowAnalysisPass();
|
||||||
~DataFlowAnalysisPass() override;
|
~DataFlowAnalysisPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t LinearizeBlocks(hir::HIRBuilder* builder);
|
uint32_t LinearizeBlocks(hir::HIRBuilder* builder);
|
||||||
|
|
|
@ -27,7 +27,7 @@ DeadCodeEliminationPass::DeadCodeEliminationPass() : CompilerPass() {}
|
||||||
|
|
||||||
DeadCodeEliminationPass::~DeadCodeEliminationPass() {}
|
DeadCodeEliminationPass::~DeadCodeEliminationPass() {}
|
||||||
|
|
||||||
int DeadCodeEliminationPass::Run(HIRBuilder* builder) {
|
bool DeadCodeEliminationPass::Run(HIRBuilder* builder) {
|
||||||
// ContextPromotion/DSE will likely leave around a lot of dead statements.
|
// ContextPromotion/DSE will likely leave around a lot of dead statements.
|
||||||
// Code generated for comparison/testing produces many unused statements and
|
// Code generated for comparison/testing produces many unused statements and
|
||||||
// with proper use analysis it should be possible to remove most of them:
|
// with proper use analysis it should be possible to remove most of them:
|
||||||
|
@ -143,7 +143,7 @@ int DeadCodeEliminationPass::Run(HIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeadCodeEliminationPass::MakeNopRecursive(Instr* i) {
|
void DeadCodeEliminationPass::MakeNopRecursive(Instr* i) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class DeadCodeEliminationPass : public CompilerPass {
|
||||||
DeadCodeEliminationPass();
|
DeadCodeEliminationPass();
|
||||||
~DeadCodeEliminationPass() override;
|
~DeadCodeEliminationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MakeNopRecursive(hir::Instr* i);
|
void MakeNopRecursive(hir::Instr* i);
|
||||||
|
|
|
@ -28,7 +28,7 @@ FinalizationPass::FinalizationPass() : CompilerPass() {}
|
||||||
|
|
||||||
FinalizationPass::~FinalizationPass() {}
|
FinalizationPass::~FinalizationPass() {}
|
||||||
|
|
||||||
int FinalizationPass::Run(HIRBuilder* builder) {
|
bool FinalizationPass::Run(HIRBuilder* builder) {
|
||||||
// Process the HIR and prepare it for lowering.
|
// Process the HIR and prepare it for lowering.
|
||||||
// After this is done the HIR should be ready for emitting.
|
// After this is done the HIR should be ready for emitting.
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ int FinalizationPass::Run(HIRBuilder* builder) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
|
@ -22,7 +22,7 @@ class FinalizationPass : public CompilerPass {
|
||||||
FinalizationPass();
|
FinalizationPass();
|
||||||
~FinalizationPass() override;
|
~FinalizationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,7 +69,7 @@ RegisterAllocationPass::~RegisterAllocationPass() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int RegisterAllocationPass::Run(HIRBuilder* builder) {
|
bool RegisterAllocationPass::Run(HIRBuilder* builder) {
|
||||||
// Simple per-block allocator that operates on SSA form.
|
// Simple per-block allocator that operates on SSA form.
|
||||||
// Registers do not move across blocks, though this could be
|
// Registers do not move across blocks, though this could be
|
||||||
// optimized with some intra-block analysis (dominators/etc).
|
// optimized with some intra-block analysis (dominators/etc).
|
||||||
|
@ -151,7 +151,7 @@ int RegisterAllocationPass::Run(HIRBuilder* builder) {
|
||||||
// Unable to spill anything - this shouldn't happen.
|
// Unable to spill anything - this shouldn't happen.
|
||||||
XELOGE("Unable to spill any registers");
|
XELOGE("Unable to spill any registers");
|
||||||
assert_always();
|
assert_always();
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demand allocation.
|
// Demand allocation.
|
||||||
|
@ -159,7 +159,7 @@ int RegisterAllocationPass::Run(HIRBuilder* builder) {
|
||||||
// Boned.
|
// Boned.
|
||||||
XELOGE("Register allocation failed");
|
XELOGE("Register allocation failed");
|
||||||
assert_always();
|
assert_always();
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ int RegisterAllocationPass::Run(HIRBuilder* builder) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterAllocationPass::DumpUsage(const char* name) {
|
void RegisterAllocationPass::DumpUsage(const char* name) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ class RegisterAllocationPass : public CompilerPass {
|
||||||
RegisterAllocationPass(const backend::MachineInfo* machine_info);
|
RegisterAllocationPass(const backend::MachineInfo* machine_info);
|
||||||
~RegisterAllocationPass() override;
|
~RegisterAllocationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO(benvanik): rewrite all this set shit -- too much indirection, the
|
// TODO(benvanik): rewrite all this set shit -- too much indirection, the
|
||||||
|
|
|
@ -27,10 +27,10 @@ SimplificationPass::SimplificationPass() : CompilerPass() {}
|
||||||
|
|
||||||
SimplificationPass::~SimplificationPass() {}
|
SimplificationPass::~SimplificationPass() {}
|
||||||
|
|
||||||
int SimplificationPass::Run(HIRBuilder* builder) {
|
bool SimplificationPass::Run(HIRBuilder* builder) {
|
||||||
EliminateConversions(builder);
|
EliminateConversions(builder);
|
||||||
SimplifyAssignments(builder);
|
SimplifyAssignments(builder);
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimplificationPass::EliminateConversions(HIRBuilder* builder) {
|
void SimplificationPass::EliminateConversions(HIRBuilder* builder) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class SimplificationPass : public CompilerPass {
|
||||||
SimplificationPass();
|
SimplificationPass();
|
||||||
~SimplificationPass() override;
|
~SimplificationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EliminateConversions(hir::HIRBuilder* builder);
|
void EliminateConversions(hir::HIRBuilder* builder);
|
||||||
|
|
|
@ -33,7 +33,7 @@ ValidationPass::ValidationPass() : CompilerPass() {}
|
||||||
|
|
||||||
ValidationPass::~ValidationPass() {}
|
ValidationPass::~ValidationPass() {}
|
||||||
|
|
||||||
int ValidationPass::Run(HIRBuilder* builder) {
|
bool ValidationPass::Run(HIRBuilder* builder) {
|
||||||
#if 0
|
#if 0
|
||||||
StringBuffer str;
|
StringBuffer str;
|
||||||
builder->Dump(&str);
|
builder->Dump(&str);
|
||||||
|
@ -48,15 +48,15 @@ int ValidationPass::Run(HIRBuilder* builder) {
|
||||||
while (label) {
|
while (label) {
|
||||||
assert_true(label->block == block);
|
assert_true(label->block == block);
|
||||||
if (label->block != block) {
|
if (label->block != block) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
label = label->next;
|
label = label->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto instr = block->instr_head;
|
auto instr = block->instr_head;
|
||||||
while (instr) {
|
while (instr) {
|
||||||
if (ValidateInstruction(block, instr)) {
|
if (!ValidateInstruction(block, instr)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
instr = instr->next;
|
instr = instr->next;
|
||||||
}
|
}
|
||||||
|
@ -64,13 +64,13 @@ int ValidationPass::Run(HIRBuilder* builder) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValidationPass::ValidateInstruction(Block* block, Instr* instr) {
|
bool ValidationPass::ValidateInstruction(Block* block, Instr* instr) {
|
||||||
assert_true(instr->block == block);
|
assert_true(instr->block == block);
|
||||||
if (instr->block != block) {
|
if (instr->block != block) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instr->dest) {
|
if (instr->dest) {
|
||||||
|
@ -84,33 +84,33 @@ int ValidationPass::ValidateInstruction(Block* block, Instr* instr) {
|
||||||
|
|
||||||
uint32_t signature = instr->opcode->signature;
|
uint32_t signature = instr->opcode->signature;
|
||||||
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
if (GET_OPCODE_SIG_TYPE_SRC1(signature) == OPCODE_SIG_TYPE_V) {
|
||||||
if (ValidateValue(block, instr, instr->src1.value)) {
|
if (!ValidateValue(block, instr, instr->src1.value)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) {
|
if (GET_OPCODE_SIG_TYPE_SRC2(signature) == OPCODE_SIG_TYPE_V) {
|
||||||
if (ValidateValue(block, instr, instr->src2.value)) {
|
if (!ValidateValue(block, instr, instr->src2.value)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) {
|
if (GET_OPCODE_SIG_TYPE_SRC3(signature) == OPCODE_SIG_TYPE_V) {
|
||||||
if (ValidateValue(block, instr, instr->src3.value)) {
|
if (!ValidateValue(block, instr, instr->src3.value)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValidationPass::ValidateValue(Block* block, Instr* instr, Value* value) {
|
bool ValidationPass::ValidateValue(Block* block, Instr* instr, Value* value) {
|
||||||
// if (value->def) {
|
// if (value->def) {
|
||||||
// auto def = value->def;
|
// auto def = value->def;
|
||||||
// assert_true(def->block == block);
|
// assert_true(def->block == block);
|
||||||
// if (def->block != block) {
|
// if (def->block != block) {
|
||||||
// return 1;
|
// return false;
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
|
@ -22,11 +22,11 @@ class ValidationPass : public CompilerPass {
|
||||||
ValidationPass();
|
ValidationPass();
|
||||||
~ValidationPass() override;
|
~ValidationPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int ValidateInstruction(hir::Block* block, hir::Instr* instr);
|
bool ValidateInstruction(hir::Block* block, hir::Instr* instr);
|
||||||
int ValidateValue(hir::Block* block, hir::Instr* instr, hir::Value* value);
|
bool ValidateValue(hir::Block* block, hir::Instr* instr, hir::Value* value);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
|
@ -58,7 +58,7 @@ void ValueReductionPass::ComputeLastUse(Value* value) {
|
||||||
value->last_use = last_use ? last_use->instr : nullptr;
|
value->last_use = last_use ? last_use->instr : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValueReductionPass::Run(HIRBuilder* builder) {
|
bool ValueReductionPass::Run(HIRBuilder* builder) {
|
||||||
// Walk each block and reuse variable ordinals as much as possible.
|
// Walk each block and reuse variable ordinals as much as possible.
|
||||||
|
|
||||||
llvm::BitVector ordinals(builder->max_value_ordinal());
|
llvm::BitVector ordinals(builder->max_value_ordinal());
|
||||||
|
@ -139,7 +139,7 @@ int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace passes
|
} // namespace passes
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ValueReductionPass : public CompilerPass {
|
||||||
ValueReductionPass();
|
ValueReductionPass();
|
||||||
~ValueReductionPass() override;
|
~ValueReductionPass() override;
|
||||||
|
|
||||||
int Run(hir::HIRBuilder* builder) override;
|
bool Run(hir::HIRBuilder* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ComputeLastUse(hir::Value* value);
|
void ComputeLastUse(hir::Value* value);
|
||||||
|
|
|
@ -73,7 +73,7 @@ void HandleGlobalLock(PPCContext* ppc_state, void* arg0, void* arg1) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int PPCFrontend::Initialize() {
|
bool PPCFrontend::Initialize() {
|
||||||
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
void* arg0 = reinterpret_cast<void*>(&builtins_.global_lock);
|
||||||
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
|
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_taken);
|
||||||
builtins_.check_global_lock = processor_->DefineBuiltin(
|
builtins_.check_global_lock = processor_->DefineBuiltin(
|
||||||
|
@ -83,24 +83,25 @@ int PPCFrontend::Initialize() {
|
||||||
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
|
"HandleGlobalLock", (FunctionInfo::ExternHandler)HandleGlobalLock, arg0,
|
||||||
arg1);
|
arg1);
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PPCFrontend::DeclareFunction(FunctionInfo* symbol_info) {
|
bool PPCFrontend::DeclareFunction(FunctionInfo* symbol_info) {
|
||||||
// Could scan or something here.
|
// Could scan or something here.
|
||||||
// Could also check to see if it's a well-known function type and classify
|
// Could also check to see if it's a well-known function type and classify
|
||||||
// for later.
|
// for later.
|
||||||
// Could also kick off a precompiler, since we know it's likely the function
|
// Could also kick off a precompiler, since we know it's likely the function
|
||||||
// will be demanded soon.
|
// will be demanded soon.
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PPCFrontend::DefineFunction(FunctionInfo* symbol_info,
|
bool PPCFrontend::DefineFunction(FunctionInfo* symbol_info,
|
||||||
uint32_t debug_info_flags, uint32_t trace_flags,
|
uint32_t debug_info_flags,
|
||||||
Function** out_function) {
|
uint32_t trace_flags,
|
||||||
|
Function** out_function) {
|
||||||
PPCTranslator* translator = translator_pool_.Allocate(this);
|
PPCTranslator* translator = translator_pool_.Allocate(this);
|
||||||
int result = translator->Translate(symbol_info, debug_info_flags, trace_flags,
|
bool result = translator->Translate(symbol_info, debug_info_flags,
|
||||||
out_function);
|
trace_flags, out_function);
|
||||||
translator_pool_.Release(translator);
|
translator_pool_.Release(translator);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,16 +43,16 @@ class PPCFrontend {
|
||||||
explicit PPCFrontend(Processor* processor);
|
explicit PPCFrontend(Processor* processor);
|
||||||
~PPCFrontend();
|
~PPCFrontend();
|
||||||
|
|
||||||
int Initialize();
|
bool Initialize();
|
||||||
|
|
||||||
Processor* processor() const { return processor_; }
|
Processor* processor() const { return processor_; }
|
||||||
Memory* memory() const;
|
Memory* memory() const;
|
||||||
ContextInfo* context_info() const { return context_info_.get(); }
|
ContextInfo* context_info() const { return context_info_.get(); }
|
||||||
PPCBuiltins* builtins() { return &builtins_; }
|
PPCBuiltins* builtins() { return &builtins_; }
|
||||||
|
|
||||||
int DeclareFunction(FunctionInfo* symbol_info);
|
bool DeclareFunction(FunctionInfo* symbol_info);
|
||||||
int DefineFunction(FunctionInfo* symbol_info, uint32_t debug_info_flags,
|
bool DefineFunction(FunctionInfo* symbol_info, uint32_t debug_info_flags,
|
||||||
uint32_t trace_flags, Function** out_function);
|
uint32_t trace_flags, Function** out_function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Processor* processor_;
|
Processor* processor_;
|
||||||
|
|
|
@ -45,7 +45,7 @@ void PPCHIRBuilder::Reset() {
|
||||||
HIRBuilder::Reset();
|
HIRBuilder::Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, uint32_t flags) {
|
bool PPCHIRBuilder::Emit(FunctionInfo* symbol_info, uint32_t flags) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
Memory* memory = frontend_->memory();
|
Memory* memory = frontend_->memory();
|
||||||
|
@ -154,19 +154,19 @@ void PPCHIRBuilder::AnnotateLabel(uint32_t address, Label* label) {
|
||||||
FunctionInfo* PPCHIRBuilder::LookupFunction(uint32_t address) {
|
FunctionInfo* PPCHIRBuilder::LookupFunction(uint32_t address) {
|
||||||
Processor* processor = frontend_->processor();
|
Processor* processor = frontend_->processor();
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
if (processor->LookupFunctionInfo(address, &symbol_info)) {
|
if (!processor->LookupFunctionInfo(address, &symbol_info)) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return symbol_info;
|
return symbol_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label* PPCHIRBuilder::LookupLabel(uint32_t address) {
|
Label* PPCHIRBuilder::LookupLabel(uint32_t address) {
|
||||||
if (address < start_address_) {
|
if (address < start_address_) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
size_t offset = (address - start_address_) / 4;
|
size_t offset = (address - start_address_) / 4;
|
||||||
if (offset >= instr_count_) {
|
if (offset >= instr_count_) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Label* label = label_list_[offset];
|
Label* label = label_list_[offset];
|
||||||
if (label) {
|
if (label) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ class PPCHIRBuilder : public hir::HIRBuilder {
|
||||||
// Emit comment nodes.
|
// Emit comment nodes.
|
||||||
EMIT_DEBUG_COMMENTS = 1 << 0,
|
EMIT_DEBUG_COMMENTS = 1 << 0,
|
||||||
};
|
};
|
||||||
int Emit(FunctionInfo* symbol_info, uint32_t flags);
|
bool Emit(FunctionInfo* symbol_info, uint32_t flags);
|
||||||
|
|
||||||
FunctionInfo* symbol_info() const { return symbol_info_; }
|
FunctionInfo* symbol_info() const { return symbol_info_; }
|
||||||
FunctionInfo* LookupFunction(uint32_t address);
|
FunctionInfo* LookupFunction(uint32_t address);
|
||||||
|
|
|
@ -35,13 +35,13 @@ PPCScanner::~PPCScanner() {}
|
||||||
|
|
||||||
bool PPCScanner::IsRestGprLr(uint32_t address) {
|
bool PPCScanner::IsRestGprLr(uint32_t address) {
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
if (frontend_->processor()->LookupFunctionInfo(address, &symbol_info)) {
|
if (!frontend_->processor()->LookupFunctionInfo(address, &symbol_info)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return symbol_info->behavior() == FunctionInfo::BEHAVIOR_EPILOG_RETURN;
|
return symbol_info->behavior() == FunctionInfo::BEHAVIOR_EPILOG_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
bool PPCScanner::Scan(FunctionInfo* symbol_info, DebugInfo* debug_info) {
|
||||||
// This is a simple basic block analyizer. It walks the start address to the
|
// This is a simple basic block analyizer. It walks the start address to the
|
||||||
// end address looking for branches. Each span of instructions between
|
// end address looking for branches. Each span of instructions between
|
||||||
// branches is considered a basic block. When the last blr (that has no
|
// branches is considered a basic block. When the last blr (that has no
|
||||||
|
@ -275,7 +275,7 @@ int PPCScanner::FindExtents(FunctionInfo* symbol_info) {
|
||||||
// - record prolog/epilog lengths/stack size/etc
|
// - record prolog/epilog lengths/stack size/etc
|
||||||
|
|
||||||
LOGPPC("Finished analyzing %.8X", start_address);
|
LOGPPC("Finished analyzing %.8X", start_address);
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BlockInfo> PPCScanner::FindBlocks(FunctionInfo* symbol_info) {
|
std::vector<BlockInfo> PPCScanner::FindBlocks(FunctionInfo* symbol_info) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/cpu/debug_info.h"
|
||||||
#include "xenia/cpu/symbol_info.h"
|
#include "xenia/cpu/symbol_info.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -30,7 +31,7 @@ class PPCScanner {
|
||||||
PPCScanner(PPCFrontend* frontend);
|
PPCScanner(PPCFrontend* frontend);
|
||||||
~PPCScanner();
|
~PPCScanner();
|
||||||
|
|
||||||
int FindExtents(FunctionInfo* symbol_info);
|
bool Scan(FunctionInfo* symbol_info, DebugInfo* debug_info);
|
||||||
|
|
||||||
std::vector<BlockInfo> FindBlocks(FunctionInfo* symbol_info);
|
std::vector<BlockInfo> FindBlocks(FunctionInfo* symbol_info);
|
||||||
|
|
||||||
|
|
|
@ -86,9 +86,9 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
||||||
|
|
||||||
PPCTranslator::~PPCTranslator() = default;
|
PPCTranslator::~PPCTranslator() = default;
|
||||||
|
|
||||||
int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
bool PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||||
uint32_t debug_info_flags, uint32_t trace_flags,
|
uint32_t debug_info_flags, uint32_t trace_flags,
|
||||||
Function** out_function) {
|
Function** out_function) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
// Reset() all caching when we leave.
|
// Reset() all caching when we leave.
|
||||||
|
@ -97,18 +97,6 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||||
xe::make_reset_scope(assembler_);
|
xe::make_reset_scope(assembler_);
|
||||||
xe::make_reset_scope(&string_buffer_);
|
xe::make_reset_scope(&string_buffer_);
|
||||||
|
|
||||||
// Scan the function to find its extents. We only need to do this if we
|
|
||||||
// haven't already been provided with them from some other source.
|
|
||||||
if (!symbol_info->has_end_address()) {
|
|
||||||
// TODO(benvanik): find a way to remove the need for the scan. A fixup
|
|
||||||
// scheme acting on branches could go back and modify calls to branches
|
|
||||||
// if they are within the extents.
|
|
||||||
int result = scanner_->FindExtents(symbol_info);
|
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: we only want to do this when required, as it's expensive to build.
|
// NOTE: we only want to do this when required, as it's expensive to build.
|
||||||
if (FLAGS_always_disasm) {
|
if (FLAGS_always_disasm) {
|
||||||
debug_info_flags |= DEBUG_INFO_ALL_DISASM;
|
debug_info_flags |= DEBUG_INFO_ALL_DISASM;
|
||||||
|
@ -118,6 +106,11 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||||
debug_info.reset(new DebugInfo());
|
debug_info.reset(new DebugInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan the function to find its extents and gather debug data.
|
||||||
|
if (!scanner_->Scan(symbol_info, debug_info.get())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Stash source.
|
// Stash source.
|
||||||
if (debug_info_flags & DEBUG_INFO_SOURCE_DISASM) {
|
if (debug_info_flags & DEBUG_INFO_SOURCE_DISASM) {
|
||||||
DumpSource(symbol_info, &string_buffer_);
|
DumpSource(symbol_info, &string_buffer_);
|
||||||
|
@ -134,9 +127,8 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||||
if (debug_info) {
|
if (debug_info) {
|
||||||
emit_flags |= PPCHIRBuilder::EMIT_DEBUG_COMMENTS;
|
emit_flags |= PPCHIRBuilder::EMIT_DEBUG_COMMENTS;
|
||||||
}
|
}
|
||||||
int result = builder_->Emit(symbol_info, emit_flags);
|
if (!builder_->Emit(symbol_info, emit_flags)) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash raw HIR.
|
// Stash raw HIR.
|
||||||
|
@ -147,9 +139,8 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile/optimize/etc.
|
// Compile/optimize/etc.
|
||||||
result = compiler_->Compile(builder_.get());
|
if (!compiler_->Compile(builder_.get())) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash optimized HIR.
|
// Stash optimized HIR.
|
||||||
|
@ -160,14 +151,12 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble to backend machine code.
|
// Assemble to backend machine code.
|
||||||
result =
|
if (!assembler_->Assemble(symbol_info, builder_.get(), debug_info_flags,
|
||||||
assembler_->Assemble(symbol_info, builder_.get(), debug_info_flags,
|
std::move(debug_info), trace_flags, out_function)) {
|
||||||
std::move(debug_info), trace_flags, out_function);
|
return false;
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void PPCTranslator::DumpSource(FunctionInfo* symbol_info,
|
void PPCTranslator::DumpSource(FunctionInfo* symbol_info,
|
||||||
|
|
|
@ -30,8 +30,8 @@ class PPCTranslator {
|
||||||
PPCTranslator(PPCFrontend* frontend);
|
PPCTranslator(PPCFrontend* frontend);
|
||||||
~PPCTranslator();
|
~PPCTranslator();
|
||||||
|
|
||||||
int Translate(FunctionInfo* symbol_info, uint32_t debug_info_flags,
|
bool Translate(FunctionInfo* symbol_info, uint32_t debug_info_flags,
|
||||||
uint32_t trace_flags, Function** out_function);
|
uint32_t trace_flags, Function** out_function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DumpSource(FunctionInfo* symbol_info, StringBuffer* string_buffer);
|
void DumpSource(FunctionInfo* symbol_info, StringBuffer* string_buffer);
|
||||||
|
|
|
@ -188,7 +188,7 @@ class TestRunner {
|
||||||
bool Setup(TestSuite& suite) {
|
bool Setup(TestSuite& suite) {
|
||||||
// Load the binary module.
|
// Load the binary module.
|
||||||
auto module = std::make_unique<xe::cpu::RawModule>(processor.get());
|
auto module = std::make_unique<xe::cpu::RawModule>(processor.get());
|
||||||
if (module->LoadFile(START_ADDRESS, suite.bin_file_path)) {
|
if (!module->LoadFile(START_ADDRESS, suite.bin_file_path)) {
|
||||||
XELOGE("Unable to load test binary %ls", suite.bin_file_path.c_str());
|
XELOGE("Unable to load test binary %ls", suite.bin_file_path.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -212,9 +212,8 @@ class TestRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute test.
|
// Execute test.
|
||||||
xe::cpu::Function* fn;
|
xe::cpu::Function* fn = nullptr;
|
||||||
processor->ResolveFunction(test_case.address, &fn);
|
if (!processor->ResolveFunction(test_case.address, &fn)) {
|
||||||
if (!fn) {
|
|
||||||
XELOGE("Entry function not found");
|
XELOGE("Entry function not found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ Function::Function(FunctionInfo* symbol_info)
|
||||||
|
|
||||||
Function::~Function() = default;
|
Function::~Function() = default;
|
||||||
|
|
||||||
int Function::AddBreakpoint(Breakpoint* breakpoint) {
|
bool Function::AddBreakpoint(Breakpoint* breakpoint) {
|
||||||
std::lock_guard<std::mutex> guard(lock_);
|
std::lock_guard<std::mutex> guard(lock_);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto other : breakpoints_) {
|
for (auto other : breakpoints_) {
|
||||||
|
@ -32,25 +32,25 @@ int Function::AddBreakpoint(Breakpoint* breakpoint) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (found) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
breakpoints_.push_back(breakpoint);
|
breakpoints_.push_back(breakpoint);
|
||||||
AddBreakpointImpl(breakpoint);
|
return AddBreakpointImpl(breakpoint);
|
||||||
}
|
}
|
||||||
return found ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Function::RemoveBreakpoint(Breakpoint* breakpoint) {
|
bool Function::RemoveBreakpoint(Breakpoint* breakpoint) {
|
||||||
std::lock_guard<std::mutex> guard(lock_);
|
std::lock_guard<std::mutex> guard(lock_);
|
||||||
bool found = false;
|
|
||||||
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
||||||
if (*it == breakpoint) {
|
if (*it == breakpoint) {
|
||||||
|
if (!RemoveBreakpointImpl(breakpoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
breakpoints_.erase(it);
|
breakpoints_.erase(it);
|
||||||
RemoveBreakpointImpl(breakpoint);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found ? 0 : 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Breakpoint* Function::FindBreakpoint(uint32_t address) {
|
Breakpoint* Function::FindBreakpoint(uint32_t address) {
|
||||||
|
@ -65,7 +65,7 @@ Breakpoint* Function::FindBreakpoint(uint32_t address) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
bool Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||||
// SCOPE_profile_cpu_f("cpu");
|
// SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
ThreadState* original_thread_state = ThreadState::Get();
|
ThreadState* original_thread_state = ThreadState::Get();
|
||||||
|
@ -73,7 +73,7 @@ int Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||||
ThreadState::Bind(thread_state);
|
ThreadState::Bind(thread_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = 0;
|
bool result = true;
|
||||||
|
|
||||||
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
|
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
|
||||||
auto handler = symbol_info_->extern_handler();
|
auto handler = symbol_info_->extern_handler();
|
||||||
|
@ -84,7 +84,7 @@ int Function::Call(ThreadState* thread_state, uint32_t return_address) {
|
||||||
} else {
|
} else {
|
||||||
XELOGW("undefined extern call to %.8llX %s", symbol_info_->address(),
|
XELOGW("undefined extern call to %.8llX %s", symbol_info_->address(),
|
||||||
symbol_info_->name().c_str());
|
symbol_info_->name().c_str());
|
||||||
result = 1;
|
result = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CallImpl(thread_state, return_address);
|
CallImpl(thread_state, return_address);
|
||||||
|
|
|
@ -36,16 +36,16 @@ class Function {
|
||||||
debug_info_ = std::move(debug_info);
|
debug_info_ = std::move(debug_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddBreakpoint(debug::Breakpoint* breakpoint);
|
bool AddBreakpoint(debug::Breakpoint* breakpoint);
|
||||||
int RemoveBreakpoint(debug::Breakpoint* breakpoint);
|
bool RemoveBreakpoint(debug::Breakpoint* breakpoint);
|
||||||
|
|
||||||
int Call(ThreadState* thread_state, uint32_t return_address);
|
bool Call(ThreadState* thread_state, uint32_t return_address);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
debug::Breakpoint* FindBreakpoint(uint32_t address);
|
debug::Breakpoint* FindBreakpoint(uint32_t address);
|
||||||
virtual int AddBreakpointImpl(debug::Breakpoint* breakpoint) { return 0; }
|
virtual bool AddBreakpointImpl(debug::Breakpoint* breakpoint) { return 0; }
|
||||||
virtual int RemoveBreakpointImpl(debug::Breakpoint* breakpoint) { return 0; }
|
virtual bool RemoveBreakpointImpl(debug::Breakpoint* breakpoint) { return 0; }
|
||||||
virtual int CallImpl(ThreadState* thread_state, uint32_t return_address) = 0;
|
virtual bool CallImpl(ThreadState* thread_state, uint32_t return_address) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t address_;
|
uint32_t address_;
|
||||||
|
|
|
@ -51,7 +51,7 @@ void HIRBuilder::Reset() {
|
||||||
arena_->Reset();
|
arena_->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int HIRBuilder::Finalize() {
|
bool HIRBuilder::Finalize() {
|
||||||
// Scan blocks in order and add fallthrough branches. These are needed for
|
// Scan blocks in order and add fallthrough branches. These are needed for
|
||||||
// analysis passes to work. We may have also added blocks out of order and
|
// analysis passes to work. We may have also added blocks out of order and
|
||||||
// need to ensure they fall through in the right order.
|
// need to ensure they fall through in the right order.
|
||||||
|
@ -84,7 +84,7 @@ int HIRBuilder::Finalize() {
|
||||||
current_block_ = NULL;
|
current_block_ = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HIRBuilder::DumpValue(StringBuffer* str, Value* value) {
|
void HIRBuilder::DumpValue(StringBuffer* str, Value* value) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ class HIRBuilder {
|
||||||
virtual ~HIRBuilder();
|
virtual ~HIRBuilder();
|
||||||
|
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
virtual int Finalize();
|
virtual bool Finalize();
|
||||||
|
|
||||||
void Dump(StringBuffer* str);
|
void Dump(StringBuffer* str);
|
||||||
void AssertNoCycles();
|
void AssertNoCycles();
|
||||||
|
|
|
@ -175,7 +175,7 @@ void Module::ForEachFunction(size_t since, size_t& version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Module::ReadMap(const char* file_name) {
|
bool Module::ReadMap(const char* file_name) {
|
||||||
std::ifstream infile(file_name);
|
std::ifstream infile(file_name);
|
||||||
|
|
||||||
// Skip until ' Address'. Skip the next blank line.
|
// Skip until ' Address'. Skip the next blank line.
|
||||||
|
@ -225,7 +225,7 @@ int Module::ReadMap(const char* file_name) {
|
||||||
if (type_str == "f") {
|
if (type_str == "f") {
|
||||||
// Function.
|
// Function.
|
||||||
FunctionInfo* fn_info;
|
FunctionInfo* fn_info;
|
||||||
if (processor_->LookupFunctionInfo(this, address, &fn_info)) {
|
if (!processor_->LookupFunctionInfo(this, address, &fn_info)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Don't overwrite names we've set elsewhere.
|
// Don't overwrite names we've set elsewhere.
|
||||||
|
@ -243,7 +243,7 @@ int Module::ReadMap(const char* file_name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -49,7 +49,7 @@ class Module {
|
||||||
void ForEachFunction(size_t since, size_t& version,
|
void ForEachFunction(size_t since, size_t& version,
|
||||||
std::function<void(FunctionInfo*)> callback);
|
std::function<void(FunctionInfo*)> callback);
|
||||||
|
|
||||||
int ReadMap(const char* file_name);
|
bool ReadMap(const char* file_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SymbolInfo::Status DeclareSymbol(SymbolInfo::Type type, uint32_t address,
|
SymbolInfo::Status DeclareSymbol(SymbolInfo::Type type, uint32_t address,
|
||||||
|
|
|
@ -98,7 +98,7 @@ Processor::~Processor() {
|
||||||
backend_.reset();
|
backend_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::Setup() {
|
bool Processor::Setup() {
|
||||||
debug_info_flags_ = DEBUG_INFO_DEFAULT;
|
debug_info_flags_ = DEBUG_INFO_DEFAULT;
|
||||||
trace_flags_ = 0;
|
trace_flags_ = 0;
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ int Processor::Setup() {
|
||||||
modules_.push_back(std::move(builtin_module));
|
modules_.push_back(std::move(builtin_module));
|
||||||
|
|
||||||
if (frontend_ || backend_) {
|
if (frontend_ || backend_) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
std::unique_ptr<xe::cpu::backend::Backend> backend;
|
||||||
|
@ -136,17 +136,13 @@ int Processor::Setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!backend) {
|
if (!backend) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!backend->Initialize()) {
|
||||||
int result = backend->Initialize();
|
return false;
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
if (!frontend->Initialize()) {
|
||||||
result = frontend->Initialize();
|
return false;
|
||||||
if (result) {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
backend_ = std::move(backend);
|
backend_ = std::move(backend);
|
||||||
|
@ -157,13 +153,13 @@ int Processor::Setup() {
|
||||||
interrupt_thread_block_ = memory_->SystemHeapAlloc(2048);
|
interrupt_thread_block_ = memory_->SystemHeapAlloc(2048);
|
||||||
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::AddModule(std::unique_ptr<Module> module) {
|
bool Processor::AddModule(std::unique_ptr<Module> module) {
|
||||||
std::lock_guard<std::mutex> guard(modules_lock_);
|
std::lock_guard<std::mutex> guard(modules_lock_);
|
||||||
modules_.push_back(std::move(module));
|
modules_.push_back(std::move(module));
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Module* Processor::GetModule(const char* name) {
|
Module* Processor::GetModule(const char* name) {
|
||||||
|
@ -205,7 +201,7 @@ std::vector<Function*> Processor::FindFunctionsWithAddress(uint32_t address) {
|
||||||
return entry_table_.FindWithAddress(address);
|
return entry_table_.FindWithAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::ResolveFunction(uint32_t address, Function** out_function) {
|
bool Processor::ResolveFunction(uint32_t address, Function** out_function) {
|
||||||
*out_function = nullptr;
|
*out_function = nullptr;
|
||||||
Entry* entry;
|
Entry* entry;
|
||||||
Entry::Status status = entry_table_.GetOrCreate(address, &entry);
|
Entry::Status status = entry_table_.GetOrCreate(address, &entry);
|
||||||
|
@ -214,15 +210,13 @@ int Processor::ResolveFunction(uint32_t address, Function** out_function) {
|
||||||
|
|
||||||
// Grab symbol declaration.
|
// Grab symbol declaration.
|
||||||
FunctionInfo* symbol_info;
|
FunctionInfo* symbol_info;
|
||||||
int result = LookupFunctionInfo(address, &symbol_info);
|
if (!LookupFunctionInfo(address, &symbol_info)) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = DemandFunction(symbol_info, &entry->function);
|
if (!DemandFunction(symbol_info, &entry->function)) {
|
||||||
if (result) {
|
|
||||||
entry->status = Entry::STATUS_FAILED;
|
entry->status = Entry::STATUS_FAILED;
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
entry->end_address = symbol_info->end_address();
|
entry->end_address = symbol_info->end_address();
|
||||||
status = entry->status = Entry::STATUS_READY;
|
status = entry->status = Entry::STATUS_READY;
|
||||||
|
@ -230,15 +224,15 @@ int Processor::ResolveFunction(uint32_t address, Function** out_function) {
|
||||||
if (status == Entry::STATUS_READY) {
|
if (status == Entry::STATUS_READY) {
|
||||||
// Ready to use.
|
// Ready to use.
|
||||||
*out_function = entry->function;
|
*out_function = entry->function;
|
||||||
return 0;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Failed or bad state.
|
// Failed or bad state.
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::LookupFunctionInfo(uint32_t address,
|
bool Processor::LookupFunctionInfo(uint32_t address,
|
||||||
FunctionInfo** out_symbol_info) {
|
FunctionInfo** out_symbol_info) {
|
||||||
*out_symbol_info = nullptr;
|
*out_symbol_info = nullptr;
|
||||||
|
|
||||||
// TODO(benvanik): fast reject invalid addresses/log errors.
|
// TODO(benvanik): fast reject invalid addresses/log errors.
|
||||||
|
@ -258,14 +252,14 @@ int Processor::LookupFunctionInfo(uint32_t address,
|
||||||
}
|
}
|
||||||
if (!code_module) {
|
if (!code_module) {
|
||||||
// No module found that could contain the address.
|
// No module found that could contain the address.
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LookupFunctionInfo(code_module, address, out_symbol_info);
|
return LookupFunctionInfo(code_module, address, out_symbol_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::LookupFunctionInfo(Module* module, uint32_t address,
|
bool Processor::LookupFunctionInfo(Module* module, uint32_t address,
|
||||||
FunctionInfo** out_symbol_info) {
|
FunctionInfo** out_symbol_info) {
|
||||||
// Atomic create/lookup symbol in module.
|
// Atomic create/lookup symbol in module.
|
||||||
// If we get back the NEW flag we must declare it now.
|
// If we get back the NEW flag we must declare it now.
|
||||||
FunctionInfo* symbol_info = nullptr;
|
FunctionInfo* symbol_info = nullptr;
|
||||||
|
@ -273,20 +267,19 @@ int Processor::LookupFunctionInfo(Module* module, uint32_t address,
|
||||||
module->DeclareFunction(address, &symbol_info);
|
module->DeclareFunction(address, &symbol_info);
|
||||||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
||||||
// Symbol is undeclared, so declare now.
|
// Symbol is undeclared, so declare now.
|
||||||
int result = frontend_->DeclareFunction(symbol_info);
|
if (!frontend_->DeclareFunction(symbol_info)) {
|
||||||
if (result) {
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
symbol_info->set_status(SymbolInfo::STATUS_DECLARED);
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_symbol_info = symbol_info;
|
*out_symbol_info = symbol_info;
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::DemandFunction(FunctionInfo* symbol_info,
|
bool Processor::DemandFunction(FunctionInfo* symbol_info,
|
||||||
Function** out_function) {
|
Function** out_function) {
|
||||||
*out_function = nullptr;
|
*out_function = nullptr;
|
||||||
|
|
||||||
// Lock function for generation. If it's already being generated
|
// Lock function for generation. If it's already being generated
|
||||||
|
@ -296,11 +289,10 @@ int Processor::DemandFunction(FunctionInfo* symbol_info,
|
||||||
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
if (symbol_status == SymbolInfo::STATUS_NEW) {
|
||||||
// Symbol is undefined, so define now.
|
// Symbol is undefined, so define now.
|
||||||
Function* function = nullptr;
|
Function* function = nullptr;
|
||||||
int result = frontend_->DefineFunction(symbol_info, debug_info_flags_,
|
if (!frontend_->DefineFunction(symbol_info, debug_info_flags_, trace_flags_,
|
||||||
trace_flags_, &function);
|
&function)) {
|
||||||
if (result) {
|
|
||||||
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
symbol_info->set_function(function);
|
symbol_info->set_function(function);
|
||||||
|
|
||||||
|
@ -313,23 +305,23 @@ int Processor::DemandFunction(FunctionInfo* symbol_info,
|
||||||
|
|
||||||
if (symbol_status == SymbolInfo::STATUS_FAILED) {
|
if (symbol_status == SymbolInfo::STATUS_FAILED) {
|
||||||
// Symbol likely failed.
|
// Symbol likely failed.
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_function = symbol_info->function();
|
*out_function = symbol_info->function();
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
bool Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
||||||
SCOPE_profile_cpu_f("cpu");
|
SCOPE_profile_cpu_f("cpu");
|
||||||
|
|
||||||
// Attempt to get the function.
|
// Attempt to get the function.
|
||||||
Function* fn;
|
Function* fn;
|
||||||
if (ResolveFunction(address, &fn)) {
|
if (!ResolveFunction(address, &fn)) {
|
||||||
// Symbol not found in any module.
|
// Symbol not found in any module.
|
||||||
XELOGCPU("Execute(%.8X): failed to find function", address);
|
XELOGCPU("Execute(%.8X): failed to find function", address);
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PPCContext* context = thread_state->context();
|
PPCContext* context = thread_state->context();
|
||||||
|
@ -342,8 +334,7 @@ int Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
||||||
context->lr = lr;
|
context->lr = lr;
|
||||||
|
|
||||||
// Execute the function.
|
// Execute the function.
|
||||||
fn->Call(thread_state, lr);
|
return fn->Call(thread_state, lr);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address,
|
uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address,
|
||||||
|
@ -355,7 +346,7 @@ uint64_t Processor::Execute(ThreadState* thread_state, uint32_t address,
|
||||||
for (size_t i = 0; i < arg_count; ++i) {
|
for (size_t i = 0; i < arg_count; ++i) {
|
||||||
context->r[3 + i] = args[i];
|
context->r[3 + i] = args[i];
|
||||||
}
|
}
|
||||||
if (Execute(thread_state, address)) {
|
if (!Execute(thread_state, address)) {
|
||||||
return 0xDEADBABE;
|
return 0xDEADBABE;
|
||||||
}
|
}
|
||||||
return context->r[3];
|
return context->r[3];
|
||||||
|
|
|
@ -52,9 +52,9 @@ class Processor {
|
||||||
backend::Backend* backend() const { return backend_.get(); }
|
backend::Backend* backend() const { return backend_.get(); }
|
||||||
ExportResolver* export_resolver() const { return export_resolver_; }
|
ExportResolver* export_resolver() const { return export_resolver_; }
|
||||||
|
|
||||||
int Setup();
|
bool Setup();
|
||||||
|
|
||||||
int AddModule(std::unique_ptr<Module> module);
|
bool AddModule(std::unique_ptr<Module> module);
|
||||||
Module* GetModule(const char* name);
|
Module* GetModule(const char* name);
|
||||||
Module* GetModule(const std::string& name) { return GetModule(name.c_str()); }
|
Module* GetModule(const std::string& name) { return GetModule(name.c_str()); }
|
||||||
std::vector<Module*> GetModules();
|
std::vector<Module*> GetModules();
|
||||||
|
@ -66,12 +66,12 @@ class Processor {
|
||||||
|
|
||||||
std::vector<Function*> FindFunctionsWithAddress(uint32_t address);
|
std::vector<Function*> FindFunctionsWithAddress(uint32_t address);
|
||||||
|
|
||||||
int LookupFunctionInfo(uint32_t address, FunctionInfo** out_symbol_info);
|
bool LookupFunctionInfo(uint32_t address, FunctionInfo** out_symbol_info);
|
||||||
int LookupFunctionInfo(Module* module, uint32_t address,
|
bool LookupFunctionInfo(Module* module, uint32_t address,
|
||||||
FunctionInfo** out_symbol_info);
|
FunctionInfo** out_symbol_info);
|
||||||
int ResolveFunction(uint32_t address, Function** out_function);
|
bool ResolveFunction(uint32_t address, Function** out_function);
|
||||||
|
|
||||||
int Execute(ThreadState* thread_state, uint32_t address);
|
bool Execute(ThreadState* thread_state, uint32_t address);
|
||||||
uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t args[],
|
uint64_t Execute(ThreadState* thread_state, uint32_t address, uint64_t args[],
|
||||||
size_t arg_count);
|
size_t arg_count);
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ class Processor {
|
||||||
size_t arg_count);
|
size_t arg_count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
bool DemandFunction(FunctionInfo* symbol_info, Function** out_function);
|
||||||
|
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ RawModule::RawModule(Processor* processor)
|
||||||
|
|
||||||
RawModule::~RawModule() {}
|
RawModule::~RawModule() {}
|
||||||
|
|
||||||
int RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
bool RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
||||||
auto fixed_path = xe::to_string(xe::fix_path_separators(path));
|
auto fixed_path = xe::to_string(xe::fix_path_separators(path));
|
||||||
FILE* file = fopen(fixed_path.c_str(), "rb");
|
FILE* file = fopen(fixed_path.c_str(), "rb");
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
|
@ -49,7 +49,7 @@ int RawModule::LoadFile(uint32_t base_address, const std::wstring& path) {
|
||||||
|
|
||||||
low_address_ = base_address;
|
low_address_ = base_address;
|
||||||
high_address_ = base_address + file_length;
|
high_address_ = base_address + file_length;
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RawModule::ContainsAddress(uint32_t address) {
|
bool RawModule::ContainsAddress(uint32_t address) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class RawModule : public Module {
|
||||||
RawModule(Processor* processor);
|
RawModule(Processor* processor);
|
||||||
~RawModule() override;
|
~RawModule() override;
|
||||||
|
|
||||||
int LoadFile(uint32_t base_address, const std::wstring& path);
|
bool LoadFile(uint32_t base_address, const std::wstring& path);
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@ class ThreadState {
|
||||||
uint32_t thread_state_address() const { return thread_state_address_; }
|
uint32_t thread_state_address() const { return thread_state_address_; }
|
||||||
xe::cpu::frontend::PPCContext* context() const { return context_; }
|
xe::cpu::frontend::PPCContext* context() const { return context_; }
|
||||||
|
|
||||||
int Suspend() { return Suspend(~0); }
|
bool Suspend() { return Suspend(~0); }
|
||||||
int Suspend(uint32_t timeout_ms) { return 1; }
|
bool Suspend(uint32_t timeout_ms) { return false; }
|
||||||
int Resume(bool force = false) { return 1; }
|
bool Resume(bool force = false) { return false; }
|
||||||
|
|
||||||
static void Bind(ThreadState* thread_state);
|
static void Bind(ThreadState* thread_state);
|
||||||
static ThreadState* Get();
|
static ThreadState* Get();
|
||||||
|
|
|
@ -40,10 +40,8 @@ XexModule::XexModule(Processor* processor)
|
||||||
|
|
||||||
XexModule::~XexModule() { xe_xex2_dealloc(xex_); }
|
XexModule::~XexModule() { xe_xex2_dealloc(xex_); }
|
||||||
|
|
||||||
int XexModule::Load(const std::string& name, const std::string& path,
|
bool XexModule::Load(const std::string& name, const std::string& path,
|
||||||
xe_xex2_ref xex) {
|
xe_xex2_ref xex) {
|
||||||
int result;
|
|
||||||
|
|
||||||
xex_ = xex;
|
xex_ = xex;
|
||||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex);
|
const xe_xex2_header_t* header = xe_xex2_get_header(xex);
|
||||||
|
|
||||||
|
@ -66,17 +64,15 @@ int XexModule::Load(const std::string& name, const std::string& path,
|
||||||
|
|
||||||
// Add all imports (variables/functions).
|
// Add all imports (variables/functions).
|
||||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||||
result = SetupLibraryImports(&header->import_libraries[n]);
|
if (!SetupLibraryImports(&header->import_libraries[n])) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find __savegprlr_* and __restgprlr_* and the others.
|
// Find __savegprlr_* and __restgprlr_* and the others.
|
||||||
// We can flag these for special handling (inlining/etc).
|
// We can flag these for special handling (inlining/etc).
|
||||||
result = FindSaveRest();
|
if (!FindSaveRest()) {
|
||||||
if (result) {
|
return false;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup debug info.
|
// Setup debug info.
|
||||||
|
@ -86,20 +82,22 @@ int XexModule::Load(const std::string& name, const std::string& path,
|
||||||
|
|
||||||
// Load a specified module map and diff.
|
// Load a specified module map and diff.
|
||||||
if (FLAGS_load_module_map.size()) {
|
if (FLAGS_load_module_map.size()) {
|
||||||
ReadMap(FLAGS_load_module_map.c_str());
|
if (!ReadMap(FLAGS_load_module_map.c_str())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
bool XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
ExportResolver* export_resolver = processor_->export_resolver();
|
ExportResolver* export_resolver = processor_->export_resolver();
|
||||||
|
|
||||||
xe_xex2_import_info_t* import_infos;
|
xe_xex2_import_info_t* import_infos;
|
||||||
size_t import_info_count;
|
size_t import_info_count;
|
||||||
if (xe_xex2_get_import_infos(xex_, library, &import_infos,
|
if (xe_xex2_get_import_infos(xex_, library, &import_infos,
|
||||||
&import_info_count)) {
|
&import_info_count)) {
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char name[128];
|
char name[128];
|
||||||
|
@ -203,14 +201,14 @@ int XexModule::SetupLibraryImports(const xe_xex2_import_library_t* library) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XexModule::ContainsAddress(uint32_t address) {
|
bool XexModule::ContainsAddress(uint32_t address) {
|
||||||
return address >= low_address_ && address < high_address_;
|
return address >= low_address_ && address < high_address_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int XexModule::FindSaveRest() {
|
bool XexModule::FindSaveRest() {
|
||||||
// Special stack save/restore functions.
|
// Special stack save/restore functions.
|
||||||
// http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/xxx.s.htm
|
// http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/xxx.s.htm
|
||||||
// It'd be nice to stash these away and mark them as such to allow for
|
// It'd be nice to stash these away and mark them as such to allow for
|
||||||
|
@ -523,7 +521,7 @@ int XexModule::FindSaveRest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -27,16 +27,16 @@ class XexModule : public xe::cpu::Module {
|
||||||
|
|
||||||
xe_xex2_ref xex() const { return xex_; }
|
xe_xex2_ref xex() const { return xex_; }
|
||||||
|
|
||||||
int Load(const std::string& name, const std::string& path, xe_xex2_ref xex);
|
bool Load(const std::string& name, const std::string& path, xe_xex2_ref xex);
|
||||||
|
|
||||||
const std::string& name() const override { return name_; }
|
const std::string& name() const override { return name_; }
|
||||||
|
|
||||||
bool ContainsAddress(uint32_t address) override;
|
bool ContainsAddress(uint32_t address) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int SetupImports(xe_xex2_ref xex);
|
bool SetupImports(xe_xex2_ref xex);
|
||||||
int SetupLibraryImports(const xe_xex2_import_library_t* library);
|
bool SetupLibraryImports(const xe_xex2_import_library_t* library);
|
||||||
int FindSaveRest();
|
bool FindSaveRest();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Processor* processor_;
|
Processor* processor_;
|
||||||
|
|
|
@ -5,7 +5,5 @@
|
||||||
'debug_server.h',
|
'debug_server.h',
|
||||||
'debugger.cc',
|
'debugger.cc',
|
||||||
'debugger.h',
|
'debugger.h',
|
||||||
'trace_writer.cc',
|
|
||||||
'trace_writer.h',
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "xenia/debug/trace_writer.h"
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace debug {
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
} // namespace debug
|
|
||||||
} // namespace xe
|
|
|
@ -1,29 +0,0 @@
|
||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* Xenia : Xbox 360 Emulator Research Project *
|
|
||||||
******************************************************************************
|
|
||||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
|
||||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XENIA_DEBUG_TRACE_WRITER_H_
|
|
||||||
#define XENIA_DEBUG_TRACE_WRITER_H_
|
|
||||||
|
|
||||||
namespace xe {
|
|
||||||
namespace debug {
|
|
||||||
|
|
||||||
enum TraceFlags {
|
|
||||||
kTraceFunctionInfo = 1 << 0,
|
|
||||||
kTraceInstructionReferences = 1 << 1,
|
|
||||||
kTraceInstructionResults = 1 << 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
class TraceWriter {
|
|
||||||
public:
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace debug
|
|
||||||
} // namespace xe
|
|
||||||
|
|
||||||
#endif // XENIA_DEBUG_TRACE_WRITER_H_
|
|
|
@ -100,8 +100,7 @@ X_STATUS Emulator::Setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the core components.
|
// Setup the core components.
|
||||||
result = processor_->Setup();
|
if (!processor_->Setup()) {
|
||||||
if (result) {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = audio_system_->Setup();
|
result = audio_system_->Setup();
|
||||||
|
|
|
@ -130,10 +130,10 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
|
||||||
// Prepare the module for execution.
|
// Prepare the module for execution.
|
||||||
// Runtime takes ownership.
|
// Runtime takes ownership.
|
||||||
auto xex_module = std::make_unique<XexModule>(processor);
|
auto xex_module = std::make_unique<XexModule>(processor);
|
||||||
if (xex_module->Load(name_, path_, xex_)) {
|
if (!xex_module->Load(name_, path_, xex_)) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
if (processor->AddModule(std::move(xex_module))) {
|
if (!processor->AddModule(std::move(xex_module))) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue