浏览代码

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.
Quentin Carbonneaux 3 年之前
父节点
当前提交
9126afa2da
共有 9 个文件被更改,包括 30 次插入13 次删除
  1. 1 1
      all.h
  2. 3 0
      amd64/emit.c
  3. 3 1
      amd64/isel.c
  4. 3 0
      arm64/emit.c
  5. 4 9
      arm64/isel.c
  6. 2 0
      fold.c
  7. 10 1
      parse.c
  8. 3 0
      rv64/emit.c
  9. 1 1
      tools/lexh.c

+ 1 - 1
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

+ 3 - 0
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,

+ 3 - 1
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;

+ 3 - 0
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++)

+ 4 - 9
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;

+ 2 - 0
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;

+ 10 - 1
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;
 		}

+ 3 - 0
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)

+ 1 - 1
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",