Mostly complete tracing. Probably a lot of bugs.
This commit is contained in:
@@ -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_
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user