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.
---
I'm sharing this on the ML to
gather some feedback. I still
need to test on osx before
merging it in master.
For Hare, I expect we will want
to generate 'hlt' terminators
on abort paths, and more generally
when calling a @noreturn func.
hlt may also prove handy when
optimization passes have to kill
a jump that should be dead (e.g.,
that depends on data loaded from
uninitialized memory).
all.h | 2 +-
amd64/emit.c | 3 +++
amd64/isel.c | 4 +++-
arm64/emit.c | 3 +++
arm64/isel.c | 13 ++++---------
fold.c | 5 ++++-
parse.c | 7 ++++++-
rv64/emit.c | 3 +++
tools/lexh.c | 2 +-
9 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/all.h b/all.h
index d852609..3ddb944 100644
--- 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
index a034a66..9e5996b 100644
--- 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
index 63c304a..6d62275 100644
--- 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
index 38b7e1a..4a0316c 100644
--- 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
index 9b062d8..062beb3 100644
--- 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
index 75554bf..3873e40 100644
--- a/fold.c
+++ b/fold.c
@@ -147,9 +147,12 @@ visitjmp(Blk *b, int n, Fn *fn)
edge[n][0].work = flowrk;
flowrk = &edge[n][0];
break;
+ case Jhlt:
+ case_Jret:
+ break;
default:
if (isret(b->jmp.type))
- break;
+ goto case_Jret;
die("unreachable");
}
}
diff --git a/parse.c b/parse.c
index 04ef8be..5b18d7c 100644
--- 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();
diff --git a/rv64/emit.c b/rv64/emit.c
index 4ce6555..f9e58da 100644
--- 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
index 1aea3e0..a07514e 100644
--- 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",
--
2.38.1