Compile logical or/and operators with early termination.

Make the && and || operators right-associative since that generates
better code, and should make no difference in semantics.
This commit is contained in:
Tor Andersson
2014-01-12 13:39:48 +01:00
parent 67de4965c6
commit 62fea907a6
3 changed files with 63 additions and 31 deletions
+59 -25
View File
@@ -68,6 +68,22 @@ static void emitstring(JF, int opcode, const char *s)
emit(J, F, addconst(J, F, v));
}
static int jump(JF, int opcode)
{
int addr = F->len + 1;
emit(J, F, opcode);
emit(J, F, 0);
emit(J, F, 0);
return addr;
}
static void label(JF, int addr)
{
int dest = F->len;
F->code[addr+0] = (dest >> 8) & 0xFF;
F->code[addr+1] = (dest) & 0xFF;
}
static void unary(JF, js_Ast *exp, int opcode)
{
cexp(J, F, exp->a);
@@ -152,6 +168,7 @@ static void assignop(JF, js_Ast *exp, int opcode)
static void cexp(JF, js_Ast *exp)
{
int then, end;
int n;
switch (exp->type) {
@@ -233,8 +250,6 @@ static void cexp(JF, js_Ast *exp)
case EXP_POSTINC: clval(J, F, exp->a); emit(J, F, OP_POSTINC); break;
case EXP_POSTDEC: clval(J, F, exp->a); emit(J, F, OP_POSTDEC); break;
case EXP_LOGOR: binary(J, F, exp, OP_LOGOR); break;
case EXP_LOGAND: binary(J, F, exp, OP_LOGAND); break;
case EXP_BITOR: binary(J, F, exp, OP_BITOR); break;
case EXP_BITXOR: binary(J, F, exp, OP_BITXOR); break;
case EXP_BITAND: binary(J, F, exp, OP_BITAND); break;
@@ -281,6 +296,36 @@ static void cexp(JF, js_Ast *exp)
cexp(J, F, exp->b);
break;
case EXP_LOGOR:
/* if a == true then a else b */
cexp(J, F, exp->a);
emit(J, F, OP_DUP);
end = jump(J, F, OP_JTRUE);
emit(J, F, OP_POP);
cexp(J, F, exp->b);
label(J, F, end);
break;
case EXP_LOGAND:
/* if a == false then a else b */
cexp(J, F, exp->a);
emit(J, F, OP_DUP);
end = jump(J, F, OP_JFALSE);
emit(J, F, OP_POP);
cexp(J, F, exp->b);
label(J, F, end);
break;
case EXP_COND:
cexp(J, F, exp->a);
then = jump(J, F, OP_JTRUE);
cexp(J, F, exp->c);
end = jump(J, F, OP_JUMP);
label(J, F, then);
cexp(J, F, exp->b);
label(J, F, end);
break;
default:
jsC_error(J, exp, "unknown expression");
}
@@ -303,25 +348,9 @@ static void cvardeclist(JF, js_Ast *list)
}
}
static int emitjump(JF, int opcode)
{
int addr = F->len + 1;
emit(J, F, opcode);
emit(J, F, 0);
emit(J, F, 0);
return addr;
}
static void emitlabel(JF, int addr)
{
int dest = F->len;
F->code[addr+0] = (dest >> 8) & 0xFF;
F->code[addr+1] = (dest) & 0xFF;
}
static void cstm(JF, js_Ast *stm)
{
int lelse, lend;
int then, end;
switch (stm->type) {
case STM_BLOCK:
@@ -336,14 +365,19 @@ static void cstm(JF, js_Ast *stm)
break;
case STM_IF:
cexp(J, F, stm->a);
lelse = emitjump(J, F, OP_JFALSE);
cstm(J, F, stm->b);
emitlabel(J, F, lelse);
if (stm->c) {
lend = emitjump(J, F, OP_JUMP);
cexp(J, F, stm->a);
then = jump(J, F, OP_JTRUE);
cstm(J, F, stm->c);
emitlabel(J, F, lend);
end = jump(J, F, OP_JUMP);
label(J, F, then);
cstm(J, F, stm->b);
label(J, F, end);
} else {
cexp(J, F, stm->a);
end = jump(J, F, OP_JFALSE);
cstm(J, F, stm->b);
label(J, F, end);
}
break;
-2
View File
@@ -49,8 +49,6 @@ enum
OP_BITNOT,
OP_LOGNOT,
OP_LOGOR,
OP_LOGAND,
OP_BITOR,
OP_BITXOR,
OP_BITAND,
+4 -4
View File
@@ -458,16 +458,16 @@ static js_Ast *bitor(js_State *J, int notin)
static js_Ast *logand(js_State *J, int notin)
{
js_Ast *a = bitor(J, notin);
while (accept(J, TK_AND))
a = EXP2(LOGAND, a, bitor(J, notin));
if (accept(J, TK_AND))
a = EXP2(LOGAND, a, logand(J, notin));
return a;
}
static js_Ast *logor(js_State *J, int notin)
{
js_Ast *a = logand(J, notin);
while (accept(J, TK_OR))
a = EXP2(LOGOR, a, logand(J, notin));
if (accept(J, TK_OR))
a = EXP2(LOGOR, a, logor(J, notin));
return a;
}