diff --git a/src/alloy/backend/x64/lowering/lowering_sequences.cc b/src/alloy/backend/x64/lowering/lowering_sequences.cc index 62686229a..52265b1b3 100644 --- a/src/alloy/backend/x64/lowering/lowering_sequences.cc +++ b/src/alloy/backend/x64/lowering/lowering_sequences.cc @@ -185,7 +185,8 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { // -------------------------------------------------------------------------- table->AddSequence(OPCODE_COMMENT, [](X64Emitter& e, Instr*& i) { - //char* str = (char*)i->src1.offset; + // TODO(benvanik): pass through. + auto str = (const char*)i->src1.offset; //lb.Comment(str); //UNIMPLEMENTED_SEQ(); i = i->next; @@ -206,8 +207,7 @@ void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { table->AddSequence(OPCODE_SOURCE_OFFSET, [](X64Emitter& e, Instr*& i) { // TODO(benvanik): translate source offsets for mapping? We're just passing // down the original offset - it may be nice to have two. - //lb.SourceOffset(i->src1.offset); - //UNIMPLEMENTED_SEQ(); + e.MarkSourceOffset(i); i = i->next; return true; }); diff --git a/src/alloy/backend/x64/x64_assembler.cc b/src/alloy/backend/x64/x64_assembler.cc index 9176a60f2..d4e88e621 100644 --- a/src/alloy/backend/x64/x64_assembler.cc +++ b/src/alloy/backend/x64/x64_assembler.cc @@ -70,12 +70,14 @@ int X64Assembler::Assemble( // Lower HIR -> x64. void* machine_code = 0; size_t code_size = 0; - result = emitter_->Emit(builder, machine_code, code_size); + result = emitter_->Emit(builder, + debug_info_flags, debug_info, + machine_code, code_size); XEEXPECTZERO(result); // Stash generated machine code. if (debug_info_flags & DEBUG_INFO_MACHINE_CODE_DISASM) { - DumpMachineCode(machine_code, code_size, &string_buffer_); + DumpMachineCode(debug_info, machine_code, code_size, &string_buffer_); debug_info->set_machine_code_disasm(string_buffer_.ToString()); string_buffer_.Reset(); } @@ -94,14 +96,31 @@ XECLEANUP: } void X64Assembler::DumpMachineCode( - void* machine_code, size_t code_size, StringBuffer* str) { + DebugInfo* debug_info, + void* machine_code, size_t code_size, + StringBuffer* str) { BE::DISASM disasm; xe_zero_struct(&disasm, sizeof(disasm)); disasm.Archi = 64; disasm.Options = BE::Tabulation + BE::MasmSyntax + BE::PrefixedNumeral; disasm.EIP = (BE::UIntPtr)machine_code; BE::UIntPtr eip_end = disasm.EIP + code_size; + uint64_t prev_source_offset = 0; while (disasm.EIP < eip_end) { + // Look up source offset. + auto map_entry = debug_info->LookupCodeOffset( + disasm.EIP - (BE::UIntPtr)machine_code); + if (map_entry) { + if (map_entry->source_offset == prev_source_offset) { + str->Append(" "); + } else { + str->Append("%.8X ", map_entry->source_offset); + prev_source_offset = map_entry->source_offset; + } + } else { + str->Append("? "); + } + size_t len = BE::Disasm(&disasm); if (len == BE::UNKNOWN_OPCODE) { break; diff --git a/src/alloy/backend/x64/x64_assembler.h b/src/alloy/backend/x64/x64_assembler.h index 6e8855dd8..3d6235254 100644 --- a/src/alloy/backend/x64/x64_assembler.h +++ b/src/alloy/backend/x64/x64_assembler.h @@ -38,7 +38,9 @@ public: runtime::Function** out_function); private: - void DumpMachineCode(void* machine_code, size_t code_size, StringBuffer* str); + void DumpMachineCode(runtime::DebugInfo* debug_info, + void* machine_code, size_t code_size, + StringBuffer* str); private: X64Backend* x64_backend_; diff --git a/src/alloy/backend/x64/x64_emitter.cc b/src/alloy/backend/x64/x64_emitter.cc index 24ce7e5f8..c527e62a5 100644 --- a/src/alloy/backend/x64/x64_emitter.cc +++ b/src/alloy/backend/x64/x64_emitter.cc @@ -13,6 +13,7 @@ #include #include #include +#include using namespace alloy; using namespace alloy::backend; @@ -51,7 +52,15 @@ int X64Emitter::Initialize() { } int X64Emitter::Emit( - HIRBuilder* builder, void*& out_code_address, size_t& out_code_size) { + HIRBuilder* builder, + uint32_t debug_info_flags, runtime::DebugInfo* debug_info, + void*& out_code_address, size_t& out_code_size) { + // Reset. + if (debug_info_flags & DEBUG_INFO_SOURCE_MAP) { + source_map_count_ = 0; + source_map_arena_.Reset(); + } + // Fill the generator with code. int result = Emit(builder); if (result) { @@ -62,6 +71,13 @@ int X64Emitter::Emit( out_code_size = getSize(); out_code_address = Emplace(code_cache_); + // Stash source map. + if (debug_info_flags & DEBUG_INFO_SOURCE_MAP) { + debug_info->InitializeSourceMap( + source_map_count_, + (SourceMapEntry*)source_map_arena_.CloneContents()); + } + return 0; } @@ -211,3 +227,11 @@ void X64Emitter::FindFreeRegs( FindFreeRegs(v2, v2_idx, v2_flags); FindFreeRegs(v3, v3_idx, v3_flags); } + +void X64Emitter::MarkSourceOffset(Instr* i) { + auto entry = source_map_arena_.Alloc(); + entry->source_offset = i->src1.offset; + entry->hir_offset = uint32_t(i->block->ordinal << 16) | i->ordinal; + entry->code_offset = getSize(); + source_map_count_++; +} diff --git a/src/alloy/backend/x64/x64_emitter.h b/src/alloy/backend/x64/x64_emitter.h index 85e03ec4d..8dd54399a 100644 --- a/src/alloy/backend/x64/x64_emitter.h +++ b/src/alloy/backend/x64/x64_emitter.h @@ -18,6 +18,7 @@ XEDECLARECLASS2(alloy, hir, HIRBuilder); XEDECLARECLASS2(alloy, hir, Instr); +XEDECLARECLASS2(alloy, runtime, DebugInfo); namespace alloy { namespace backend { @@ -45,6 +46,7 @@ public: 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); public: @@ -132,6 +134,8 @@ public: static uint32_t GetRegBit(const Xbyak::Reg64& r) { return 1 << r.getIdx(); } static uint32_t GetRegBit(const Xbyak::Xmm& r) { return 1 << (16 + r.getIdx()); } + void MarkSourceOffset(hir::Instr* i); + private: void* Emplace(X64CodeCache* code_cache); int Emit(hir::HIRBuilder* builder); @@ -150,6 +154,9 @@ private: // Current register values. hir::Value* reg_values[32]; } reg_state_; + + size_t source_map_count_; + Arena source_map_arena_; }; diff --git a/src/alloy/backend/x64/x64_function.cc b/src/alloy/backend/x64/x64_function.cc index 86c1ab845..31671732d 100644 --- a/src/alloy/backend/x64/x64_function.cc +++ b/src/alloy/backend/x64/x64_function.cc @@ -20,11 +20,12 @@ using namespace alloy::runtime; X64Function::X64Function(FunctionInfo* symbol_info) : - machine_code_(0), code_size_(0), + machine_code_(NULL), code_size_(0), GuestFunction(symbol_info) { } X64Function::~X64Function() { + // machine_code_ is freed by code cache. } void X64Function::Setup(void* machine_code, size_t code_size) { diff --git a/src/alloy/backend/x64/x64_function.h b/src/alloy/backend/x64/x64_function.h index 36d0df88b..01a6767c9 100644 --- a/src/alloy/backend/x64/x64_function.h +++ b/src/alloy/backend/x64/x64_function.h @@ -34,8 +34,8 @@ protected: uint64_t return_address); private: - void* machine_code_; - size_t code_size_; + void* machine_code_; + size_t code_size_; }; diff --git a/src/alloy/compiler/passes/finalization_pass.cc b/src/alloy/compiler/passes/finalization_pass.cc index d7fa967bf..668b546b8 100644 --- a/src/alloy/compiler/passes/finalization_pass.cc +++ b/src/alloy/compiler/passes/finalization_pass.cc @@ -35,8 +35,11 @@ int FinalizationPass::Run(HIRBuilder* builder) { auto arena = builder->arena(); + uint32_t block_ordinal = 0; auto block = builder->first_block(); while (block) { + block->ordinal = block_ordinal++; + // Ensure all labels have names. auto label = block->label_head; while (label) { @@ -52,10 +55,10 @@ int FinalizationPass::Run(HIRBuilder* builder) { // ? remove useless jumps? // Renumber all instructions to make liveness tracking easier. - uint32_t n = 0; + uint32_t instr_ordinal = 0; auto instr = block->instr_head; while (instr) { - instr->ordinal = n++; + instr->ordinal = instr_ordinal++; instr = instr->next; } diff --git a/src/alloy/hir/block.h b/src/alloy/hir/block.h index 4de652ffa..1cb6d6414 100644 --- a/src/alloy/hir/block.h +++ b/src/alloy/hir/block.h @@ -33,6 +33,8 @@ public: Instr* instr_head; Instr* instr_tail; + + uint16_t ordinal; }; diff --git a/src/alloy/runtime/debug_info.cc b/src/alloy/runtime/debug_info.cc index 066ce81da..26ca03bdb 100644 --- a/src/alloy/runtime/debug_info.cc +++ b/src/alloy/runtime/debug_info.cc @@ -17,12 +17,56 @@ DebugInfo::DebugInfo() : source_disasm_(0), raw_hir_disasm_(0), hir_disasm_(0), - machine_code_disasm_(0) { + machine_code_disasm_(0), + source_map_count_(0), + source_map_(NULL) { } DebugInfo::~DebugInfo() { + xe_free(source_map_); xe_free(source_disasm_); xe_free(raw_hir_disasm_); xe_free(hir_disasm_); xe_free(machine_code_disasm_); } + +void DebugInfo::InitializeSourceMap(size_t source_map_count, + SourceMapEntry* source_map) { + source_map_count_ = source_map_count; + source_map_ = source_map; + + // TODO(benvanik): ensure sorted in some way? MC offset? +} + +SourceMapEntry* DebugInfo::LookupSourceOffset(uint64_t offset) { + // TODO(benvanik): binary search? We know the list is sorted by code order. + for (size_t n = 0; n < source_map_count_; n++) { + auto entry = &source_map_[n]; + if (entry->source_offset == offset) { + return entry; + } + } + return NULL; +} + +SourceMapEntry* DebugInfo::LookupHIROffset(uint64_t offset) { + // TODO(benvanik): binary search? We know the list is sorted by code order. + for (size_t n = 0; n < source_map_count_; n++) { + auto entry = &source_map_[n]; + if (entry->hir_offset >= offset) { + return entry; + } + } + return NULL; +} + +SourceMapEntry* DebugInfo::LookupCodeOffset(uint64_t offset) { + // TODO(benvanik): binary search? We know the list is sorted by code order. + for (size_t n = 0; n < source_map_count_; n++) { + auto entry = &source_map_[n]; + if (entry->code_offset >= offset) { + return entry; + } + } + return 0; +} diff --git a/src/alloy/runtime/debug_info.h b/src/alloy/runtime/debug_info.h index 3609c5513..47d2aa277 100644 --- a/src/alloy/runtime/debug_info.h +++ b/src/alloy/runtime/debug_info.h @@ -25,10 +25,20 @@ enum DebugInfoFlags { DEBUG_INFO_HIR_DISASM = (1 << 3), DEBUG_INFO_MACHINE_CODE_DISASM = (1 << 4), + DEBUG_INFO_SOURCE_MAP = (1 << 5), + + DEBUG_INFO_DEFAULT = DEBUG_INFO_SOURCE_MAP, DEBUG_INFO_ALL_DISASM = 0xFFFF, }; +typedef struct SourceMapEntry_s { + uint64_t source_offset; // Original source address/offset. + uint64_t hir_offset; // Block ordinal (16b) | Instr ordinal (16b) + uint64_t code_offset; // Offset from emitted code start. +} SourceMapEntry; + + class DebugInfo { public: DebugInfo(); @@ -43,16 +53,20 @@ public: const char* machine_code_disasm() const { return machine_code_disasm_; } void set_machine_code_disasm(char* value) { machine_code_disasm_ = value; } - // map functions: source addr -> hir index (raw?) - // hir index (raw?) to lir index (raw?) - // lir index (raw?) to machine code offset - // source -> machine code offset + void InitializeSourceMap(size_t source_map_count, + SourceMapEntry* source_map); + SourceMapEntry* LookupSourceOffset(uint64_t offset); + SourceMapEntry* LookupHIROffset(uint64_t offset); + SourceMapEntry* LookupCodeOffset(uint64_t offset); private: char* source_disasm_; char* raw_hir_disasm_; char* hir_disasm_; char* machine_code_disasm_; + + size_t source_map_count_; + SourceMapEntry* source_map_; }; diff --git a/src/alloy/runtime/runtime.cc b/src/alloy/runtime/runtime.cc index 95e27a2d2..8a49a1bc4 100644 --- a/src/alloy/runtime/runtime.cc +++ b/src/alloy/runtime/runtime.cc @@ -250,7 +250,7 @@ int Runtime::DemandFunction( if (symbol_status == SymbolInfo::STATUS_NEW) { // Symbol is undefined, so define now. Function* function = NULL; - int result = frontend_->DefineFunction(symbol_info, DEBUG_INFO_NONE, &function); + int result = frontend_->DefineFunction(symbol_info, DEBUG_INFO_DEFAULT, &function); if (result) { symbol_info->set_status(SymbolInfo::STATUS_FAILED); return result;