Mostly complete tracing. Probably a lot of bugs.

This commit is contained in:
Ben Vanik
2014-08-14 20:28:44 -07:00
parent cebf595958
commit c275562594
54 changed files with 1052 additions and 161 deletions

View File

@@ -43,6 +43,7 @@ class Assembler {
virtual int Assemble(runtime::FunctionInfo* symbol_info,
hir::HIRBuilder* builder, uint32_t debug_info_flags,
std::unique_ptr<runtime::DebugInfo> debug_info,
uint32_t trace_flags,
runtime::Function** out_function) = 0;
protected:

View File

@@ -50,7 +50,7 @@ void IVMAssembler::Reset() {
int IVMAssembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
uint32_t debug_info_flags,
std::unique_ptr<DebugInfo> debug_info,
Function** out_function) {
uint32_t trace_flags, Function** out_function) {
SCOPE_profile_cpu_f("alloy");
// Reset when we leave.

View File

@@ -31,7 +31,7 @@ class IVMAssembler : public Assembler {
int Assemble(runtime::FunctionInfo* symbol_info, hir::HIRBuilder* builder,
uint32_t debug_info_flags,
std::unique_ptr<runtime::DebugInfo> debug_info,
runtime::Function** out_function) override;
uint32_t trace_flags, runtime::Function** out_function) override;
private:
Arena intcode_arena_;

View File

@@ -11,11 +11,12 @@
#include <algorithm>
#include <poly/poly.h>
#include <alloy/hir/label.h>
#include <alloy/runtime/runtime.h>
#include <alloy/runtime/symbol_info.h>
#include <alloy/runtime/thread_state.h>
#include <poly/poly.h>
#include <xdb/protocol.h>
// TODO(benvanik): make a compile time flag?
//#define DYNAMIC_REGISTER_ACCESS_CHECK(address) false
@@ -246,6 +247,22 @@ int Translate_SOURCE_OFFSET(TranslationContext& ctx, Instr* i) {
return 0;
}
// TODO(benvanik): dispatch of register forms.
uint32_t IntCode_TRACE_SOURCE(IntCodeState& ics, const IntCode* i) {
// TODO(benvanik): append to active trace writer.
uint64_t trace_base = ics.thread_state->memory()->trace_base();
if (trace_base) {
auto ev = xdb::protocol::InstrEvent::Append(trace_base);
ev->type = xdb::protocol::EventType::INSTR;
ev->thread_id = ics.thread_state->thread_id();
ev->address = ics.rf[i->src1_reg].i32;
}
return IA_NEXT;
}
int Translate_TRACE_SOURCE(TranslationContext& ctx, Instr* i) {
return DispatchToC(ctx, i, IntCode_TRACE_SOURCE);
}
uint32_t IntCode_DEBUG_BREAK(IntCodeState& ics, const IntCode* i) {
DFLUSH();
__debugbreak();
@@ -4174,33 +4191,33 @@ int Translate_ATOMIC_EXCHANGE(TranslationContext& ctx, Instr* i) {
typedef int (*TranslateFn)(TranslationContext& ctx, Instr* i);
static const TranslateFn dispatch_table[] = {
Translate_COMMENT, Translate_NOP,
Translate_SOURCE_OFFSET, Translate_DEBUG_BREAK,
Translate_DEBUG_BREAK_TRUE, Translate_TRAP,
Translate_TRAP_TRUE, Translate_CALL,
Translate_CALL_TRUE, Translate_CALL_INDIRECT,
Translate_CALL_INDIRECT_TRUE, Translate_CALL_EXTERN,
Translate_RETURN, Translate_RETURN_TRUE,
Translate_SET_RETURN_ADDRESS, Translate_BRANCH,
Translate_BRANCH_TRUE, Translate_BRANCH_FALSE,
Translate_ASSIGN, Translate_CAST,
Translate_ZERO_EXTEND, Translate_SIGN_EXTEND,
Translate_TRUNCATE, Translate_CONVERT,
Translate_ROUND, Translate_VECTOR_CONVERT_I2F,
Translate_VECTOR_CONVERT_F2I, Translate_LOAD_VECTOR_SHL,
Translate_LOAD_VECTOR_SHR, Translate_LOAD_CLOCK,
Translate_LOAD_LOCAL, Translate_STORE_LOCAL,
Translate_LOAD_CONTEXT, Translate_STORE_CONTEXT,
Translate_LOAD, Translate_STORE,
Translate_PREFETCH, Translate_MAX,
Translate_VECTOR_MAX, Translate_MIN,
Translate_VECTOR_MIN, Translate_SELECT,
Translate_IS_TRUE, Translate_IS_FALSE,
Translate_COMPARE_EQ, Translate_COMPARE_NE,
Translate_COMPARE_SLT, Translate_COMPARE_SLE,
Translate_COMPARE_SGT, Translate_COMPARE_SGE,
Translate_COMPARE_ULT, Translate_COMPARE_ULE,
Translate_COMPARE_UGT, Translate_COMPARE_UGE,
Translate_DID_CARRY,
Translate_SOURCE_OFFSET, Translate_TRACE_SOURCE,
Translate_DEBUG_BREAK, Translate_DEBUG_BREAK_TRUE,
Translate_TRAP, Translate_TRAP_TRUE,
Translate_CALL, Translate_CALL_TRUE,
Translate_CALL_INDIRECT, Translate_CALL_INDIRECT_TRUE,
Translate_CALL_EXTERN, Translate_RETURN,
Translate_RETURN_TRUE, Translate_SET_RETURN_ADDRESS,
Translate_BRANCH, Translate_BRANCH_TRUE,
Translate_BRANCH_FALSE, Translate_ASSIGN,
Translate_CAST, Translate_ZERO_EXTEND,
Translate_SIGN_EXTEND, Translate_TRUNCATE,
Translate_CONVERT, Translate_ROUND,
Translate_VECTOR_CONVERT_I2F, Translate_VECTOR_CONVERT_F2I,
Translate_LOAD_VECTOR_SHL, Translate_LOAD_VECTOR_SHR,
Translate_LOAD_CLOCK, Translate_LOAD_LOCAL,
Translate_STORE_LOCAL, Translate_LOAD_CONTEXT,
Translate_STORE_CONTEXT, Translate_LOAD,
Translate_STORE, Translate_PREFETCH,
Translate_MAX, Translate_VECTOR_MAX,
Translate_MIN, Translate_VECTOR_MIN,
Translate_SELECT, Translate_IS_TRUE,
Translate_IS_FALSE, Translate_COMPARE_EQ,
Translate_COMPARE_NE, Translate_COMPARE_SLT,
Translate_COMPARE_SLE, Translate_COMPARE_SGT,
Translate_COMPARE_SGE, Translate_COMPARE_ULT,
Translate_COMPARE_ULE, Translate_COMPARE_UGT,
Translate_COMPARE_UGE, Translate_DID_CARRY,
TranslateInvalid, // Translate_DID_OVERFLOW,
Translate_DID_SATURATE, Translate_VECTOR_COMPARE_EQ,
Translate_VECTOR_COMPARE_SGT, Translate_VECTOR_COMPARE_SGE,

View File

@@ -8,6 +8,7 @@
'ivm_backend.cc',
'ivm_backend.h',
'ivm_function.cc',
'ivm_function.h',
'ivm_stack.cc',
'ivm_stack.h',
],

View File

@@ -58,7 +58,7 @@ void X64Assembler::Reset() {
int X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
uint32_t debug_info_flags,
std::unique_ptr<DebugInfo> debug_info,
Function** out_function) {
uint32_t trace_flags, Function** out_function) {
SCOPE_profile_cpu_f("alloy");
// Reset when we leave.
@@ -68,7 +68,7 @@ int X64Assembler::Assemble(FunctionInfo* symbol_info, HIRBuilder* builder,
void* machine_code = 0;
size_t code_size = 0;
int result = emitter_->Emit(builder, debug_info_flags, debug_info.get(),
machine_code, code_size);
trace_flags, machine_code, code_size);
if (result) {
return result;
}

View File

@@ -37,7 +37,7 @@ class X64Assembler : public Assembler {
int Assemble(runtime::FunctionInfo* symbol_info, hir::HIRBuilder* builder,
uint32_t debug_info_flags,
std::unique_ptr<runtime::DebugInfo> debug_info,
runtime::Function** out_function) override;
uint32_t trace_flags, runtime::Function** out_function) override;
private:
void DumpMachineCode(runtime::DebugInfo* debug_info, void* machine_code,

View File

@@ -19,6 +19,7 @@
#include <alloy/runtime/runtime.h>
#include <alloy/runtime/symbol_info.h>
#include <alloy/runtime/thread_state.h>
#include <xdb/protocol.h>
namespace alloy {
namespace backend {
@@ -66,8 +67,8 @@ X64Emitter::~X64Emitter() {}
int X64Emitter::Initialize() { return 0; }
int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
runtime::DebugInfo* debug_info, void*& out_code_address,
size_t& out_code_size) {
runtime::DebugInfo* debug_info, uint32_t trace_flags,
void*& out_code_address, size_t& out_code_size) {
SCOPE_profile_cpu_f("alloy");
// Reset.
@@ -75,6 +76,7 @@ int X64Emitter::Emit(HIRBuilder* builder, uint32_t debug_info_flags,
source_map_count_ = 0;
source_map_arena_.Reset();
}
trace_flags_ = trace_flags;
// Fill the generator with code.
size_t stack_size = 0;
@@ -151,6 +153,19 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
mov(rdx, qword[rcx + 8]); // membase
}
uint64_t trace_base = runtime_->memory()->trace_base();
if (trace_base && trace_flags_ & TRACE_USER_CALLS) {
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::UserCallEvent)));
lock();
xadd(qword[rax], r8);
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::USER_CALL) |
(static_cast<uint64_t>(0) << 8) | (0ull << 32));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
}
// Body.
auto block = builder->first_block();
while (block) {
@@ -165,6 +180,16 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
const Instr* instr = block->instr_head;
while (instr) {
const Instr* new_tail = instr;
// Special handling of TRACE_SOURCE.
if (instr->opcode == &OPCODE_TRACE_SOURCE_info) {
if (trace_flags_ & TRACE_SOURCE) {
EmitTraceSource(instr);
}
instr = instr->next;
continue;
}
if (!SelectSequence(*this, instr, &new_tail)) {
// No sequence found!
assert_always();
@@ -179,6 +204,7 @@ int X64Emitter::Emit(HIRBuilder* builder, size_t& out_stack_size) {
// Function epilog.
L("epilog");
EmitTraceUserCallReturn();
if (emit_prolog) {
mov(rcx, qword[rsp + StackLayout::GUEST_RCX_HOME]);
add(rsp, (uint32_t)stack_size);
@@ -204,6 +230,129 @@ void X64Emitter::MarkSourceOffset(const Instr* i) {
source_map_count_++;
}
void X64Emitter::EmitTraceSource(const Instr* instr) {
uint64_t trace_base = runtime_->memory()->trace_base();
if (!trace_base || !(trace_flags_ & TRACE_SOURCE)) {
return;
}
// TODO(benvanik): make this a function call to some append fn.
uint8_t dest_reg_0 = instr->flags & 0xFF;
uint8_t dest_reg_1 = instr->flags >> 8;
xdb::protocol::EventType event_type;
size_t event_size;
if (dest_reg_0 == 100) {
event_type = xdb::protocol::EventType::INSTR;
event_size = sizeof(xdb::protocol::InstrEvent);
} else if (dest_reg_1 == 100) {
if (dest_reg_0 & (1 << 7)) {
event_type = xdb::protocol::EventType::INSTR_R16;
event_size = sizeof(xdb::protocol::InstrEventR16);
} else {
event_type = xdb::protocol::EventType::INSTR_R8;
event_size = sizeof(xdb::protocol::InstrEventR8);
}
} else {
if (dest_reg_0 & (1 << 7) && dest_reg_1 & (1 << 7)) {
event_type = xdb::protocol::EventType::INSTR_R16_R16;
event_size = sizeof(xdb::protocol::InstrEventR16R16);
} else if (dest_reg_0 & (1 << 7) && !(dest_reg_1 & (1 << 7))) {
event_type = xdb::protocol::EventType::INSTR_R16_R8;
event_size = sizeof(xdb::protocol::InstrEventR16R8);
} else if (!(dest_reg_0 & (1 << 7)) && dest_reg_1 & (1 << 7)) {
event_type = xdb::protocol::EventType::INSTR_R8_R16;
event_size = sizeof(xdb::protocol::InstrEventR8R16);
} else if (!(dest_reg_0 & (1 << 7)) && !(dest_reg_1 & (1 << 7))) {
event_type = xdb::protocol::EventType::INSTR_R8_R8;
event_size = sizeof(xdb::protocol::InstrEventR8R8);
}
}
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(event_size));
lock();
xadd(qword[rax], r8);
// r8 is now the pointer where we can write our event.
// Write the header, which is the same for everything (pretty much).
// Some event types ignore the dest reg, and that's fine.
uint64_t qword_0 = static_cast<uint64_t>(event_type) |
(static_cast<uint64_t>(dest_reg_0) << 8) |
(instr->src1.offset << 32);
mov(rax, qword_0);
mov(qword[r8], rax);
// Write thread ID.
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
switch (event_type) {
case xdb::protocol::EventType::INSTR:
break;
case xdb::protocol::EventType::INSTR_R8:
case xdb::protocol::EventType::INSTR_R16:
if (dest_reg_0 & (1 << 7)) {
EmitTraceSourceAppendValue(instr->src2.value, 8);
} else {
EmitTraceSourceAppendValue(instr->src2.value, 8);
}
break;
case xdb::protocol::EventType::INSTR_R8_R8:
case xdb::protocol::EventType::INSTR_R8_R16:
case xdb::protocol::EventType::INSTR_R16_R8:
case xdb::protocol::EventType::INSTR_R16_R16:
mov(word[r8 + 8], dest_reg_0 | static_cast<uint16_t>(dest_reg_1 << 8));
size_t offset = 8;
if (dest_reg_0 & (1 << 7)) {
EmitTraceSourceAppendValue(instr->src2.value, offset);
offset += 16;
} else {
EmitTraceSourceAppendValue(instr->src2.value, offset);
offset += 8;
}
if (dest_reg_1 & (1 << 7)) {
EmitTraceSourceAppendValue(instr->src3.value, offset);
offset += 16;
} else {
EmitTraceSourceAppendValue(instr->src3.value, offset);
offset += 8;
}
break;
}
}
void X64Emitter::EmitTraceSourceAppendValue(const Value* value,
size_t r8_offset) {
//
}
void X64Emitter::EmitGetCurrentThreadId() {
// rcx must point to context. We could fetch from the stack if needed.
mov(ax,
word[rcx + runtime_->frontend()->context_info()->thread_id_offset()]);
}
void X64Emitter::EmitTraceUserCallReturn() {
auto trace_base = runtime_->memory()->trace_base();
if (!trace_base || !(trace_flags_ & TRACE_USER_CALLS)) {
return;
}
mov(rdx, rax);
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::UserCallReturnEvent)));
lock();
xadd(qword[rax], r8);
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::USER_CALL_RETURN) |
(static_cast<uint64_t>(0) << 8) | (0ull << 32));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
mov(rax, rdx);
ReloadEDX();
}
void X64Emitter::DebugBreak() {
// TODO(benvanik): notify debugger.
db(0xCC);
@@ -258,7 +407,7 @@ uint64_t ResolveFunctionSymbol(void* raw_context, uint64_t symbol_info_ptr) {
#else
uint64_t return_address =
reinterpret_cast<uint64_t>(__builtin_return_address(0));
#endif // XE_WIN32_LIKE
#endif // XE_LIKE_WIN32
#pragma pack(push, 1)
struct Asm {
uint16_t mov_rax;
@@ -301,6 +450,9 @@ void X64Emitter::Call(const hir::Instr* instr,
// Actually jump/call to rax.
if (instr->flags & CALL_TAIL) {
// Since we skip the prolog we need to mark the return here.
EmitTraceUserCallReturn();
// Pass the callers return address over.
mov(rdx, qword[rsp + StackLayout::GUEST_RET_ADDR]);
@@ -338,7 +490,7 @@ uint64_t ResolveFunctionAddress(void* raw_context, uint64_t target_address) {
#else
uint64_t return_address =
reinterpret_cast<uint64_t>(__builtin_return_address(0));
#endif // XE_WIN32_LIKE
#endif // XE_LIKE_WIN32
#pragma pack(push, 1)
struct Asm {
uint16_t cmp_rdx;
@@ -426,6 +578,9 @@ void X64Emitter::CallIndirect(const hir::Instr* instr, const Reg64& reg) {
// Actually jump/call to rax.
L(skip_resolve);
if (instr->flags & CALL_TAIL) {
// Since we skip the prolog we need to mark the return here.
EmitTraceUserCallReturn();
// Pass the callers return address over.
mov(rdx, qword[rsp + StackLayout::GUEST_RET_ADDR]);
@@ -449,6 +604,24 @@ uint64_t UndefinedCallExtern(void* raw_context, uint64_t symbol_info_ptr) {
void X64Emitter::CallExtern(const hir::Instr* instr,
const FunctionInfo* symbol_info) {
assert_true(symbol_info->behavior() == FunctionInfo::BEHAVIOR_EXTERN);
uint64_t trace_base = runtime_->memory()->trace_base();
if (trace_base & trace_flags_ & TRACE_EXTERN_CALLS) {
mov(rax, trace_base);
mov(r8d, static_cast<uint32_t>(sizeof(xdb::protocol::KernelCallEvent)));
lock();
xadd(qword[rax], r8);
// TODO(benvanik): get module/ordinal.
uint32_t module_id = 0;
uint32_t ordinal = 0;
mov(rax, static_cast<uint64_t>(xdb::protocol::EventType::KERNEL_CALL) |
(static_cast<uint64_t>(0) << 8) | (module_id << 16) |
(ordinal));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
}
if (!symbol_info->extern_handler()) {
CallNative(UndefinedCallExtern, reinterpret_cast<uint64_t>(symbol_info));
} else {
@@ -466,6 +639,21 @@ void X64Emitter::CallExtern(const hir::Instr* instr,
ReloadEDX();
// rax = host return
}
if (trace_base && trace_flags_ & TRACE_EXTERN_CALLS) {
mov(rax, trace_base);
mov(r8d,
static_cast<uint32_t>(sizeof(xdb::protocol::KernelCallReturnEvent)));
lock();
xadd(qword[rax], r8);
uint32_t module_id = 0;
uint32_t ordinal = 0;
mov(rax,
static_cast<uint64_t>(xdb::protocol::EventType::KERNEL_CALL_RETURN) |
(static_cast<uint64_t>(0) << 8) | (0));
mov(qword[r8], rax);
EmitGetCurrentThreadId();
mov(word[r8 + 2], ax);
}
}
void X64Emitter::CallNative(void* fn) {

View File

@@ -84,8 +84,8 @@ class X64Emitter : public Xbyak::CodeGenerator {
int Initialize();
int Emit(hir::HIRBuilder* builder, uint32_t debug_info_flags,
runtime::DebugInfo* debug_info, void*& out_code_address,
size_t& out_code_size);
runtime::DebugInfo* debug_info, uint32_t trace_flags,
void*& out_code_address, size_t& out_code_size);
public:
// Reserved: rsp
@@ -163,6 +163,10 @@ class X64Emitter : public Xbyak::CodeGenerator {
protected:
void* Emplace(size_t stack_size);
int Emit(hir::HIRBuilder* builder, size_t& out_stack_size);
void EmitTraceSource(const hir::Instr* instr);
void EmitTraceSourceAppendValue(const hir::Value* value, size_t r8_offset);
void EmitGetCurrentThreadId();
void EmitTraceUserCallReturn();
protected:
runtime::Runtime* runtime_;
@@ -177,6 +181,8 @@ class X64Emitter : public Xbyak::CodeGenerator {
size_t stack_size_;
uint32_t trace_flags_;
static const uint32_t gpr_reg_map_[GPR_COUNT];
static const uint32_t xmm_reg_map_[XMM_COUNT];
};

View File

@@ -12,8 +12,11 @@
namespace alloy {
namespace frontend {
ContextInfo::ContextInfo(size_t size, uintptr_t thread_state_offset)
: size_(size), thread_state_offset_(thread_state_offset) {}
ContextInfo::ContextInfo(size_t size, uintptr_t thread_state_offset,
uintptr_t thread_id_offset)
: size_(size),
thread_state_offset_(thread_state_offset),
thread_id_offset_(thread_id_offset) {}
ContextInfo::~ContextInfo() {}

View File

@@ -17,16 +17,19 @@ namespace frontend {
class ContextInfo {
public:
ContextInfo(size_t size, uintptr_t thread_state_offset);
ContextInfo(size_t size, uintptr_t thread_state_offset,
uintptr_t thread_id_offset);
~ContextInfo();
size_t size() const { return size_; }
uintptr_t thread_state_offset() const { return thread_state_offset_; }
uintptr_t thread_id_offset() const { return thread_id_offset_; }
private:
size_t size_;
uintptr_t thread_state_offset_;
uintptr_t thread_id_offset_;
};
} // namespace frontend

View File

@@ -40,7 +40,7 @@ class Frontend {
virtual int DeclareFunction(runtime::FunctionInfo* symbol_info) = 0;
virtual int DefineFunction(runtime::FunctionInfo* symbol_info,
uint32_t debug_info_flags,
uint32_t debug_info_flags, uint32_t trace_flags,
runtime::Function** out_function) = 0;
protected:

View File

@@ -13,55 +13,28 @@
#include <alloy/core.h>
#include <alloy/vec128.h>
namespace alloy { namespace runtime {
class Runtime;
class ThreadState;
} }
namespace alloy {
namespace frontend {
namespace ppc {
using vec128_t = alloy::vec128_t;
typedef union {
uint32_t value;
struct {
uint8_t lt :1; // Negative (LT) - result is negative
uint8_t gt :1; // Positive (GT) - result is positive (and not zero)
uint8_t eq :1; // Zero (EQ) - result is zero or a stwcx/stdcx completed successfully
uint8_t so :1; // Summary Overflow (SO) - copy of XER[SO]
} cr0;
struct {
uint8_t fx :1; // FP exception summary - copy of FPSCR[FX]
uint8_t fex :1; // FP enabled exception summary - copy of FPSCR[FEX]
uint8_t vx :1; // FP invalid operation exception summary - copy of FPSCR[VX]
uint8_t ox :1; // FP overflow exception - copy of FPSCR[OX]
} cr1;
struct {
uint8_t value :4;
} cr2;
struct {
uint8_t value :4;
} cr3;
struct {
uint8_t value :4;
} cr4;
struct {
uint8_t value :4;
} cr5;
struct {
uint8_t value :4;
} cr6;
struct {
uint8_t value :4;
} cr7;
} PPCCR;
// Map:
// 0-31: GPR
// 32-63: FPR
// 64: LR
// 65: CTR
// 66: XER
// 67: FPSCR
// 68: VSCR
// 69-76: CR0-7
// 100: invalid
// 128-256: VR
#pragma pack(push, 4)
typedef struct XECACHEALIGN64 PPCContext_s {
@@ -194,12 +167,15 @@ typedef struct XECACHEALIGN64 PPCContext_s {
// fpscr.value = (fpscr.value & ~0x000F8000) | v;
// }
// Thread ID assigned to this context.
uint32_t thread_id;
// Reserve address for load acquire/store release. Shared.
uint32_t* reserve_address;
uint32_t* reserve_address;
// Runtime-specific data pointer. Used on callbacks to get access to the
// current runtime and its data.
runtime::Runtime* runtime;
runtime::Runtime* runtime;
void SetRegFromString(const char* name, const char* value);
bool CompareRegWithString(const char* name, const char* value,
@@ -207,10 +183,8 @@ typedef struct XECACHEALIGN64 PPCContext_s {
} PPCContext;
#pragma pack(pop)
} // namespace ppc
} // namespace frontend
} // namespace alloy
#endif // ALLOY_FRONTEND_PPC_PPC_CONTEXT_H_

View File

@@ -297,8 +297,8 @@ XEEMITTER(fnmsubsx, 0xEC00003C, A)(PPCHIRBuilder& f, InstrData& i) {
XEEMITTER(fcfidx, 0xFC00069C, X)(PPCHIRBuilder& f, InstrData& i) {
// frD <- signed_int64_to_double( frB )
Value* v = f.Convert(f.Cast(f.LoadFPR(i.A.FRB), INT64_TYPE), FLOAT64_TYPE);
f.StoreFPR(i.A.FRT, v);
Value* v = f.Convert(f.Cast(f.LoadFPR(i.X.RB), INT64_TYPE), FLOAT64_TYPE);
f.StoreFPR(i.X.RT, v);
// f.UpdateFPRF(v);
if (i.A.Rc) {
// e.update_cr_with_cond(1, v);
@@ -337,7 +337,7 @@ XEEMITTER(fctiwx, 0xFC00001C, X)(PPCHIRBuilder& f, InstrData& i) {
v = f.Cast(f.ZeroExtend(v, INT64_TYPE), FLOAT64_TYPE);
f.StoreFPR(i.X.RT, v);
// f.UpdateFPRF(v);
if (i.A.Rc) {
if (i.X.Rc) {
// e.update_cr_with_cond(1, v);
XEINSTRNOTIMPLEMENTED();
return 1;
@@ -409,7 +409,8 @@ XEEMITTER(mffsx, 0xFC00048E, X)(PPCHIRBuilder& f, InstrData& i) {
XEINSTRNOTIMPLEMENTED();
return 1;
}
f.StoreFPR(i.X.RT, f.Cast(f.LoadFPSCR(), FLOAT64_TYPE));
Value* v = f.Cast(f.LoadFPSCR(), FLOAT64_TYPE);
f.StoreFPR(i.X.RT, v);
return 0;
}

View File

@@ -47,7 +47,8 @@ PPCFrontend::PPCFrontend(Runtime* runtime) : Frontend(runtime) {
InitializeIfNeeded();
std::unique_ptr<ContextInfo> context_info(
new ContextInfo(sizeof(PPCContext), offsetof(PPCContext, thread_state)));
new ContextInfo(sizeof(PPCContext), offsetof(PPCContext, thread_state),
offsetof(PPCContext, thread_id)));
// Add fields/etc.
context_info_ = std::move(context_info);
}
@@ -77,10 +78,11 @@ int PPCFrontend::DeclareFunction(FunctionInfo* symbol_info) {
int PPCFrontend::DefineFunction(FunctionInfo* symbol_info,
uint32_t debug_info_flags,
uint32_t trace_flags,
Function** out_function) {
PPCTranslator* translator = translator_pool_.Allocate(this);
int result =
translator->Translate(symbol_info, debug_info_flags, out_function);
translator->Translate(symbol_info, debug_info_flags, trace_flags, out_function);
translator_pool_.Release(translator);
return result;
}

View File

@@ -24,14 +24,14 @@ class PPCTranslator;
class PPCFrontend : public Frontend {
public:
PPCFrontend(runtime::Runtime* runtime);
virtual ~PPCFrontend();
~PPCFrontend() override;
virtual int Initialize();
int Initialize() override;
virtual int DeclareFunction(runtime::FunctionInfo* symbol_info);
virtual int DefineFunction(runtime::FunctionInfo* symbol_info,
uint32_t debug_info_flags,
runtime::Function** out_function);
int DeclareFunction(runtime::FunctionInfo* symbol_info) override;
int DefineFunction(runtime::FunctionInfo* symbol_info,
uint32_t debug_info_flags, uint32_t trace_flags,
runtime::Function** out_function) override;
private:
TypePool<PPCTranslator, PPCFrontend*> translator_pool_;

View File

@@ -43,7 +43,7 @@ void PPCHIRBuilder::Reset() {
HIRBuilder::Reset();
}
int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, bool with_debug_info) {
int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, uint32_t flags) {
SCOPE_profile_cpu_f("alloy");
Memory* memory = frontend_->memory();
@@ -53,7 +53,7 @@ int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, bool with_debug_info) {
start_address_ = symbol_info->address();
instr_count_ = (symbol_info->end_address() - symbol_info->address()) / 4 + 1;
with_debug_info_ = with_debug_info;
with_debug_info_ = (flags & EMIT_DEBUG_COMMENTS) == EMIT_DEBUG_COMMENTS;
if (with_debug_info_) {
Comment("%s fn %.8X-%.8X %s", symbol_info->module()->name().c_str(),
symbol_info->address(), symbol_info->end_address(),
@@ -84,6 +84,7 @@ int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, bool with_debug_info) {
i.code = poly::load_and_swap<uint32_t>(p + address);
// TODO(benvanik): find a way to avoid using the opcode tables.
i.type = GetInstrType(i.code);
trace_info_.dest_count = 0;
// Mark label, if we were assigned one earlier on in the walk.
// We may still get a label, but it'll be inserted by LookupLabel
@@ -136,6 +137,30 @@ int PPCHIRBuilder::Emit(FunctionInfo* symbol_info, bool with_debug_info) {
// DebugBreak();
// TraceInvalidInstruction(i);
}
if (flags & EMIT_TRACE_SOURCE) {
if (flags & EMIT_TRACE_SOURCE_VALUES) {
switch (trace_info_.dest_count) {
case 0:
TraceSource(i.address);
break;
case 1:
TraceSource(i.address, trace_info_.dests[0].reg,
trace_info_.dests[0].value);
break;
case 2:
TraceSource(i.address, trace_info_.dests[0].reg,
trace_info_.dests[0].value, trace_info_.dests[1].reg,
trace_info_.dests[1].value);
break;
default:
assert_unhandled_case(trace_info_.dest_count);
break;
}
} else {
TraceSource(i.address);
}
}
}
return Finalize();
@@ -205,6 +230,10 @@ Value* PPCHIRBuilder::LoadLR() {
void PPCHIRBuilder::StoreLR(Value* value) {
assert_true(value->type == INT64_TYPE);
StoreContext(offsetof(PPCContext, lr), value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = 64;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadCTR() {
@@ -214,6 +243,10 @@ Value* PPCHIRBuilder::LoadCTR() {
void PPCHIRBuilder::StoreCTR(Value* value) {
assert_true(value->type == INT64_TYPE);
StoreContext(offsetof(PPCContext, ctr), value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = 65;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadCR(uint32_t n) {
@@ -232,6 +265,8 @@ void PPCHIRBuilder::StoreCR(uint32_t n, Value* value) {
void PPCHIRBuilder::StoreCRField(uint32_t n, uint32_t bit, Value* value) {
StoreContext(offsetof(PPCContext, cr0) + (4 * n) + bit, value);
// TODO(benvanik): trace CR.
}
void PPCHIRBuilder::UpdateCR(uint32_t n, Value* lhs, bool is_signed) {
@@ -256,6 +291,8 @@ void PPCHIRBuilder::UpdateCR(uint32_t n, Value* lhs, Value* rhs,
// Value* so = AllocValue(UINT8_TYPE);
// StoreContext(offsetof(PPCContext, cr) + (4 * n) + 3, so);
// TOOD(benvanik): trace CR.
}
void PPCHIRBuilder::UpdateCR6(Value* src_value) {
@@ -265,6 +302,8 @@ void PPCHIRBuilder::UpdateCR6(Value* src_value) {
StoreContext(offsetof(PPCContext, cr6.cr6_all_equal),
IsFalse(Not(src_value)));
StoreContext(offsetof(PPCContext, cr6.cr6_none_equal), IsFalse(src_value));
// TOOD(benvanik): trace CR.
}
Value* PPCHIRBuilder::LoadFPSCR() {
@@ -274,6 +313,10 @@ Value* PPCHIRBuilder::LoadFPSCR() {
void PPCHIRBuilder::StoreFPSCR(Value* value) {
assert_true(value->type == INT64_TYPE);
StoreContext(offsetof(PPCContext, fpscr), value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = 67;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadXER() {
@@ -290,6 +333,10 @@ Value* PPCHIRBuilder::LoadCA() {
void PPCHIRBuilder::StoreCA(Value* value) {
assert_true(value->type == INT8_TYPE);
StoreContext(offsetof(PPCContext, xer_ca), value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = 66;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadSAT() {
@@ -299,6 +346,10 @@ Value* PPCHIRBuilder::LoadSAT() {
void PPCHIRBuilder::StoreSAT(Value* value) {
value = Truncate(value, INT8_TYPE);
StoreContext(offsetof(PPCContext, vscr_sat), value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = 44;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadGPR(uint32_t reg) {
@@ -308,6 +359,10 @@ Value* PPCHIRBuilder::LoadGPR(uint32_t reg) {
void PPCHIRBuilder::StoreGPR(uint32_t reg, Value* value) {
assert_true(value->type == INT64_TYPE);
StoreContext(offsetof(PPCContext, r) + reg * 8, value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = reg;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadFPR(uint32_t reg) {
@@ -317,6 +372,10 @@ Value* PPCHIRBuilder::LoadFPR(uint32_t reg) {
void PPCHIRBuilder::StoreFPR(uint32_t reg, Value* value) {
assert_true(value->type == FLOAT64_TYPE);
StoreContext(offsetof(PPCContext, f) + reg * 8, value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = reg + 32;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadVR(uint32_t reg) {
@@ -326,6 +385,10 @@ Value* PPCHIRBuilder::LoadVR(uint32_t reg) {
void PPCHIRBuilder::StoreVR(uint32_t reg, Value* value) {
assert_true(value->type == VEC128_TYPE);
StoreContext(offsetof(PPCContext, v) + reg * 16, value);
auto& trace_reg = trace_info_.dests[trace_info_.dest_count++];
trace_reg.reg = 128 + reg;
trace_reg.value = value;
}
Value* PPCHIRBuilder::LoadAcquire(Value* address, TypeName type,

View File

@@ -33,7 +33,15 @@ class PPCHIRBuilder : public hir::HIRBuilder {
virtual void Reset();
int Emit(runtime::FunctionInfo* symbol_info, bool with_debug_info);
enum EmitFlags {
// Emit comment nodes.
EMIT_DEBUG_COMMENTS = 1 << 0,
// Emit TraceSource nodes.
EMIT_TRACE_SOURCE = 1 << 1,
// Emit TraceSource nodes with the resulting values of the operations.
EMIT_TRACE_SOURCE_VALUES = EMIT_TRACE_SOURCE | (1 << 2),
};
int Emit(runtime::FunctionInfo* symbol_info, uint32_t flags);
runtime::FunctionInfo* symbol_info() const { return symbol_info_; }
runtime::FunctionInfo* LookupFunction(uint64_t address);
@@ -89,6 +97,15 @@ class PPCHIRBuilder : public hir::HIRBuilder {
uint64_t instr_count_;
Instr** instr_offset_list_;
Label** label_list_;
// Reset each instruction.
struct {
uint32_t dest_count;
struct {
uint8_t reg;
Value* value;
} dests[4];
} trace_info_;
};
} // namespace ppc

View File

@@ -85,7 +85,7 @@ PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
PPCTranslator::~PPCTranslator() = default;
int PPCTranslator::Translate(FunctionInfo* symbol_info,
uint32_t debug_info_flags,
uint32_t debug_info_flags, uint32_t trace_flags,
Function** out_function) {
SCOPE_profile_cpu_f("alloy");
@@ -124,7 +124,16 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
}
// Emit function.
int result = builder_->Emit(symbol_info, debug_info != nullptr);
uint32_t emit_flags = 0;
if (debug_info) {
emit_flags |= PPCHIRBuilder::EMIT_DEBUG_COMMENTS;
}
if (trace_flags & TRACE_SOURCE_VALUES) {
emit_flags |= PPCHIRBuilder::EMIT_TRACE_SOURCE_VALUES;
} else if (trace_flags & TRACE_SOURCE) {
emit_flags |= PPCHIRBuilder::EMIT_TRACE_SOURCE;
}
int result = builder_->Emit(symbol_info, emit_flags);
if (result) {
return result;
}
@@ -150,8 +159,9 @@ int PPCTranslator::Translate(FunctionInfo* symbol_info,
}
// Assemble to backend machine code.
result = assembler_->Assemble(symbol_info, builder_.get(), debug_info_flags,
std::move(debug_info), out_function);
result =
assembler_->Assemble(symbol_info, builder_.get(), debug_info_flags,
std::move(debug_info), trace_flags, out_function);
if (result) {
return result;
}

View File

@@ -32,7 +32,7 @@ class PPCTranslator {
~PPCTranslator();
int Translate(runtime::FunctionInfo* symbol_info, uint32_t debug_info_flags,
runtime::Function** out_function);
uint32_t trace_flags, runtime::Function** out_function);
private:
void DumpSource(runtime::FunctionInfo* symbol_info,

View File

@@ -649,6 +649,28 @@ void HIRBuilder::SourceOffset(uint64_t offset) {
i->src2.value = i->src3.value = NULL;
}
void HIRBuilder::TraceSource(uint64_t offset) {
Instr* i = AppendInstr(OPCODE_TRACE_SOURCE_info, 100 | (100 << 8));
i->src1.offset = offset;
i->set_src2(LoadZero(INT64_TYPE));
i->set_src3(LoadZero(INT64_TYPE));
}
void HIRBuilder::TraceSource(uint64_t offset, uint8_t index, Value* value) {
Instr* i = AppendInstr(OPCODE_TRACE_SOURCE_info, index | (100 << 8));
i->src1.offset = offset;
i->set_src2(value);
i->set_src3(LoadZero(INT64_TYPE));
}
void HIRBuilder::TraceSource(uint64_t offset, uint8_t index_0, Value* value_0,
uint8_t index_1, Value* value_1) {
Instr* i = AppendInstr(OPCODE_TRACE_SOURCE_info, index_0 | (index_1 << 8));
i->src1.offset = offset;
i->set_src2(value_0);
i->set_src3(value_1);
}
void HIRBuilder::DebugBreak() {
Instr* i = AppendInstr(OPCODE_DEBUG_BREAK_info, 0);
i->src1.value = i->src2.value = i->src3.value = NULL;
@@ -1743,11 +1765,13 @@ Value* HIRBuilder::RotateLeft(Value* value1, Value* value2) {
return i->dest;
}
Value* HIRBuilder::VectorRotateLeft(Value* value1, Value* value2, TypeName part_type) {
Value* HIRBuilder::VectorRotateLeft(Value* value1, Value* value2,
TypeName part_type) {
ASSERT_VECTOR_TYPE(value1);
ASSERT_VECTOR_TYPE(value2);
Instr* i = AppendInstr(OPCODE_VECTOR_ROTATE_LEFT_info, part_type, AllocValue(value1->type));
Instr* i = AppendInstr(OPCODE_VECTOR_ROTATE_LEFT_info, part_type,
AllocValue(value1->type));
i->set_src1(value1);
i->set_src2(value2);
i->src3.value = NULL;

View File

@@ -71,6 +71,10 @@ class HIRBuilder {
void Nop();
void SourceOffset(uint64_t offset);
void TraceSource(uint64_t offset);
void TraceSource(uint64_t offset, uint8_t index, Value* value);
void TraceSource(uint64_t offset, uint8_t index_0, Value* value_0,
uint8_t index_1, Value* value_1);
// trace info/etc
void DebugBreak();

View File

@@ -77,6 +77,7 @@ enum Opcode {
OPCODE_COMMENT,
OPCODE_NOP,
OPCODE_SOURCE_OFFSET,
OPCODE_TRACE_SOURCE,
OPCODE_DEBUG_BREAK,
OPCODE_DEBUG_BREAK_TRUE,
OPCODE_TRAP,
@@ -207,6 +208,8 @@ enum OpcodeSignature {
OPCODE_SIG_X_O = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3),
OPCODE_SIG_X_O_V =
(OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) | (OPCODE_SIG_TYPE_V << 6),
OPCODE_SIG_X_O_V_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_O << 3) |
(OPCODE_SIG_TYPE_V << 6) | (OPCODE_SIG_TYPE_V << 9),
OPCODE_SIG_X_S = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_S << 3),
OPCODE_SIG_X_V = (OPCODE_SIG_TYPE_X) | (OPCODE_SIG_TYPE_V << 3),
OPCODE_SIG_X_V_L =

View File

@@ -26,6 +26,12 @@ DEFINE_OPCODE(
OPCODE_SIG_X_O,
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE)
DEFINE_OPCODE(
OPCODE_TRACE_SOURCE,
"trace_source",
OPCODE_SIG_X_O_V_V,
OPCODE_FLAG_IGNORE | OPCODE_FLAG_HIDE)
DEFINE_OPCODE(
OPCODE_DEBUG_BREAK,
"debug_break",

View File

@@ -13,7 +13,7 @@
namespace alloy {
Memory::Memory() : membase_(nullptr), reserve_address_(0) {
Memory::Memory() : membase_(nullptr), reserve_address_(0), trace_base_(0) {
system_page_size_ = poly::page_size();
}

View File

@@ -33,6 +33,9 @@ class Memory {
virtual uint64_t page_table() const = 0;
uint64_t trace_base() const { return trace_base_; }
void set_trace_base(uint64_t value) { trace_base_ = value; }
virtual int Initialize();
void Zero(uint64_t address, size_t size);
@@ -65,6 +68,7 @@ class Memory {
size_t system_page_size_;
uint8_t* membase_;
uint32_t reserve_address_;
uint64_t trace_base_;
};
} // namespace alloy

View File

@@ -26,6 +26,15 @@ enum DebugInfoFlags {
DEBUG_INFO_ALL_DISASM = 0xFFFF,
};
enum TraceFlags {
TRACE_NONE = 0,
TRACE_EXTERN_CALLS = (1 << 0),
TRACE_USER_CALLS = (1 << 1),
TRACE_SOURCE = (1 << 2),
TRACE_SOURCE_VALUES = (1 << 3),
TRACE_FUNCTION_GENERATION = (1 << 4),
};
typedef struct SourceMapEntry_s {
uint64_t source_offset; // Original source address/offset.
uint64_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b)

View File

@@ -12,6 +12,7 @@
#include <alloy/runtime/debugger.h>
#include <alloy/runtime/symbol_info.h>
#include <alloy/runtime/thread_state.h>
#include <xdb/protocol.h>
namespace alloy {
namespace runtime {
@@ -73,8 +74,18 @@ int Function::Call(ThreadState* thread_state, uint64_t return_address) {
int result = 0;
uint64_t trace_base = thread_state->memory()->trace_base();
if (symbol_info_->behavior() == FunctionInfo::BEHAVIOR_EXTERN) {
auto handler = symbol_info_->extern_handler();
if (trace_base && true) {
auto ev = xdb::protocol::KernelCallEvent::Append(trace_base);
ev->type = xdb::protocol::EventType::KERNEL_CALL;
ev->thread_id = thread_state->thread_id();
ev->module_id = 0;
ev->ordinal = 0;
}
if (handler) {
handler(thread_state->raw_context(), symbol_info_->extern_arg0(),
symbol_info_->extern_arg1());
@@ -83,8 +94,28 @@ int Function::Call(ThreadState* thread_state, uint64_t return_address) {
symbol_info_->name().c_str());
result = 1;
}
if (trace_base && true) {
auto ev = xdb::protocol::KernelCallReturnEvent::Append(trace_base);
ev->type = xdb::protocol::EventType::KERNEL_CALL_RETURN;
ev->thread_id = thread_state->thread_id();
}
} else {
if (trace_base && true) {
auto ev = xdb::protocol::UserCallEvent::Append(trace_base);
ev->type = xdb::protocol::EventType::USER_CALL;
ev->call_type = 0; // ?
ev->thread_id = thread_state->thread_id();
ev->address = static_cast<uint32_t>(symbol_info_->address());
}
CallImpl(thread_state, return_address);
if (trace_base && true) {
auto ev = xdb::protocol::UserCallReturnEvent::Append(trace_base);
ev->type = xdb::protocol::EventType::USER_CALL_RETURN;
ev->thread_id = thread_state->thread_id();
}
}
if (original_thread_state != thread_state) {

View File

@@ -13,6 +13,7 @@
#include <alloy/runtime/module.h>
#include <poly/poly.h>
#include <xdb/protocol.h>
// TODO(benvanik): based on compiler support
#include <alloy/backend/ivm/ivm_backend.h>
@@ -26,7 +27,11 @@ namespace runtime {
using alloy::backend::Backend;
using alloy::frontend::Frontend;
Runtime::Runtime(Memory* memory) : memory_(memory) {}
Runtime::Runtime(Memory* memory, uint32_t debug_info_flags,
uint32_t trace_flags)
: memory_(memory),
debug_info_flags_(debug_info_flags),
trace_flags_(trace_flags) {}
Runtime::~Runtime() {
{
@@ -224,14 +229,24 @@ int Runtime::DemandFunction(FunctionInfo* symbol_info,
if (symbol_status == SymbolInfo::STATUS_NEW) {
// Symbol is undefined, so define now.
Function* function = nullptr;
int result =
frontend_->DefineFunction(symbol_info, DEBUG_INFO_DEFAULT, &function);
int result = frontend_->DefineFunction(symbol_info, debug_info_flags_,
trace_flags_, &function);
if (result) {
symbol_info->set_status(SymbolInfo::STATUS_FAILED);
return result;
}
symbol_info->set_function(function);
auto trace_base = memory()->trace_base();
if (trace_base && trace_flags_ & TRACE_FUNCTION_GENERATION) {
auto ev = xdb::protocol::FunctionCompiledEvent::Append(trace_base);
ev->type = xdb::protocol::EventType::FUNCTION_COMPILED;
ev->flags = 0;
ev->address = static_cast<uint32_t>(symbol_info->address());
ev->length =
static_cast<uint32_t>(symbol_info->end_address() - ev->address);
}
// Before we give the symbol back to the rest, let the debugger know.
debugger_->OnFunctionDefined(symbol_info, function);

View File

@@ -29,7 +29,8 @@ namespace runtime {
class Runtime {
public:
explicit Runtime(Memory* memory);
explicit Runtime(Memory* memory, uint32_t debug_info_flags = 0,
uint32_t trace_flags = 0);
virtual ~Runtime();
Memory* memory() const { return memory_; }
@@ -60,6 +61,9 @@ class Runtime {
protected:
Memory* memory_;
uint32_t debug_info_flags_;
uint32_t trace_flags_;
std::unique_ptr<Debugger> debugger_;
std::unique_ptr<frontend::Frontend> frontend_;