summaryrefslogtreecommitdiff
path: root/src/cmd/gc/racewalk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/racewalk.c')
-rw-r--r--src/cmd/gc/racewalk.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index 5d4f62e76..790c7efd7 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -23,6 +23,7 @@ static void racewalklist(NodeList *l, NodeList **init);
static void racewalknode(Node **np, NodeList **init, int wr, int skip);
static int callinstr(Node **n, NodeList **init, int wr, int skip);
static Node* uintptraddr(Node *n);
+static void makeaddable(Node *n);
static Node* basenod(Node *n);
static void foreach(Node *n, void(*f)(Node*, void*), void *c);
static void hascallspred(Node *n, void *c);
@@ -489,6 +490,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
*np = n;
}
n = treecopy(n);
+ makeaddable(n);
f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
*init = list(*init, f);
return 1;
@@ -496,6 +498,37 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
return 0;
}
+// makeaddable returns a node whose memory location is the
+// same as n, but which is addressable in the Go language
+// sense.
+// This is different from functions like cheapexpr that may make
+// a copy of their argument.
+static void
+makeaddable(Node *n)
+{
+ // The arguments to uintptraddr technically have an address but
+ // may not be addressable in the Go sense: for example, in the case
+ // of T(v).Field where T is a struct type and v is
+ // an addressable value.
+ switch(n->op) {
+ case OINDEX:
+ if(isfixedarray(n->left->type))
+ makeaddable(n->left);
+ break;
+ case ODOT:
+ case OXDOT:
+ // Turn T(v).Field into v.Field
+ if(n->left->op == OCONVNOP)
+ n->left = n->left->left;
+ makeaddable(n->left);
+ break;
+ case ODOTPTR:
+ default:
+ // nothing to do
+ break;
+ }
+}
+
static Node*
uintptraddr(Node *n)
{