commit 9126afa2da0e1635d78429075cc44ca576f68169
parent b5da3f3d64c857baf808220e202dc37c5c039eb8
Author: Quentin Carbonneaux <quentin@c9x.me>
Date: Thu, 24 Nov 2022 11:08:33 +0100
new hlt block terminator
It is handy to express when
the end of a block cannot be
reached. If a hlt terminator
is executed, it traps the
program.
We don't go the llvm way and
specify execution semantics as
undefined behavior.
Diffstat:
9 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/all.h b/all.h
@@ -154,7 +154,7 @@ enum J {
X(jfisle) X(jfislt) X(jfiuge) X(jfiugt) \
X(jfiule) X(jfiult) X(jffeq) X(jffge) \
X(jffgt) X(jffle) X(jfflt) X(jffne) \
- X(jffo) X(jffuo)
+ X(jffo) X(jffuo) X(hlt)
#define X(j) J##j,
JMPS(X)
#undef X
diff --git a/amd64/emit.c b/amd64/emit.c
@@ -582,6 +582,9 @@ amd64_emitfn(Fn *fn, FILE *f)
emitins(*i, fn, f);
lbl = 1;
switch (b->jmp.type) {
+ case Jhlt:
+ fprintf(f, "\tud2\n");
+ break;
case Jret0:
if (fn->dynalloc)
fprintf(f,
diff --git a/amd64/isel.c b/amd64/isel.c
@@ -465,7 +465,9 @@ seljmp(Blk *b, Fn *fn)
Ins *fi;
Tmp *t;
- if (b->jmp.type == Jret0 || b->jmp.type == Jjmp)
+ if (b->jmp.type == Jret0
+ || b->jmp.type == Jjmp
+ || b->jmp.type == Jhlt)
return;
assert(b->jmp.type == Jjnz);
r = b->jmp.arg;
diff --git a/arm64/emit.c b/arm64/emit.c
@@ -561,6 +561,9 @@ arm64_emitfn(Fn *fn, FILE *out)
emitins(i, e);
lbl = 1;
switch (b->jmp.type) {
+ case Jhlt:
+ fprintf(e->f, "\tbrk\t#1000\n");
+ break;
case Jret0:
s = (e->frame - e->padding) / 4;
for (r=arm64_rclob; *r>=0; r++)
diff --git a/arm64/isel.c b/arm64/isel.c
@@ -239,16 +239,11 @@ seljmp(Blk *b, Fn *fn)
Ins *i, *ir;
int ck, cc, use;
- switch (b->jmp.type) {
- default:
- assert(0 && "TODO 2");
- break;
- case Jret0:
- case Jjmp:
+ if (b->jmp.type == Jret0
+ || b->jmp.type == Jjmp
+ || b->jmp.type == Jhlt)
return;
- case Jjnz:
- break;
- }
+ assert(b->jmp.type == Jjnz);
r = b->jmp.arg;
use = -1;
b->jmp.arg = R;
diff --git a/fold.c b/fold.c
@@ -147,6 +147,8 @@ visitjmp(Blk *b, int n, Fn *fn)
edge[n][0].work = flowrk;
flowrk = &edge[n][0];
break;
+ case Jhlt:
+ break;
default:
if (isret(b->jmp.type))
break;
diff --git a/parse.c b/parse.c
@@ -44,6 +44,7 @@ enum {
Tjmp,
Tjnz,
Tret,
+ Thlt,
Texport,
Tthread,
Tfunc,
@@ -99,6 +100,7 @@ static char *kwmap[Ntok] = {
[Tjmp] = "jmp",
[Tjnz] = "jnz",
[Tret] = "ret",
+ [Thlt] = "hlt",
[Texport] = "export",
[Tthread] = "thread",
[Tfunc] = "function",
@@ -641,7 +643,10 @@ parseline(PState ps)
curb->s2 = findblk(tokval.str);
}
if (curb->s1 == curf->start || curb->s2 == curf->start)
- err("invalid jump to the start node");
+ err("invalid jump to the start block");
+ goto Close;
+ case Thlt:
+ curb->jmp.type = Jhlt;
Close:
expect(Tnl);
closeblk();
@@ -1322,6 +1327,9 @@ printfn(Fn *fn, FILE *f)
fprintf(f, ", :%s", typ[fn->retty].name);
fprintf(f, "\n");
break;
+ case Jhlt:
+ fprintf(f, "\thlt\n");
+ break;
case Jjmp:
if (b->s1 != b->link)
fprintf(f, "\tjmp @%s\n", b->s1->name);
@@ -1332,6 +1340,7 @@ printfn(Fn *fn, FILE *f)
printref(b->jmp.arg, fn, f);
fprintf(f, ", ");
}
+ assert(b->s1 && b->s2);
fprintf(f, "@%s, @%s\n", b->s1->name, b->s2->name);
break;
}
diff --git a/rv64/emit.c b/rv64/emit.c
@@ -494,6 +494,9 @@ rv64_emitfn(Fn *fn, FILE *f)
emitins(i, fn, f);
lbl = 1;
switch (b->jmp.type) {
+ case Jhlt:
+ fprintf(f, "\tebreak\n");
+ break;
case Jret0:
if (fn->dynalloc) {
if (frame - 16 <= 2048)
diff --git a/tools/lexh.c b/tools/lexh.c
@@ -25,7 +25,7 @@ char *tok[] = {
"cgtd", "cged", "cned", "ceqd", "cod", "cuod",
"vaarg", "vastart", "...", "env",
- "call", "phi", "jmp", "jnz", "ret", "export",
+ "call", "phi", "jmp", "jnz", "ret", "hlt", "export",
"function", "type", "data", "section", "align",
"l", "w", "sh", "uh", "h", "sb", "ub", "b",
"d", "s", "z", "loadw", "loadl", "loads", "loadd",