Thomas Bracht Laumann Jespersen: 1 implement line number info tracking 12 files changed, 56 insertions(+), 9 deletions(-)
With qbe, I want to provide abstractions to frontend writers. DWARF is the assembly of debug information, the ambition of qbe is that its users do not have to care about assembly much.
Hi,
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~mpu/qbe/patches/38357/mbox | git am -3Learn more about email & git
Co-authored-by: Bor Grošelj Simić <bgs@turminal.net> --- v3 -> v4 * Rebased bgs' work on current qbe master - @bgs: I changed the Author, let me know if you'd like your name on the Author spot, I'll add myself to Co-authored-by in that case.
I think that's fine as it is now.
* drop the file number argument from "file" and "loc" - the current file number is kept in parse(), and added to Fn so the various emit() functions can get to it. * address mpu's comments on v3: added emitfile() and emitloc() that are called into from the arch-specific emit implementations In amd64/isel.c, the v3 version would fall-through to the default emit code, call emiti() and fixarg(). I noticed that {arm,rv}64 isel implementations took care _not_ to call fixarg() for Oloc ops, so I've done the same for amd64. I don't know which behaviour is correct here for amd64. This version does not track file names it's already seen. This means a sequence like: file "foo.saa" ... file "bar.saa" ... file "foo.saa" will give this output: .file 1 "foo.saa" ... .file 2 "bar.saa" ... .file 3 "foo.saa" I figured that it'd be uncommon to want to switch back and forth between the same files, but let me know if this case needs to be supported. all.h | 5 ++++- amd64/emit.c | 3 +++ amd64/isel.c | 3 +++ arm64/emit.c | 4 ++++ arm64/isel.c | 4 ++++ emit.c | 12 ++++++++++++ main.c | 2 +- ops.h | 2 ++ parse.c | 17 +++++++++++++---- rv64/emit.c | 3 +++ rv64/isel.c | 4 ++++ tools/lexh.c | 6 +++--- 12 files changed, 56 insertions(+), 9 deletions(-) diff --git a/all.h b/all.h index 7eba443..e65cce6 100644 --- a/all.h +++ b/all.h @@ -386,6 +386,7 @@ struct Fn { char vararg; char dynalloc; char name[NString]; + uint filenum; /* debug info: file number for .loc */ Lnk lnk; }; @@ -501,7 +502,7 @@ bshas(BSet *bs, uint elt) /* parse.c */ extern Op optab[NOp]; -void parse(FILE *, char *, void (Dat *), void (Fn *)); +void parse(FILE *, char *, FILE *, void (Dat *), void (Fn *)); void printfn(Fn *, FILE *); void printref(Ref, Fn *, FILE *); void err(char *, ...) __attribute__((noreturn)); @@ -571,3 +572,5 @@ int stashbits(void *, int); void elf_emitfnfin(char *, FILE *); void elf_emitfin(FILE *); void macho_emitfin(FILE *); +void emitfile(uint, char *, FILE *); +void emitloc(long int, long int, FILE *); diff --git a/amd64/emit.c b/amd64/emit.c index 9b8bb5d..00fb7aa 100644 --- a/amd64/emit.c +++ b/amd64/emit.c @@ -525,6 +525,9 @@ emitins(Ins i, Fn *fn, FILE *f) emitcopy(i.arg[0], i.arg[1], i.cls, fn, f); emitcopy(i.arg[1], TMP(XMM0+15), i.cls, fn, f); break; + case Oloc: + emitloc(fn->filenum, fn->con[i.arg[0].val].bits.i, f); + break; } } diff --git a/amd64/isel.c b/amd64/isel.c index 3e3fe62..caf10d2 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -371,6 +371,9 @@ sel(Ins i, ANum *an, Fn *fn) case_Oload: seladdr(&i.arg[0], an, fn); goto Emit; + case Oloc: + emiti(i); + break; case Ocall: case Osalloc: case Ocopy: diff --git a/arm64/emit.c b/arm64/emit.c index 5113c66..8bc6f75 100644 --- a/arm64/emit.c +++ b/arm64/emit.c @@ -446,6 +446,10 @@ emitins(Ins *i, E *e) if (!req(i->to, R)) emitf("mov %=, sp", i, e); break; + case Oloc: + /* FIXME: this should be in gas.c and called into */ + emitloc(e->fn->filenum, e->fn->con[i->arg[0].val].bits.i, e->f); + break; } } diff --git a/arm64/isel.c b/arm64/isel.c index 062beb3..a2c53aa 100644 --- a/arm64/isel.c +++ b/arm64/isel.c @@ -224,6 +224,10 @@ sel(Ins i, Fn *fn) emiti(i); return; } + if (i.op == Oloc) { + emiti(i); + return; + } if (i.op != Onop) { emiti(i); iarg = curi->arg; /* fixarg() can change curi */ diff --git a/emit.c b/emit.c index 017c461..fa4d66b 100644 --- a/emit.c +++ b/emit.c @@ -207,3 +207,15 @@ macho_emitfin(FILE *f) emitfin(f, sec); } + +void +emitfile(uint n, char *fname, FILE *f) +{ + fprintf(f, ".file %u %s\n", n, fname); +} + +void +emitloc(long int a, long int b, FILE *f) +{ + fprintf(f, "\t.loc %ld %ld\n", a, b); +} diff --git a/main.c b/main.c index abfe03e..15de8dd 100644 --- a/main.c +++ b/main.c @@ -181,7 +181,7 @@ main(int ac, char *av[]) exit(1); } } - parse(inf, f, data, func); + parse(inf, f, outf, data, func); fclose(inf); } while (++optind < ac); diff --git a/ops.h b/ops.h index fbcc2a8..6a7fb3b 100644 --- a/ops.h +++ b/ops.h @@ -121,6 +121,8 @@ O(vastart, T(m,e,e,e, x,e,e,e), 0) X(0, 0, 0) V(0) O(copy, T(w,l,s,d, x,x,x,x), 0) X(0, 0, 1) V(0) +/* Debug info */ +O(loc, T(w,l,s,d, x,x,x,x), 0) X(0, 0, 1) V(0) /****************************************/ /* INTERNAL OPERATIONS (keep nop first) */ diff --git a/parse.c b/parse.c index aed9427..b438c28 100644 --- a/parse.c +++ b/parse.c @@ -53,6 +53,7 @@ enum Token { Tdata, Tsection, Talign, + Tfile, Tl, Tw, Tsh, @@ -110,6 +111,7 @@ static char *kwmap[Ntok] = { [Tdata] = "data", [Tsection] = "section", [Talign] = "align", + [Tfile] = "file", [Tsb] = "sb", [Tub] = "ub", [Tsh] = "sh", @@ -130,7 +132,7 @@ enum { TMask = 16383, /* for temps hash */ BMask = 8191, /* for blocks hash */ - K = 9583425, /* found using tools/lexh.c */ + K = 10525445, /* found using tools/lexh.c */ M = 23, }; @@ -592,6 +594,7 @@ parseline(PState ps) case Tblit: case Tcall: case Ovastart: + case Oloc: /* operations without result */ r = R; k = Kw; @@ -856,7 +859,7 @@ typecheck(Fn *fn) } static Fn * -parsefn(Lnk *lnk) +parsefn(Lnk *lnk, uint filenum) { Blk *b; int i; @@ -866,6 +869,7 @@ parsefn(Lnk *lnk) nblk = 0; curi = insb; curf = alloc(sizeof *curf); + curf->filenum = filenum; curf->ntmp = 0; curf->ncon = 2; curf->tmp = vnew(curf->ntmp, sizeof curf->tmp[0], PFn); @@ -1160,10 +1164,11 @@ parselnk(Lnk *lnk) } void -parse(FILE *f, char *path, void data(Dat *), void func(Fn *)) +parse(FILE *f, char *path, FILE *outf, void data(Dat *), void func(Fn *)) { Lnk lnk; uint n; + static uint curfile = 0; lexinit(); inf = f; @@ -1177,8 +1182,12 @@ parse(FILE *f, char *path, void data(Dat *), void func(Fn *)) switch (parselnk(&lnk)) { default: err("top-level definition expected"); + case Tfile: + expect(Tstr); + emitfile(++curfile, tokval.str, outf); + break; case Tfunc: - func(parsefn(&lnk)); + func(parsefn(&lnk, curfile)); break; case Tdata: parsedat(data, &lnk); diff --git a/rv64/emit.c b/rv64/emit.c index f9df146..3e09410 100644 --- a/rv64/emit.c +++ b/rv64/emit.c @@ -405,6 +405,9 @@ emitins(Ins *i, Fn *fn, FILE *f) if (!req(i->to, R)) emitf("mv %=, sp", i, fn, f); break; + case Oloc: + emitloc(fn->filenum, fn->con[i->arg[0].val].bits.i, f); + break; } } diff --git a/rv64/isel.c b/rv64/isel.c index 8921a07..d9bbefe 100644 --- a/rv64/isel.c +++ b/rv64/isel.c @@ -187,6 +187,10 @@ sel(Ins i, Fn *fn) selcmp(i, ck, cc, fn); return; } + if (i.op == Oloc) { + emiti(i); + return; + } if (i.op != Onop) { emiti(i); i0 = curi; /* fixarg() can change curi */ diff --git a/tools/lexh.c b/tools/lexh.c index 5ceb4ee..8883976 100644 --- a/tools/lexh.c +++ b/tools/lexh.c @@ -23,11 +23,11 @@ char *tok[] = { "ceql", "cnel", "cles", "clts", "cgts", "cges", "cnes", "ceqs", "cos", "cuos", "cled", "cltd", "cgtd", "cged", "cned", "ceqd", "cod", "cuod", - "vaarg", "vastart", "...", "env", + "vaarg", "vastart", "...", "env", "loc", "call", "phi", "jmp", "jnz", "ret", "hlt", "export", - "function", "type", "data", "section", "align", "blit", - "l", "w", "sh", "uh", "h", "sb", "ub", "b", + "function", "type", "data", "section", "align", "file", + "blit", "l", "w", "sh", "uh", "h", "sb", "ub", "b", "d", "s", "z", "loadw", "loadl", "loads", "loadd", "alloc1", "alloc2", -- 2.38.2
Hi, really glad to see someone working on this.
I don't think that's going to work. Having multiple numbers for the same file may even be fine by the standard, the problem is that the frontend needs to know exaclty which number is assigned to what file, because the numbers are used to keep track of other kinds of debug information that the frontends will eventually generate. This tracking can also be done in other ways, but letting the frontend assign them and making QBE just pass them through seems the easiest, at least until other parts of debug information infrastructure in QBE and interested frontends crystallize.