The package rpms/qbe.git has added or updated architecture specific content in its
spec file (ExclusiveArch/ExcludeArch or %ifarch/%ifnarch) in commit(s):
https://src.fedoraproject.org/cgit/rpms/qbe.git/commit/?id=329bf1f2c180f7....
Change:
+ExclusiveArch: x86_64 aarch64 riscv64
Thanks.
Full change:
============
commit 4e053fd48fdee00bf5af199815db5f357f1cb488
Author: Timothée Floure <work(a)tfloure.ch>
Date: Fri Feb 16 21:34:53 2024 +0100
Remove QBE 1.1 archive from sources
diff --git a/sources b/sources
index 9670fd1..2836e83 100644
--- a/sources
+++ b/sources
@@ -1,2 +1 @@
-SHA512 (qbe-1.1.tar.xz) =
1e5d7d1df3d73849dbf19dd1d84c9bba63a5041622823a5a239496032f9d82bd1640dd2bbd03e28c8a180b8e66a1fe10deb940b5d8fde996bf593f7e8d943e8b
SHA512 (qbe-1.2.tar.xz) =
b3ffd172e95346b3bfae1d2aff4c22a32af8bd4443d073f6fbb711f41db01f072ca7a8108901508cd4a8366567dab46510e0438716d35548591fdf37cee49971
commit c9ef47f00122ad5d2edbde5cbba84e72939a8939
Author: Timothée Floure <work(a)tfloure.ch>
Date: Fri Feb 16 21:30:44 2024 +0100
Rebase on upstream 1.2
diff --git a/.gitignore b/.gitignore
index 6cacfc7..b206dad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
results_qbe
/qbe-1.0.tar.xz
/qbe-1.1.tar.xz
+/qbe-1.2.tar.xz
diff --git a/qbe.spec b/qbe.spec
index 32bfb1f..7997853 100644
--- a/qbe.spec
+++ b/qbe.spec
@@ -1,13 +1,6 @@
-%bcond snapshot 1
-
-%global srcver 1.1
-%global commit 2d683e0c53907ebca9abde876dd87af70719e42d
-%global shortcommit %(c=%{commit}; echo ${c:0:8})
-%global commitdate 20240129
-%global snapshotver %{commitdate}.%{shortcommit}
Name: qbe
-Version: %{srcver}%{?with_snapshot:^%{snapshotver}}
+Version: 1.2
Release: %autorelease
Summary: A pure C embeddable compiler backend
@@ -15,10 +8,6 @@ License: MIT
URL:
https://c9x.me/compile/
Source0: %{url}/release/%{name}-%{srcver}.tar.xz
-%if %{with snapshot}
-Patch: 0000-snapshot-%{srcver}-%{shortcommit}.patch
-%endif
-
BuildRequires: gcc
BuildRequires: make
diff --git a/sources b/sources
index fbc793b..9670fd1 100644
--- a/sources
+++ b/sources
@@ -1 +1,2 @@
SHA512 (qbe-1.1.tar.xz) =
1e5d7d1df3d73849dbf19dd1d84c9bba63a5041622823a5a239496032f9d82bd1640dd2bbd03e28c8a180b8e66a1fe10deb940b5d8fde996bf593f7e8d943e8b
+SHA512 (qbe-1.2.tar.xz) =
b3ffd172e95346b3bfae1d2aff4c22a32af8bd4443d073f6fbb711f41db01f072ca7a8108901508cd4a8366567dab46510e0438716d35548591fdf37cee49971
commit 7a07d1baef91c3927440ec33102a37f09fe22ca4
Merge: d90362f 329bf1f
Author: Timothée Floure <timothee.floure(a)posteo.net>
Date: Sun Feb 4 17:53:43 2024 +0000
Merge #1 `Rebase to upstream commit 2d683e0c`
commit 329bf1f2c180f737c8ac3599e2a9c1673f21bf46
Author: Mike Rochefort <mroche(a)omenos.dev>
Date: Sat Nov 11 09:40:50 2023 -0500
Rebase to upstream commit 2d683e0c
diff --git a/.gitignore b/.gitignore
index 02d2c10..6cacfc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
+*.rpm
+results_qbe
/qbe-1.0.tar.xz
/qbe-1.1.tar.xz
diff --git a/0000-snapshot-1.1-2d683e0c.patch b/0000-snapshot-1.1-2d683e0c.patch
new file mode 100644
index 0000000..49516a4
--- /dev/null
+++ b/0000-snapshot-1.1-2d683e0c.patch
@@ -0,0 +1,1160 @@
+diff --git a/Makefile b/Makefile
+index 5fadadc..f5e8a76 100644
+--- a/Makefile
++++ b/Makefile
+@@ -13,7 +13,8 @@ OBJ = $(COMMOBJ) $(AMD64OBJ) $(ARM64OBJ) $(RV64OBJ)
+
+ SRCALL = $(OBJ:.o=.c)
+
+-CFLAGS = $(CPPFLAGS) -Wall -Wextra -std=c99 -g -Wpedantic
++CC = cc
++CFLAGS = -std=c99 -g -Wall -Wextra -Wpedantic
+
+ qbe: $(OBJ)
+ $(CC) $(LDFLAGS) $(OBJ) -o $@
+@@ -41,7 +42,7 @@ config.h:
+ ;; \
+ *) \
+ case `uname -m` in \
+- *aarch64*) \
++ *aarch64*|*arm64*) \
+ echo "#define Deftgt T_arm64"; \
+ ;; \
+ *riscv64*) \
+diff --git a/all.h b/all.h
+index 7eba443..e421b9c 100644
+--- a/all.h
++++ b/all.h
+@@ -33,7 +33,7 @@ typedef struct Lnk Lnk;
+ typedef struct Target Target;
+
+ enum {
+- NString = 72,
++ NString = 80,
+ NIns = 1 << 20,
+ NAlign = 3,
+ NField = 32,
+@@ -115,7 +115,7 @@ static inline int rtype(Ref r)
+
+ static inline int rsval(Ref r)
+ {
+- return ((int32_t)r.val << 3) >> 3;
++ return (int32_t)((int64_t)r.val << 3) >> 3;
+ }
+
+ enum CmpI {
+@@ -458,6 +458,7 @@ void freeall(void);
+ void *vnew(ulong, size_t, Pool);
+ void vfree(void *);
+ void vgrow(void *, ulong);
++void strf(char[NString], char *, ...);
+ uint32_t intern(char *);
+ char *str(uint32_t);
+ int argcls(Ins *, int);
+@@ -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 *, void (char *), void (Dat *), void (Fn *));
+ void printfn(Fn *, FILE *);
+ void printref(Ref, Fn *, FILE *);
+ void err(char *, ...) __attribute__((noreturn));
+@@ -510,7 +511,7 @@ void err(char *, ...) __attribute__((noreturn));
+ void elimsb(Fn *);
+
+ /* cfg.c */
+-Blk *blknew(void);
++Blk *newblk(void);
+ void edgedel(Blk *, Blk **);
+ void fillpreds(Fn *);
+ void fillrpo(Fn *);
+@@ -567,6 +568,8 @@ void rega(Fn *);
+ /* emit.c */
+ void emitfnlnk(char *, Lnk *, FILE *);
+ void emitdat(Dat *, FILE *);
++void emitdbgfile(char *, FILE *);
++void emitdbgloc(uint, uint, FILE *);
+ int stashbits(void *, int);
+ void elf_emitfnfin(char *, FILE *);
+ void elf_emitfin(FILE *);
+diff --git a/amd64/emit.c b/amd64/emit.c
+index 9b8bb5d..51d1a5c 100644
+--- a/amd64/emit.c
++++ b/amd64/emit.c
+@@ -372,6 +372,8 @@ emitins(Ins i, Fn *fn, FILE *f)
+ int64_t val;
+ int o, t0;
+ Ins ineg;
++ Con *con;
++ char *sym;
+
+ switch (i.op) {
+ default:
+@@ -490,6 +492,26 @@ emitins(Ins i, Fn *fn, FILE *f)
+ * should use movabsq when reading movq */
+ emitf("mov%k %0, %=", &i, fn, f);
+ break;
++ case Oaddr:
++ if (!T.apple
++ && rtype(i.arg[0]) == RCon
++ && fn->con[i.arg[0].val].sym.type == SThr) {
++ /* derive the symbol address from the TCB
++ * address at offset 0 of %fs */
++ assert(isreg(i.to));
++ con = &fn->con[i.arg[0].val];
++ sym = str(con->sym.id);
++ emitf("movq %%fs:0, %L=", &i, fn, f);
++ fprintf(f, "\tleaq %s%s@tpoff",
++ sym[0] == '"' ? "" : T.assym, sym);
++ if (con->bits.i)
++ fprintf(f, "%+"PRId64, con->bits.i);
++ fprintf(f, "(%%%s), %%%s\n",
++ regtoa(i.to.val, SLong),
++ regtoa(i.to.val, SLong));
++ break;
++ }
++ goto Table;
+ case Ocall:
+ /* calls simply have a weird syntax in AT&T
+ * assembly... */
+@@ -525,6 +547,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 Odbgloc:
++ emitdbgloc(i.arg[0].val, i.arg[1].val, f);
++ break;
+ }
+ }
+
+diff --git a/amd64/isel.c b/amd64/isel.c
+index 3e3fe62..e29c8bf 100644
+--- a/amd64/isel.c
++++ b/amd64/isel.c
+@@ -58,6 +58,21 @@ rslot(Ref r, Fn *fn)
+ return fn->tmp[r.val].slot;
+ }
+
++static int
++hascon(Ref r, Con **pc, Fn *fn)
++{
++ switch (rtype(r)) {
++ case RCon:
++ *pc = &fn->con[r.val];
++ return 1;
++ case RMem:
++ *pc = &fn->mem[r.val].offset;
++ return 1;
++ default:
++ return 0;
++ }
++}
++
+ static void
+ fixarg(Ref *r, int k, Ins *i, Fn *fn)
+ {
+@@ -100,6 +115,34 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
+ r1 = newtmp("isel", Kl, fn);
+ emit(Oaddr, Kl, r1, SLOT(s), R);
+ }
++ else if (T.apple && hascon(r0, &c, fn)
++ && c->type == CAddr && c->sym.type == SThr) {
++ r1 = newtmp("isel", Kl, fn);
++ if (c->bits.i) {
++ r2 = newtmp("isel", Kl, fn);
++ cc = (Con){.type = CBits};
++ cc.bits.i = c->bits.i;
++ r3 = newcon(&cc, fn);
++ emit(Oadd, Kl, r1, r2, r3);
++ } else
++ r2 = r1;
++ emit(Ocopy, Kl, r2, TMP(RAX), R);
++ r2 = newtmp("isel", Kl, fn);
++ r3 = newtmp("isel", Kl, fn);
++ emit(Ocall, 0, R, r3, CALL(17));
++ emit(Ocopy, Kl, TMP(RDI), r2, R);
++ emit(Oload, Kl, r3, r2, R);
++ cc = *c;
++ cc.bits.i = 0;
++ r3 = newcon(&cc, fn);
++ emit(Oload, Kl, r2, r3, R);
++ if (rtype(r0) == RMem) {
++ m = &fn->mem[r0.val];
++ m->offset.type = CUndef;
++ m->base = r1;
++ r1 = r0;
++ }
++ }
+ else if (!(isstore(op) && r == &i->arg[1])
+ && !isload(op) && op != Ocall && rtype(r0) == RCon
+ && fn->con[r0.val].type == CAddr) {
+@@ -122,28 +165,6 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn)
+ m->offset.type = CUndef;
+ m->base = r0;
+ }
+- } else if (T.apple && rtype(r0) == RCon
+- && (c = &fn->con[r0.val])->type == CAddr
+- && c->sym.type == SThr) {
+- r1 = newtmp("isel", Kl, fn);
+- if (c->bits.i) {
+- r2 = newtmp("isel", Kl, fn);
+- cc = (Con){.type = CBits};
+- cc.bits.i = c->bits.i;
+- r3 = newcon(&cc, fn);
+- emit(Oadd, Kl, r1, r2, r3);
+- } else
+- r2 = r1;
+- emit(Ocopy, Kl, r2, TMP(RAX), R);
+- r2 = newtmp("isel", Kl, fn);
+- r3 = newtmp("isel", Kl, fn);
+- emit(Ocall, 0, R, r3, CALL(17));
+- emit(Ocopy, Kl, TMP(RDI), r2, R);
+- emit(Oload, Kl, r3, r2, R);
+- cc = *c;
+- cc.bits.i = 0;
+- r3 = newcon(&cc, fn);
+- emit(Oload, Kl, r2, r3, R);
+ }
+ *r = r1;
+ }
+@@ -295,15 +316,15 @@ sel(Ins i, ANum *an, Fn *fn)
+ break;
+ case Oultof:
+ /* %mask =l and %arg.0, 1
+- %isbig =l shr %arg.0, 63
+- %divided =l shr %arg.0, %isbig
+- %or =l or %mask, %divided
+- %float =d sltof %or
+- %cast =l cast %float
+- %addend =l shl %isbig, 52
+- %sum =l add %cast, %addend
+- %result =d cast %sum
+- */
++ * %isbig =l shr %arg.0, 63
++ * %divided =l shr %arg.0, %isbig
++ * %or =l or %mask, %divided
++ * %float =d sltof %or
++ * %cast =l cast %float
++ * %addend =l shl %isbig, 52
++ * %sum =l add %cast, %addend
++ * %result =d cast %sum
++ */
+ r0 = newtmp("utof", k, fn);
+ if (k == Ks)
+ kc = Kw, sh = 23;
+@@ -336,8 +357,25 @@ sel(Ins i, ANum *an, Fn *fn)
+ kc = Kd;
+ tmp[4] = getcon(0xc3e0000000000000, fn);
+ Oftoui:
+- if (k == Kw)
++ if (k == Kw) {
++ r0 = newtmp("ftou", Kl, fn);
++ emit(Ocopy, Kw, i.to, r0, R);
++ i.cls = Kl;
++ i.to = r0;
+ goto Emit;
++ }
++ /* %try0 =l {s,d}tosi %fp
++ * %mask =l sar %try0, 63
++ *
++ * mask is all ones if the first
++ * try was oob, all zeroes o.w.
++ *
++ * %fps ={s,d} sub %fp, (1<<63)
++ * %try1 =l {s,d}tosi %fps
++ *
++ * %tmp =l and %mask, %try1
++ * %res =l or %tmp, %try0
++ */
+ r0 = newtmp("ftou", kc, fn);
+ for (j=0; j<4; j++)
+ tmp[j] = newtmp("ftou", Kl, fn);
+@@ -371,6 +409,7 @@ sel(Ins i, ANum *an, Fn *fn)
+ case_Oload:
+ seladdr(&i.arg[0], an, fn);
+ goto Emit;
++ case Odbgloc:
+ case Ocall:
+ case Osalloc:
+ case Ocopy:
+diff --git a/amd64/sysv.c b/amd64/sysv.c
+index 04dfd83..5b559c1 100644
+--- a/amd64/sysv.c
++++ b/amd64/sysv.c
+@@ -507,12 +507,12 @@ split(Fn *fn, Blk *b)
+ Blk *bn;
+
+ ++fn->nblk;
+- bn = blknew();
++ bn = newblk();
+ bn->nins = &insb[NIns] - curi;
+ idup(&bn->ins, curi, bn->nins);
+ curi = &insb[NIns];
+ bn->visit = ++b->visit;
+- (void)!snprintf(bn->name, NString, "%s.%d", b->name, b->visit);
++ strf(bn->name, "%s.%d", b->name, b->visit);
+ bn->loop = b->loop;
+ bn->link = b->link;
+ b->link = bn;
+diff --git a/arm64/abi.c b/arm64/abi.c
+index 8ba4ffc..abc02d9 100644
+--- a/arm64/abi.c
++++ b/arm64/abi.c
+@@ -446,6 +446,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
+ case 2: op = Ostoreh; break;
+ case 4:
+ case 8: op = store[*c->cls]; break;
++ default: die("unreachable");
+ }
+ emit(op, 0, R, i->arg[0], r);
+ } else {
+@@ -541,12 +542,12 @@ split(Fn *fn, Blk *b)
+ Blk *bn;
+
+ ++fn->nblk;
+- bn = blknew();
++ bn = newblk();
+ bn->nins = &insb[NIns] - curi;
+ idup(&bn->ins, curi, bn->nins);
+ curi = &insb[NIns];
+ bn->visit = ++b->visit;
+- (void)!snprintf(bn->name, NString, "%s.%d", b->name, b->visit);
++ strf(bn->name, "%s.%d", b->name, b->visit);
+ bn->loop = b->loop;
+ bn->link = b->link;
+ b->link = bn;
+@@ -799,8 +800,8 @@ arm64_abi(Fn *fn)
+ }
+
+ /* abi0 for apple target; introduces
+- * necessery sign extension for arg
+- * passing & returns
++ * necessary sign extensions in calls
++ * and returns
+ */
+ void
+ apple_extsb(Fn *fn)
+@@ -818,6 +819,7 @@ apple_extsb(Fn *fn)
+ op = Oextsb + (j - Jretsb);
+ emit(op, Kw, r, b->jmp.arg, R);
+ b->jmp.arg = r;
++ b->jmp.type = Jretw;
+ }
+ for (i=&b->ins[b->nins]; i>b->ins;) {
+ emiti(*--i);
+@@ -844,7 +846,7 @@ apple_extsb(Fn *fn)
+ }
+
+ if (debug['A']) {
+- fprintf(stderr, "\n> After apple_extsb:\n");
++ fprintf(stderr, "\n> After Apple pre-ABI:\n");
+ printfn(fn, stderr);
+ }
+ }
+diff --git a/arm64/emit.c b/arm64/emit.c
+index 5113c66..990d839 100644
+--- a/arm64/emit.c
++++ b/arm64/emit.c
+@@ -446,6 +446,9 @@ emitins(Ins *i, E *e)
+ if (!req(i->to, R))
+ emitf("mov %=, sp", i, e);
+ break;
++ case Odbgloc:
++ emitdbgloc(i->arg[0].val, i->arg[1].val, e->f);
++ break;
+ }
+ }
+
+@@ -636,4 +639,6 @@ arm64_emitfn(Fn *fn, FILE *out)
+ }
+ }
+ id0 += e->fn->nblk;
++ if (!T.apple)
++ elf_emitfnfin(fn->name, out);
+ }
+diff --git a/cfg.c b/cfg.c
+index d12f6c8..406c307 100644
+--- a/cfg.c
++++ b/cfg.c
+@@ -1,7 +1,7 @@
+ #include "all.h"
+
+ Blk *
+-blknew()
++newblk()
+ {
+ static Blk z;
+ Blk *b;
+@@ -299,7 +299,7 @@ simpljmp(Fn *fn)
+ Blk **uf; /* union-find */
+ Blk **p, *b, *ret;
+
+- ret = blknew();
++ ret = newblk();
+ ret->id = fn->nblk++;
+ ret->jmp.type = Jret0;
+ uf = emalloc(fn->nblk * sizeof uf[0]);
+diff --git a/doc/il.txt b/doc/il.txt
+index cc3e021..2d488dc 100644
+--- a/doc/il.txt
++++ b/doc/il.txt
+@@ -15,7 +15,7 @@
+ 2. <@ Types >
+ * <@ Simple Types >
+ * <@ Subtyping >
+- 3. <@ Constants >
++ 3. <@ Constants and Vals >
+ 4. <@ Linkage >
+ 5. <@ Definitions >
+ * <@ Aggregate Types >
+@@ -168,8 +168,8 @@ The rationale is that a word can be signed or unsigned, so
+ extending it to a long could be done in two ways, either
+ by zero-extension, or by sign-extension.
+
+-- 3. Constants
+---------------
++- 3. Constants and Vals
++-----------------------
+
+ `bnf
+ CONST :=
+@@ -182,6 +182,10 @@ by zero-extension, or by sign-extension.
+ CONST
+ | 'thread' $IDENT # Thread-local symbol
+
++ VAL :=
++ DYNCONST
++ | %IDENT
++
+ Constants come in two kinds: compile-time constants and
+ dynamic constants. Dynamic constants include compile-time
+ constants and other symbol variants that are only known at
+@@ -221,6 +225,10 @@ When the `thread` keyword prefixes a symbol name, the
+ symbol's numeric value is resolved at runtime in the
+ thread-local storage.
+
++Vals are used as arguments in regular, phi, and jump
++instructions within function definitions. They are
++either constants or function-scope temporaries.
++
+ - 4. Linkage
+ ------------
+
+@@ -250,7 +258,7 @@ thread starts, the supporting platform runtime is in
+ charge of making a new copy of the object for the
+ fresh thread. Objects in thread-local storage must
+ be accessed using the `thread $IDENT` syntax, as
+-specified in the <@ Constants > section.
++specified in the <@ Constants and Vals > section.
+
+ A `section` flag can be specified to tell the linker to
+ put the defined item in a certain section. The use of
+@@ -293,6 +301,15 @@ using linkage flags.
+ '{'
+ ( SUBTY [NUMBER] ),
+ '}'
++ | # Union type
++ 'type' :IDENT '=' ['align' NUMBER]
++ '{'
++ (
++ '{'
++ ( SUBTY [NUMBER] ),
++ '}'
++ )+
++ '}'
+ | # Opaque type
+ 'type' :IDENT '=' 'align' NUMBER '{' NUMBER
'}'
+
+@@ -318,6 +335,15 @@ explicitly specified by the programmer.
+
+ type :cryptovector = align 16 { w 4 }
+
++Union types allow the same chunk of memory to be used with
++different layouts. They are defined by enclosing multiple
++regular aggregate type bodies in a pair of curly braces.
++Size and alignment of union types are set to the maximum size
++and alignment of each variation or, in the case of alignment,
++can be explicitly specified.
++
++ type :un9 = { { b } { s } }
++
+ Opaque types are used when the inner structure of an
+ aggregate cannot be specified; the alignment for opaque
+ types is mandatory. They are defined simply by enclosing
+diff --git a/emit.c b/emit.c
+index 017c461..490628e 100644
+--- a/emit.c
++++ b/emit.c
+@@ -207,3 +207,38 @@ macho_emitfin(FILE *f)
+
+ emitfin(f, sec);
+ }
++
++static uint32_t *file;
++static uint nfile;
++static uint curfile;
++
++void
++emitdbgfile(char *fn, FILE *f)
++{
++ uint32_t id;
++ uint n;
++
++ id = intern(fn);
++ for (n=0; n<nfile; n++)
++ if (file[n] == id) {
++ /* gas requires positive
++ * file numbers */
++ curfile = n + 1;
++ return;
++ }
++ if (!file)
++ file = vnew(0, sizeof *file, PHeap);
++ vgrow(&file, ++nfile);
++ file[nfile-1] = id;
++ curfile = nfile;
++ fprintf(f, ".file %u %s\n", curfile, fn);
++}
++
++void
++emitdbgloc(uint line, uint col, FILE *f)
++{
++ if (col != 0)
++ fprintf(f, "\t.loc %u %u %u\n", curfile, line, col);
++ else
++ fprintf(f, "\t.loc %u %u\n", curfile, line);
++}
+diff --git a/main.c b/main.c
+index abfe03e..5ecb4d0 100644
+--- a/main.c
++++ b/main.c
+@@ -107,6 +107,12 @@ func(Fn *fn)
+ freeall();
+ }
+
++static void
++dbgfile(char *fn)
++{
++ emitdbgfile(fn, outf);
++}
++
+ int
+ main(int ac, char *av[])
+ {
+@@ -181,7 +187,7 @@ main(int ac, char *av[])
+ exit(1);
+ }
+ }
+- parse(inf, f, data, func);
++ parse(inf, f, dbgfile, data, func);
+ fclose(inf);
+ } while (++optind < ac);
+
+diff --git a/mem.c b/mem.c
+index 1db632f..944cd2f 100644
+--- a/mem.c
++++ b/mem.c
+@@ -1,6 +1,7 @@
+ #include "all.h"
+
+ typedef struct Range Range;
++typedef struct Store Store;
+ typedef struct Slot Slot;
+
+ /* require use, maintains use counts */
+@@ -95,6 +96,11 @@ struct Range {
+ int a, b;
+ };
+
++struct Store {
++ int ip;
++ Ins *i;
++};
++
+ struct Slot {
+ int t;
+ int sz;
+@@ -102,6 +108,8 @@ struct Slot {
+ bits l;
+ Range r;
+ Slot *s;
++ Store *st;
++ int nst;
+ };
+
+ static inline int
+@@ -159,15 +167,20 @@ load(Ref r, bits x, int ip, Fn *fn, Slot *sl)
+ }
+
+ static void
+-store(Ref r, bits x, int ip, Fn *fn, Slot *sl)
++store(Ref r, bits x, int ip, Ins *i, Fn *fn, Slot *sl)
+ {
+ int64_t off;
+ Slot *s;
+
+ if (slot(&s, &off, r, fn, sl)) {
+- if (s->l)
++ if (s->l) {
+ radd(&s->r, ip);
+- s->l &= ~(x << off);
++ s->l &= ~(x << off);
++ } else {
++ vgrow(&s->st, ++s->nst);
++ s->st[s->nst-1].ip = ip;
++ s->st[s->nst-1].i = i;
++ }
+ }
+ }
+
+@@ -223,6 +236,8 @@ coalesce(Fn *fn)
+ s->sz = t->alias.u.loc.sz;
+ s->m = t->alias.u.loc.m;
+ s->s = 0;
++ s->st = vnew(0, sizeof s->st[0], PHeap);
++ s->nst = 0;
+ }
+ }
+
+@@ -264,14 +279,14 @@ coalesce(Fn *fn)
+ }
+ if (isstore(i->op)) {
+ x = BIT(storesz(i)) - 1;
+- store(arg[1], x, ip--, fn, sl);
++ store(arg[1], x, ip--, i, fn, sl);
+ }
+ if (i->op == Oblit0) {
+ assert((i+1)->op == Oblit1);
+ assert(rtype((i+1)->arg[0]) == RInt);
+ sz = abs(rsval((i+1)->arg[0]));
+ x = sz >= NBit ? (bits)-1 : BIT(sz) - 1;
+- store(arg[1], x, ip--, fn, sl);
++ store(arg[1], x, ip--, i, fn, sl);
+ load(arg[0], x, ip, fn, sl);
+ vgrow(&bl, ++nbl);
+ bl[nbl-1] = i;
+@@ -289,6 +304,16 @@ coalesce(Fn *fn)
+ }
+ free(br);
+
++ /* kill dead stores */
++ for (s=sl; s<&sl[nsl]; s++)
++ for (n=0; n<s->nst; n++)
++ if (!rin(s->r, s->st[n].ip)) {
++ i = s->st[n].i;
++ if (i->op == Oblit0)
++ *(i+1) = (Ins){.op = Onop};
++ *i = (Ins){.op = Onop};
++ }
++
+ /* kill slots with an empty live range */
+ total = 0;
+ freed = 0;
+@@ -297,6 +322,7 @@ coalesce(Fn *fn)
+ for (s=s0=sl; s<&sl[nsl]; s++) {
+ total += s->sz;
+ if (!s->r.b) {
++ vfree(s->st);
+ vgrow(&stk, ++n);
+ stk[n-1] = s->t;
+ freed += s->sz;
+@@ -381,6 +407,11 @@ coalesce(Fn *fn)
+ /* substitute fused slots */
+ for (s=sl; s<&sl[nsl]; s++) {
+ t = &fn->tmp[s->t];
++ /* the visit link is stale,
++ * reset it before the slot()
++ * calls below
++ */
++ t->visit = s-sl;
+ assert(t->ndef == 1 && t->def);
+ if (s->s == s)
+ continue;
+@@ -446,5 +477,7 @@ coalesce(Fn *fn)
+ printfn(fn, stderr);
+ }
+
++ for (s=sl; s<&sl[nsl]; s++)
++ vfree(s->st);
+ vfree(sl);
+ }
+diff --git a/ops.h b/ops.h
+index fbcc2a8..8ccf80d 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 */
++O(dbgloc, T(w,e,e,e, w,e,e,e), 0) X(0, 0, 1) V(0)
+
+ /****************************************/
+ /* INTERNAL OPERATIONS (keep nop first) */
+diff --git a/parse.c b/parse.c
+index aed9427..738ec5b 100644
+--- a/parse.c
++++ b/parse.c
+@@ -53,6 +53,7 @@ enum Token {
+ Tdata,
+ Tsection,
+ Talign,
++ Tdbgfile,
+ Tl,
+ Tw,
+ Tsh,
+@@ -110,6 +111,7 @@ static char *kwmap[Ntok] = {
+ [Tdata] = "data",
+ [Tsection] = "section",
+ [Talign] = "align",
++ [Tdbgfile] = "dbgfile",
+ [Tsb] = "sb",
+ [Tub] = "ub",
+ [Tsh] = "sh",
+@@ -555,7 +557,7 @@ findblk(char *name)
+ for (b=blkh[h]; b; b=b->dlink)
+ if (strcmp(b->name, name) == 0)
+ return b;
+- b = blknew();
++ b = newblk();
+ b->id = nblk++;
+ strcpy(b->name, name);
+ b->dlink = blkh[h];
+@@ -587,6 +589,12 @@ parseline(PState ps)
+ if (ps == PLbl && t != Tlbl && t != Trbrace)
+ err("label or } expected");
+ switch (t) {
++ case Ttmp:
++ r = tmpref(tokval.str);
++ expect(Teq);
++ k = parsecls(&ty);
++ op = next();
++ break;
+ default:
+ if (isstore(t)) {
+ case Tblit:
+@@ -596,13 +604,11 @@ parseline(PState ps)
+ r = R;
+ k = Kw;
+ op = t;
+- goto DoOp;
++ break;
+ }
+ err("label, instruction or jump expected");
+ case Trbrace:
+ return PEnd;
+- case Ttmp:
+- break;
+ case Tlbl:
+ b = findblk(tokval.str);
+ if (curb && curb->jmp.type == Jxxx) {
+@@ -655,12 +661,24 @@ parseline(PState ps)
+ expect(Tnl);
+ closeblk();
+ return PLbl;
++ case Odbgloc:
++ op = t;
++ k = Kw;
++ r = R;
++ expect(Tint);
++ arg[0] = INT(tokval.num);
++ if (arg[0].val != tokval.num)
++ err("line number too big");
++ if (peek() == Tcomma) {
++ next();
++ expect(Tint);
++ arg[1] = INT(tokval.num);
++ if (arg[1].val != tokval.num)
++ err("column number too big");
++ } else
++ arg[1] = INT(0);
++ goto Ins;
+ }
+- r = tmpref(tokval.str);
+- expect(Teq);
+- k = parsecls(&ty);
+- op = next();
+-DoOp:
+ if (op == Tcall) {
+ arg[0] = parseref();
+ parserefl(1);
+@@ -669,8 +687,7 @@ DoOp:
+ if (k == Kc) {
+ k = Kl;
+ arg[1] = TYPE(ty);
+- } else
+- arg[1] = R;
++ }
+ if (k >= Ksb)
+ k = Kw;
+ goto Ins;
+@@ -1160,7 +1177,7 @@ parselnk(Lnk *lnk)
+ }
+
+ void
+-parse(FILE *f, char *path, void data(Dat *), void func(Fn *))
++parse(FILE *f, char *path, void dbgfile(char *), void data(Dat *), void func(Fn *))
+ {
+ Lnk lnk;
+ uint n;
+@@ -1177,6 +1194,10 @@ parse(FILE *f, char *path, void data(Dat *), void func(Fn *))
+ switch (parselnk(&lnk)) {
+ default:
+ err("top-level definition expected");
++ case Tdbgfile:
++ expect(Tstr);
++ dbgfile(tokval.str);
++ break;
+ case Tfunc:
+ func(parsefn(&lnk));
+ break;
+@@ -1203,6 +1224,8 @@ printcon(Con *c, FILE *f)
+ case CUndef:
+ break;
+ case CAddr:
++ if (c->sym.type == SThr)
++ fprintf(f, "thread ");
+ fprintf(f, "$%s", str(c->sym.id));
+ if (c->bits.i)
+ fprintf(f, "%+"PRIi64, c->bits.i);
+diff --git a/rega.c b/rega.c
+index c97d1e1..8e601c9 100644
+--- a/rega.c
++++ b/rega.c
+@@ -239,6 +239,8 @@ pmrec(enum PMStat *status, int i, int *k)
+ c = -1;
+ emit(Ocopy, pm[i].cls, pm[i].dst, pm[i].src, R);
+ break;
++ default:
++ die("unreachable");
+ }
+ status[i] = Moved;
+ return c;
+@@ -663,12 +665,12 @@ rega(Fn *fn)
+ pmgen();
+ if (curi == &insb[NIns])
+ continue;
+- b1 = blknew();
++ b1 = newblk();
+ b1->loop = (b->loop+s->loop) / 2;
+ b1->link = blist;
+ blist = b1;
+ fn->nblk++;
+- (void)!snprintf(b1->name, sizeof(b1->name), "%s_%s", b->name,
s->name);
++ strf(b1->name, "%s_%s", b->name, s->name);
+ b1->nins = &insb[NIns] - curi;
+ stmov += b1->nins;
+ stblk += 1;
+diff --git a/rv64/emit.c b/rv64/emit.c
+index f9df146..a410ddf 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 Odbgloc:
++ emitdbgloc(i->arg[0].val, i->arg[1].val, f);
++ break;
+ }
+ }
+
+@@ -557,4 +560,5 @@ rv64_emitfn(Fn *fn, FILE *f)
+ }
+ }
+ id0 += fn->nblk;
++ elf_emitfnfin(fn->name, f);
+ }
+diff --git a/test/fpcnv.ssa b/test/fpcnv.ssa
+index aea67ac..3466ed2 100644
+--- a/test/fpcnv.ssa
++++ b/test/fpcnv.ssa
+@@ -92,7 +92,7 @@ function l $dtol(d %f) {
+ # 0xdcf5fbe299d0148aull, 0xffffffff00000000ull, -1 };
+ #
+ # double fin[] = { 0.17346516197824458, 442.0760005466251, 4342856.879893436,
+-# 98547543006.49626, 236003043787688.3, 9.499222733527032e+18,
++# 4294967295.0, 98547543006.49626, 236003043787688.3, 9.499222733527032e+18,
+ # 1.1936266170755652e+19 };
+ #
+ # int main() {
+diff --git a/test/mem2.ssa b/test/mem2.ssa
+new file mode 100644
+index 0000000..4a136b4
+--- /dev/null
++++ b/test/mem2.ssa
+@@ -0,0 +1,32 @@
++# Ember Sawady reported this bug
++# in stack-slot coalescing
++
++type :t = { w 2 }
++
++function :t $func() {
++(a)start.0
++ %temp =l alloc4 4
++ %ret =l alloc4 8
++ storew 1, %temp
++ # storew can also go here
++ %field =l add %ret, 4
++ storew 2, %ret
++ blit %temp, %field, 4
++ # removing either of these storews causes it to work
++ storew 2, %ret
++ ret %ret
++}
++
++export function w $main() {
++@start
++ %ret =:t call $func()
++ %fptr =l add %ret, 4
++ %field =w loaduw %fptr
++ %x =w ceqw %field, 1
++ jnz %x, @passed, @failed
++@failed
++ # this fails despite 1 => temp => ret + 4 => field
++ call $abort()
++@passed
++ ret 0
++}
+diff --git a/test/mem3.ssa b/test/mem3.ssa
+new file mode 100644
+index 0000000..a6cafd2
+--- /dev/null
++++ b/test/mem3.ssa
+@@ -0,0 +1,48 @@
++# Ember Sawady reported this bug
++# in stack-slot coalescing
++
++type :type.3 = align 8 { l 1, l 1 }
++type :tags.2 = { { :type.3 1 } }
++type :type.1 = align 8 { w 1, :tags.2 1 }
++type :tags.9 = { { w 1 } }
++type :type.8 = align 4 { w 1, :tags.9 1 }
++
++function :type.1 $func() {
++(a)start.0
++ %object.5 =l alloc8 24
++ %object.7 =l alloc4 8
++ %binding.21 =l alloc8 16
++ %object.23 =l alloc8 24
++(a)body.4
++ %.10 =l add %object.7, 4
++ jnz 1, @matches.13, @next.14
++(a)matches.13
++ # binding.21 gets fused with object.23
++ storel 1, %binding.21
++ %value.22 =l add %binding.21, 8
++ storel 2, %value.22
++ %.24 =l add %object.23, 8
++ # but the blit direction is not set correctly
++ blit %binding.21, %.24, 16
++ ret %object.23
++(a)next.14
++ storew 2543892678, %object.5
++ ret %object.5
++}
++
++export function w $main() {
++(a)start.27
++ %object.43 =l alloc8 24
++ %object.49 =l alloc8 24
++(a)body.28
++ %returns.34 =:type.1 call $func()
++ %value.47 =l add %returns.34, 16
++ %load.48 =l loadl %value.47
++ %.33 =w ceql %load.48, 2
++ jnz %.33, @passed.32, @failed.31
++(a)failed.31
++ call $abort()
++(a)passed.32
++ ret 0
++}
++
+diff --git a/test/tls.ssa b/test/tls.ssa
+index e990663..a17dda9 100644
+--- a/test/tls.ssa
++++ b/test/tls.ssa
+@@ -1,5 +1,8 @@
+ thread data $i = align 4 {w 42}
+-data $fmt = align 1 {b "i%d==%d\n", b 0}
++data $fmti = align 1 {b "i%d==%d\n", b 0}
++
++thread data $x = {w 1, w 2, w 3, w 4}
++data $fmtx = align 1 {b "*(x+%d)==%d\n", b 0}
+
+ export
+ function w $main() {
+@@ -10,9 +13,21 @@ function w $main() {
+ %t =l load %pthr
+ call $pthread_join(l %t, l %rval)
+ %i0 =w loadw thread $i
+- call $printf(l $fmt, ..., w 0, w %i0)
++ call $printf(l $fmti, ..., w 0, w %i0)
+ %i1 =w load %rval
+- call $printf(l $fmt, ..., w 1, w %i1)
++ call $printf(l $fmti, ..., w 1, w %i1)
++
++ %a0 =l call $xaddr()
++ %x0 =w load %a0
++ call $printf(l $fmtx, ..., w 0, w %x0)
++ %a4 =l call $xaddroff4()
++ %x4 =w load %a4
++ call $printf(l $fmtx, ..., w 4, w %x4)
++ %a8 =l call $xaddroff(l 8)
++ %x8 =w load %a8
++ call $printf(l $fmtx, ..., w 8, w %x8)
++ %xc =l call $xvalcnt(l 3)
++ call $printf(l $fmtx, ..., w 12, w %xc)
+ ret 0
+ }
+
+@@ -24,7 +39,36 @@ function l $thread(l %arg) {
+ ret %ret
+ }
+
++function l $xaddr() {
++@start
++ ret thread $x
++}
++
++function l $xaddroff4() {
++@start
++ %a =l add 4, thread $x
++ ret %a
++}
++
++function l $xaddroff(l %off) {
++@start
++ %a =l add thread $x, %off
++ ret %a
++}
++
++function w $xvalcnt(l %cnt) {
++@start
++ %o =l mul 4, %cnt
++ %a =l add thread $x, %o
++ %x =w load %a
++ ret %x
++}
++
+ # >>> output
+ # i0==42
+ # i1==402653226
++# *(x+0)==1
++# *(x+4)==2
++# *(x+8)==3
++# *(x+12)==4
+ # <<<
+diff --git a/tools/lexh.c b/tools/lexh.c
+index 5ceb4ee..1b4a7fb 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",
"dbgloc",
+
+ "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", "dbgfile",
++ "blit", "l", "w", "sh", "uh",
"h", "sb", "ub", "b",
+ "d", "s", "z", "loadw", "loadl",
"loads", "loadd",
+ "alloc1", "alloc2",
+
+diff --git a/tools/test.sh b/tools/test.sh
+index 4412f61..23c6663 100755
+--- a/tools/test.sh
++++ b/tools/test.sh
+@@ -1,6 +1,6 @@
+ #!/bin/sh
+
+-dir=`cd $(dirname "$0"); pwd`
++dir=`dirname "$0"`
+ bin=$dir/../qbe
+ binref=$dir/../qbe.ref
+
+@@ -12,11 +12,6 @@ asmref=$tmp.ref.s
+ exe=$tmp.exe
+ out=$tmp.out
+
+-testcc() {
+- echo "int main() { }" | $1 -x c -o /dev/null - >/dev/null 2>&1
+- return $?
+-}
+-
+ init() {
+ case "$TARGET" in
+ arm64)
+@@ -79,8 +74,8 @@ init() {
+ cc="cc -lpthread"
+ ;;
+ *)
+- cc="${CC:-cc} -lpthread"
+- testcc "$cc" || cc="${CC:-cc}"
++ cc="${CC:-cc}"
++ ccpost="-lpthread"
+ ;;
+ esac
+ TARGET=`$bin -t?`
+@@ -154,7 +149,7 @@ once() {
+ src="$asm"
+ fi
+
+- if ! $cc -g -o $exe $src
++ if ! $cc -g -o $exe $src $ccpost
+ then
+ echo "[cc fail]"
+ return 1
+@@ -201,15 +196,17 @@ fi
+ case "$1" in
+ "all")
+ fail=0
++ count=0
+ for t in $dir/../test/[!_]*.ssa
+ do
+ once $t
+ fail=`expr $fail + $?`
++ count=`expr $count + 1`
+ done
+ if test $fail -ge 1
+ then
+ echo
+- echo "$fail test(s) failed!"
++ echo "$fail of $count tests failed!"
+ else
+ echo
+ echo "All is fine!"
+diff --git a/util.c b/util.c
+index 8997f6c..362fa98 100644
+--- a/util.c
++++ b/util.c
+@@ -154,6 +154,16 @@ vgrow(void *vp, ulong len)
+ *(Vec **)vp = v1;
+ }
+
++void
++strf(char str[NString], char *s, ...)
++{
++ va_list ap;
++
++ va_start(ap, s);
++ vsnprintf(str, NString, s, ap);
++ va_end(ap);
++}
++
+ uint32_t
+ intern(char *s)
+ {
+@@ -334,7 +344,7 @@ newtmp(char *prfx, int k, Fn *fn)
+ vgrow(&fn->tmp, fn->ntmp);
+ memset(&fn->tmp[t], 0, sizeof(Tmp));
+ if (prfx)
+- sprintf(fn->tmp[t].name, "%s.%d", prfx, ++n);
++ strf(fn->tmp[t].name, "%s.%d", prfx, ++n);
+ fn->tmp[t].cls = k;
+ fn->tmp[t].slot = -1;
+ fn->tmp[t].nuse = +1;
diff --git a/qbe.spec b/qbe.spec
index 9f68754..32bfb1f 100644
--- a/qbe.spec
+++ b/qbe.spec
@@ -1,17 +1,28 @@
+%bcond snapshot 1
+
+%global srcver 1.1
+%global commit 2d683e0c53907ebca9abde876dd87af70719e42d
+%global shortcommit %(c=%{commit}; echo ${c:0:8})
+%global commitdate 20240129
+%global snapshotver %{commitdate}.%{shortcommit}
+
Name: qbe
-Version: 1.1
+Version: %{srcver}%{?with_snapshot:^%{snapshotver}}
Release: %autorelease
Summary: A pure C embeddable compiler backend
License: MIT
URL:
https://c9x.me/compile/
+Source0: %{url}/release/%{name}-%{srcver}.tar.xz
-Source0: %{url}/release/%{name}-%{version}.tar.xz
+%if %{with snapshot}
+Patch: 0000-snapshot-%{srcver}-%{shortcommit}.patch
+%endif
BuildRequires: gcc
BuildRequires: make
-ExclusiveArch: x86_64 aarch64
+ExclusiveArch: x86_64 aarch64 riscv64
%description
QBE is a compiler backend that aims to provide 70% of the performance of
@@ -20,25 +31,30 @@ innovation by offering a compact user-friendly and performant backend.
The size
limit constrains QBE to focus on the essential and prevents embarking on a
never-ending path of diminishing returns.
+
%prep
-%autosetup
+%autosetup -n %{name}-%{srcver} -p 1
+
%build
-make CFLAGS="$CFLAGS -std=c11 -fPIE" %{?_smp_mflags}
+%{!?_auto_set_build_flags:%{set_build_flags}}
+%make_build CFLAGS="${CFLAGS} -fPIE -std=c17 -Wall -Wextra -Wpedantic"
+
%install
%make_install PREFIX=%{_prefix}
-mkdir -p %{buildroot}/%{_docdir}/%{name}
-cp -r -p doc/ %{buildroot}/%{_docdir}/%{name}
+
%check
+%{!?_auto_set_build_flags:%{set_build_flags}}
make check
+
%files
-%doc README
%license LICENSE
+%doc README doc/*
%{_bindir}/%{name}
-%{_docdir}/%{name}/*
+
%changelog
%autochangelog
commit d90362f02ac429cf416c6a2c85d61a530c3cf54a
Author: Fedora Release Engineering <releng(a)fedoraproject.org>
Date: Fri Jan 26 13:42:00 2024 +0000
Rebuilt for
https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
commit 0d544189cfd9a01ed83ef26046e02b9785efeb0e
Author: Fedora Release Engineering <releng(a)fedoraproject.org>
Date: Mon Jan 22 09:25:57 2024 +0000
Rebuilt for
https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
commit 573698651cdff49280b3f541190e235170e0b3f3
Author: Fedora Release Engineering <releng(a)fedoraproject.org>
Date: Fri Jul 21 15:47:00 2023 +0000
Rebuilt for
https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
Signed-off-by: Fedora Release Engineering <releng(a)fedoraproject.org>