Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/backend/ir/debug_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace rat {
}

// consecutive nodes mostly share a location, reuse the last entry then
U32 DebugBody::addLoc(SrcLoc src) {
U32 DebugBody::addLoc(SrcLoc src, U32 scope) {
const DebugLoc& last = locs.back();
if(locs.size() > 1 && last.src.file == src.file && last.src.line == src.line &&
last.src.col == src.col)
if(locs.size() > 1 && last.scope == scope && last.src.file == src.file &&
last.src.line == src.line && last.src.col == src.col)
return (U32)locs.size() - 1;
locs.push_back({src});
locs.push_back({src, scope});
return (U32)locs.size() - 1;
}
} // namespace rat
16 changes: 13 additions & 3 deletions src/backend/ir/debug_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,33 @@ namespace rat {
List<UniquePtr<DebugVar>> vars; // params first
};

// a lexical block, or an inlined call when inlined is set, scope 0 is the function body
struct DebugScope {
U32 parent = 0;
const DebugFunc* inlined = nullptr;
U32 callLoc = 0;
};

struct DebugLoc {
SrcLoc src;
U32 scope = 0;
};

// one copy of a variable in a function's code
struct DebugVarInst {
const DebugVar* var;
U32 scope = 0;
AllocNode* slot = nullptr; // frame storage
};

// debug state of one IR function
// debug state of one IR function, inlining copies it into the caller
struct DebugBody {
DebugFunc* func;
List<DebugLoc> locs = List<DebugLoc>(1); // 0 = no location
List<DebugLoc> locs = List<DebugLoc>(1); // 0 = no location
List<DebugScope> scopes = List<DebugScope>(1); // 0 = the body
List<DebugVarInst> vars;

U32 addLoc(SrcLoc src);
U32 addLoc(SrcLoc src, U32 scope);
};

struct DebugInfo {
Expand Down
23 changes: 22 additions & 1 deletion src/backend/pass/emit/x86/x86_encode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,22 @@ namespace rat {
encodedFunc->lines.push_back({a->here(), src});
}

// [start, end) belongs to the instr's scope and its ancestors, located instrs carry the scope on
void X86EncodePass::markScope(U32 loc, U32 start, U32 end) {
if(!encodedFunc || encodedFunc->scopes.empty() || start == end)
return;
const DebugBody& body = *encodedFunc->fn->getDebug();
if(loc)
scope = body.locs[loc].scope;
for(U32 s = scope; s != 0; s = body.scopes[s].parent) {
List<PcRange>& r = encodedFunc->scopes[s];
if(!r.empty() && r.back().end == start)
r.back().end = end;
else
r.push_back({start, end});
}
}

void X86EncodePass::recordVars(const Function& f) {
if(!f.getDebug())
return;
Expand Down Expand Up @@ -642,8 +658,10 @@ namespace rat {
blockOffset[blk.id] = a->here();
I32 fallthrough = (bi + 1 < f.blocks.size()) ? (I32)f.blocks[bi + 1].id : -1;
for(const MachineInstr& in : blk.insts) {
U32 at = a->here();
markLine(in.loc);
emitInst(in, fallthrough);
markScope(in.loc, at, a->here());
}
}
// jump tables: 4-byte offsets from the table base, emitted after the code
Expand Down Expand Up @@ -696,8 +714,11 @@ namespace rat {
if(objectFormatFor(target.getTriple().os) == ObjectFormat::Elf) {
encodedFunc = &encoded.emplace_back();
encodedFunc->fn = &f;
if(f.getDebug())
if(f.getDebug()) {
encodedFunc->lines.push_back({0, f.getDebug()->func->decl});
encodedFunc->scopes.resize(f.getDebug()->scopes.size());
}
scope = 0;
}
code.clear();
Asm a(code, relocs);
Expand Down
2 changes: 2 additions & 0 deletions src/backend/pass/emit/x86/x86_encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace rat {
void prologue();
void markCfi(CfiOp::Kind kind, PhysReg reg, I32 value);
void markLine(U32 loc);
void markScope(U32 loc, U32 start, U32 end);
void recordVars(const Function& f);
private:
std::ostream* os;
Expand All @@ -111,6 +112,7 @@ namespace rat {
List<PlacedFunc> placed;
List<EncodedFunc> encoded; // elf only, one per placed function
EncodedFunc* encodedFunc = nullptr; // the function being encoded, null on coff
U32 scope = 0; // of the last located instr
const X86CallConv* conv = &abi::kSysV;
const MachineFunc* fn = nullptr;
const X86FrameLayout* fl = nullptr;
Expand Down
39 changes: 39 additions & 0 deletions src/backend/pass/opt/inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace rat {
}

Node* InlinePass::mapped(Node* key) const {
if(!key)
return nullptr;
U32 id = key->getId();
return id < cloneMap.size() ? cloneMap[id] : nullptr;
}
Expand Down Expand Up @@ -128,9 +130,46 @@ namespace rat {
caller.removeNode(call);
}

// the callee scopes and locs move under a new inlined scope of the caller, callee scope k lands at
// scopeBase + k and loc l at locBase + l, the clones take the moved locs
void InlinePass::inlineScopes(Function& caller, CallNode* call, const Function& callee) {
DebugBody& to = *caller.getDebug();
const DebugBody& from = *callee.getDebug();
U32 scopeBase = (U32)to.scopes.size();
U32 locBase = (U32)to.locs.size() - 1;
to.scopes.push_back({to.locs[call->getLoc()].scope, from.func, call->getLoc()});
for(U32 k = 1; k < from.scopes.size(); ++k) {
DebugScope s = from.scopes[k];
s.parent += scopeBase;
s.callLoc = s.callLoc ? locBase + s.callLoc : 0;
to.scopes.push_back(s);
}
for(U32 l = 1; l < from.locs.size(); ++l)
to.locs.push_back({from.locs[l].src, scopeBase + from.locs[l].scope});
for(Node* n : callee)
if(Node* c = mapped(n); c && n->getLoc() && !isStartProj(callee, n))
c->setLoc(locBase + n->getLoc());
}

// after inlineScopes, the callee scopes end the caller list
void InlinePass::inlineVars(Function& caller, const Function& callee) {
DebugBody& to = *caller.getDebug();
U32 scopeBase = (U32)(to.scopes.size() - callee.getDebug()->scopes.size());
for(const DebugVarInst& v : callee.getDebug()->vars) {
DebugVarInst copy = v;
copy.scope = scopeBase + v.scope;
copy.slot = dyn_cast<AllocNode>(mapped(v.slot));
to.vars.push_back(copy);
}
}

B32 InlinePass::inlineCallSite(Function& caller, CallNode* call, Function& callee) {
if(!cloneBody(caller, call, callee))
return false;
if(caller.getDebug() && callee.getDebug()) {
inlineScopes(caller, call, callee);
inlineVars(caller, callee);
}
wireClones(callee);
Merged m = mergeReturns(caller, callee);
if(!m.ctrl)
Expand Down
2 changes: 2 additions & 0 deletions src/backend/pass/opt/inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ namespace rat {
void wireClones(Function& callee);
Merged mergeReturns(Function& caller, const Function& callee);
static void replaceCall(Function& caller, CallNode* call, const Merged& m);
void inlineScopes(Function& caller, CallNode* call, const Function& callee);
void inlineVars(Function& caller, const Function& callee);
B32 inlineCallSite(Function& caller, CallNode* call, Function& callee);
private:
const CallGraph* graph = nullptr; // of the current module run
Expand Down
Loading
Loading