gen(n->nincr); // contin: incr
patch(p1, pc); // test:
- if(n->ntest != N)
- if(n->ntest->ninit != nil)
- genlist(n->ntest->ninit);
bgen(n->ntest, 0, breakpc); // if(!test) goto break
genlist(n->nbody); // body
gjmp(continpc);
p1 = gjmp(P); // goto test
p2 = gjmp(P); // p2: goto else
patch(p1, pc); // test:
- if(n->ntest != N)
- if(n->ntest->ninit != nil)
- genlist(n->ntest->ninit);
bgen(n->ntest, 0, p2); // if(!test) goto p2
genlist(n->nbody); // then
p3 = gjmp(P); // goto done
void* remal(void *p, int32 on, int32 n);
Sym* restrictlookup(char *name, Pkg *pkg);
Node* safeexpr(Node *n, NodeList **init);
+Node* cheapexpr(Node *n, NodeList **init);
int32 setlineno(Node *n);
void setmaxarg(Type *t);
Type* shallow(Type *t);
}
/*
- * return side effect-free appending side effects to init.
+ * return side effect-free n, appending side effects to init.
* result is assignable if n is.
*/
Node*
// make a copy; must not be used as an lvalue
if(islvalue(n))
fatal("missing lvalue case in safeexpr: %N", n);
+ return cheapexpr(n, init);
+}
+
+/*
+ * return side-effect free and cheap n, appending side effects to init.
+ * result may not be assignable.
+ */
+Node*
+cheapexpr(Node *n, NodeList **init)
+{
+ Node *a, *l;
+
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+ }
+
l = nod(OXXX, N, N);
tempname(l, n->type);
a = nod(OAS, l, n);
case OAND:
case OOR:
case OXOR:
- case OANDAND:
- case OOROR:
case OSUB:
case OMUL:
case OEQ:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
+
+ case OANDAND:
+ case OOROR:
+ walkexpr(&n->left, init);
+ // cannot put side effects from n->right on init,
+ // because they cannot run before n->left is checked.
+ // save elsewhere and store on the eventual n->right.
+ ll = nil;
+ walkexpr(&n->right, &ll);
+ n->right->ninit = concat(n->right->ninit, ll);
+ goto ret;
case OPRINT:
case OPRINTN:
goto ret;
}
+ // prepare for rewrite below
+ if(n->etype == OEQ || n->etype == ONE) {
+ n->left = cheapexpr(n->left, init);
+ n->right = cheapexpr(n->right, init);
+ }
+
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", types[TINT], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(n->etype, r, nodintconst(0));
+
+ // quick check of len before full compare for == or !=
+ if(n->etype == OEQ || n->etype == ONE) {
+ if(n->etype == OEQ)
+ r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+ else
+ r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+ typecheck(&r, Erv);
+ walkexpr(&r, nil);
+ }
typecheck(&r, Erv);
n = r;
goto ret;