summaryrefslogtreecommitdiff
path: root/src/cmd/5g/cgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/5g/cgen.c')
-rw-r--r--src/cmd/5g/cgen.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index cf701a50a..8072c3ceb 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -1053,11 +1053,32 @@ stkof(Node *n)
{
Type *t;
Iter flist;
+ int32 off;
switch(n->op) {
case OINDREG:
return n->xoffset;
+ case ODOT:
+ t = n->left->type;
+ if(isptr[t->etype])
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ return off + n->xoffset;
+
+ case OINDEX:
+ t = n->left->type;
+ if(!isfixedarray(t))
+ break;
+ off = stkof(n->left);
+ if(off == -1000 || off == 1000)
+ return off;
+ if(isconst(n->right, CTINT))
+ return off + t->type->width * mpgetfix(n->right->val.u.xval);
+ return 1000;
+
case OCALLMETH:
case OCALLINTER:
case OCALLFUNC:
@@ -1106,6 +1127,17 @@ sgen(Node *n, Node *res, int32 w)
osrc = stkof(n);
odst = stkof(res);
+ if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+ // osrc and odst both on stack, and at least one is in
+ // an unknown position. Could generate code to test
+ // for forward/backward copy, but instead just copy
+ // to a temporary location first.
+ tempname(&tmp, n->type);
+ sgen(n, &tmp, w);
+ sgen(&tmp, res, w);
+ return;
+ }
+
if(osrc % 4 != 0 || odst %4 != 0)
fatal("sgen: non word(4) aligned offset src %d or dst %d", osrc, odst);