summary refs log tree commit diff stats
path: root/compiler/ccgcalls.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ccgcalls.nim')
-rw-r--r--compiler/ccgcalls.nim92
1 files changed, 62 insertions, 30 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 1c57479ae..570c931fb 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -10,16 +10,30 @@
 type
   TAfterCallActions = tuple[p: BProc, actions: PRope]
 
-proc fixupCall(p: BProc, t: PNode, d: var TLoc, pl: PRope) =
+proc leftAppearsOnRightSide(le, ri: PNode): bool =
+  if le != nil:
+    for i in 1 .. <ri.len:
+      if le.isPartOf(ri[i]) != arNo: return true
+
+proc hasNoInit(call: PNode): bool {.inline.} =
+  result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
+
+proc resetLoc(p: BProc, d: var TLoc) =
+  zeroVar(p, d, containsGarbageCollectedRef(d.t))
+
+proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
   var pl = pl
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(t) > 1: app(pl, ", ")
-      # beware of 'result = p(result)'. We always allocate a temporary:
-      if d.k in {locTemp, locNone}:
-        # We already got a temp. Great, special case it:
+      if sonsLen(ri) > 1: app(pl, ", ")
+      # beware of 'result = p(result)'. We may need to allocate a temporary:
+      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+        # Great, we can use 'd':
         if d.k == locNone: getTemp(p, typ.sons[0], d)
+        elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
+          # reset before pass as 'result' var:
+          resetLoc(p, d)
         app(pl, addrLoc(d))
         app(pl, ")")
         app(p.s[cpsStmts], pl)
@@ -117,40 +131,40 @@ proc genArgNoParam(aca: var TAfterCallActions, n: PNode): PRope =
     initLocExpr(aca.p, n, a)
     result = rdLoc(a)
 
-proc genCall(p: BProc, t: PNode, d: var TLoc) =
+proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   var aca: TAfterCallActions
   aca.p = p
   # this is a hotspot in the compiler
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl = con(op.r, "(")
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   for i in countup(1, length - 1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
     else:
-      app(pl, genArgNoParam(aca, t.sons[i]))
+      app(pl, genArgNoParam(aca, ri.sons[i]))
     if i < length - 1: app(pl, ", ")
-  fixupCall(p, t, d, pl)
+  fixupCall(p, le, ri, d, pl)
   emitAfterCallActions(aca)
 
-proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
+proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op, a: TLoc
   var aca: TAfterCallActions
   aca.p = p
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl: PRope = nil
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   var param = typ.n.sons[1].sym
-  app(pl, genArg(aca, t.sons[1], param))
+  app(pl, genArg(aca, ri.sons[1], param))
   
   if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, "->")
   else: app(pl, ".")
@@ -160,45 +174,45 @@ proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
     else:
-      app(pl, genArgNoParam(aca, t.sons[i]))
+      app(pl, genArgNoParam(aca, ri.sons[i]))
     if i < length - 1: app(pl, ", ")
-  fixupCall(p, t, d, pl)
+  fixupCall(p, le, ri, d, pl)
   emitAfterCallActions(aca)
 
-proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
+proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   # generates a crappy ObjC call
   var op, a: TLoc
   var aca: TAfterCallActions
   aca.p = p
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl = toRope"["
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   if length > 1:
-    app(pl, genArg(aca, t.sons[1], typ.n.sons[1].sym))
+    app(pl, genArg(aca, ri.sons[1], typ.n.sons[1].sym))
     app(pl, " ")
   app(pl, op.r)
   if length > 2:
     app(pl, ": ")
-    app(pl, genArg(aca, t.sons[2], typ.n.sons[2].sym))
+    app(pl, genArg(aca, ri.sons[2], typ.n.sons[2].sym))
   for i in countup(3, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
-      InternalError(t.info, "varargs for objective C method?")
+      InternalError(ri.info, "varargs for objective C method?")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
     app(pl, " ")
     app(pl, param.name.s)
     app(pl, ": ")
-    app(pl, genArg(aca, t.sons[i], param))
+    app(pl, genArg(aca, ri.sons[i], param))
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(t) > 1: app(pl, " ")
+      if sonsLen(ri) > 1: app(pl, " ")
       # beware of 'result = p(result)'. We always allocate a temporary:
       if d.k in {locTemp, locNone}:
         # We already got a temp. Great, special case it:
@@ -230,3 +244,21 @@ proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
     appf(p.s[cpsStmts], ";$n")
   emitAfterCallActions(aca)
 
+proc genCall(p: BProc, e: PNode, d: var TLoc) =
+  if e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
+      e.len >= 2:
+    genInfixCall(p, nil, e, d)
+  elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
+    genNamedParamCall(p, e, d)
+  else:
+    genPrefixCall(p, nil, e, d)
+
+proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
+  if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
+      ri.len >= 2:
+    genInfixCall(p, le, ri, d)
+  elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
+    genNamedParamCall(p, ri, d)
+  else:
+    genPrefixCall(p, le, ri, d)
+