diff options
Diffstat (limited to 'compiler/ccgexprs.nim')
-rw-r--r-- | compiler/ccgexprs.nim | 130 |
1 files changed, 81 insertions, 49 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b6feb78b2..4a3be0027 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -20,7 +20,7 @@ proc int64Literal(i: BiggestInt): PRope = proc uint64Literal(i: uint64): PRope = toRope($i & "ULL") proc intLiteral(i: BiggestInt): PRope = - if (i > low(int32)) and (i <= high(int32)): + if i > low(int32) and i <= high(int32): result = toRope(i) elif i == low(int32): # Nim has the same bug for the same reasons :-) @@ -39,7 +39,7 @@ proc int32Literal(i: int): PRope = proc genHexLiteral(v: PNode): PRope = # hex literals are unsigned in C # so we don't generate hex literals any longer. - if not (v.kind in {nkIntLit..nkUInt64Lit}): + if v.kind notin {nkIntLit..nkUInt64Lit}: internalError(v.info, "genHexLiteral") result = intLiteral(v.intVal) @@ -224,9 +224,9 @@ proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc = proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let newflags = if src.k == locData: - flags + { needToCopy } + flags + {needToCopy} elif tfShallow in dest.t.flags: - flags - { needToCopy } + flags - {needToCopy} else: flags for i in 0 .. <dest.t.len: @@ -240,9 +240,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, if t == nil: return let newflags = if src.k == locData: - flags + { needToCopy } + flags + {needToCopy} elif tfShallow in dest.t.flags: - flags - { needToCopy } + flags - {needToCopy} else: flags case t.kind @@ -328,7 +328,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) of tyObject: # XXX: check for subtyping? - if needsComplexAssignment(ty): + if not isObjLackingTypeField(ty): + genGenericAsgn(p, dest, src, flags) + elif needsComplexAssignment(ty): if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4: discard getTypeDesc(p.module, ty) internalAssert ty.n != nil @@ -655,13 +657,16 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8), getSimpleTypeDesc(p.module, e.typ)])) -proc genDeref(p: BProc, e: PNode, d: var TLoc) = - var a: TLoc - if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}: +proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = + let mt = mapType(e.sons[0].typ) + if mt in {ctArray, ctPtrToArray} and not enforceDeref: # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? + #if e[0].kind != nkBracketExpr: + # message(e.info, warnUser, "CAME HERE " & renderTree(e)) expr(p, e.sons[0], d) else: + var a: TLoc initLocExpr(p, e.sons[0], a) case skipTypes(a.t, abstractInst).kind of tyRef: @@ -671,7 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) = of tyPtr: d.s = OnUnknown # BUGFIX! else: internalError(e.info, "genDeref " & $a.t.kind) - putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)])) + if enforceDeref and mt == ctPtrToArray: + # we lie about the type for better C interop: 'ptr array[3,T]' is + # translated to 'ptr T', but for deref'ing this produces wrong code. + # See tmissingderef. So we get rid of the deref instead. The codegen + # ends up using 'memcpy' for the array assignment, + # so the '&' and '*' cancel out: + putIntoDest(p, d, a.t.sons[0], rdLoc(a)) + else: + putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)])) proc genAddr(p: BProc, e: PNode, d: var TLoc) = # careful 'addr(myptrToArray)' needs to get the ampersand: @@ -794,15 +807,15 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = else: genRecordField(p, e.sons[0], d) -proc genArrayElem(p: BProc, e: PNode, d: var TLoc) = +proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc - initLocExpr(p, e.sons[0], a) - initLocExpr(p, e.sons[1], b) + initLocExpr(p, x, a) + initLocExpr(p, y, b) var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs) var first = intLiteral(firstOrd(ty)) # emit range check: if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags: - if not isConstExpr(e.sons[1]): + if not isConstExpr(y): # semantic pass has already checked for const index expressions if firstOrd(ty) == 0: if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)): @@ -812,26 +825,26 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) = linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n", rdCharLoc(b), first, intLiteral(lastOrd(ty))) else: - let idx = getOrdValue(e.sons[1]) + let idx = getOrdValue(y) if idx < firstOrd(ty) or idx > lastOrd(ty): - localError(e.info, errIndexOutOfBounds) + localError(x.info, errIndexOutOfBounds) d.inheritLocation(a) putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first)) -proc genCStringElem(p: BProc, e: PNode, d: var TLoc) = +proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc - initLocExpr(p, e.sons[0], a) - initLocExpr(p, e.sons[1], b) + initLocExpr(p, x, a) + initLocExpr(p, y, b) var ty = skipTypes(a.t, abstractVarRange) if d.k == locNone: d.s = a.s putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) -proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) = +proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc - initLocExpr(p, e.sons[0], a) - initLocExpr(p, e.sons[1], b) # emit range check: + initLocExpr(p, x, a) + initLocExpr(p, y, b) # emit range check: if optBoundsCheck in p.options: linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n", rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``! @@ -839,10 +852,10 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b))) -proc genSeqElem(p: BProc, e: PNode, d: var TLoc) = +proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) = var a, b: TLoc - initLocExpr(p, e.sons[0], a) - initLocExpr(p, e.sons[1], b) + initLocExpr(p, x, a) + initLocExpr(p, y, b) var ty = skipTypes(a.t, abstractVarRange) if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check: @@ -862,6 +875,17 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b))) +proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) = + var ty = skipTypes(n.sons[0].typ, abstractVarRange) + if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) + case ty.kind + of tyArray, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d) + of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d) + of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d) + of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d) + of tyTuple: genTupleElem(p, n, d) + else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') + proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = # how to generate code? # 'expr1 and expr2' becomes: @@ -903,14 +927,15 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc genEcho(p: BProc, n: PNode) = # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # is threadsafe. + internalAssert n.kind == nkBracket discard lists.includeStr(p.module.headerFiles, "<stdio.h>") var args: PRope = nil var a: TLoc - for i in countup(1, n.len-1): + for i in countup(0, n.len-1): initLocExpr(p, n.sons[i], a) appf(args, ", ($1)->data", [rdLoc(a)]) linefmt(p, cpsStmts, "printf($1$2);$n", - makeCString(repeatStr(n.len-1, "%s") & tnl), args) + makeCString(repeatStr(n.len, "%s") & tnl), args) proc gcUsage(n: PNode) = if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree) @@ -1111,7 +1136,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = ty = getUniqueType(ty.sons[0]) if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr") if it.len == 3 and optFieldCheck in p.options: - genFieldCheck(p, it.sons[2], r, field) + genFieldCheck(p, it.sons[2], tmp2.r, field) app(tmp2.r, ".") app(tmp2.r, field.loc.r) tmp2.k = locTemp @@ -1680,7 +1705,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = discard cgsym(p.module, opr.loc.r.ropeToStr) genCall(p, e, d) of mReset: genReset(p, e) - of mEcho: genEcho(p, e) + of mEcho: genEcho(p, e[1].skipConv) of mArrToSeq: genArrToSeq(p, e, d) of mNLen..mNError: localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s) @@ -1702,7 +1727,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genConstExpr(p: BProc, n: PNode): PRope proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = - if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0): + if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr: var t = getUniqueType(n.typ) discard getTypeDesc(p.module, t) # so that any fields are initialized var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) @@ -1856,18 +1881,34 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = expr(p, n.sons[0], d) # downcast does C++ for us else: var dest = skipTypes(n.typ, abstractPtrs) - var src = skipTypes(n.sons[0].typ, abstractPtrs) + + var arg = n.sons[0] + while arg.kind == nkObjDownConv: arg = arg.sons[0] + + var src = skipTypes(arg.typ, abstractPtrs) var a: TLoc - initLocExpr(p, n.sons[0], a) + initLocExpr(p, arg, a) var r = rdLoc(a) - if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and - n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}: + let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar} + if isRef: app(r, "->Sup") - for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup") - r = con("&", r) else: - for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup") - putIntoDest(p, d, n.typ, r) + app(r, ".Sup") + for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup") + if isRef: + # it can happen that we end up generating '&&x->Sup' here, so we pack + # the '&x->Sup' into a temporary and then those address is taken + # (see bug #837). However sometimes using a temporary is not correct: + # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test + # this by ensuring the destination is also a pointer: + if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}: + getTemp(p, n.typ, d) + linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r) + else: + r = con("&", r) + putIntoDest(p, d, n.typ, r) + else: + putIntoDest(p, d, n.typ, r) proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = var t = getUniqueType(n.typ) @@ -1985,16 +2026,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkCast: genCast(p, n, d) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d) of nkHiddenAddr, nkAddr: genAddr(p, n, d) - of nkBracketExpr: - var ty = skipTypes(n.sons[0].typ, abstractVarRange) - if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) - case ty.kind - of tyArray, tyArrayConstr: genArrayElem(p, n, d) - of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, d) - of tySequence, tyString: genSeqElem(p, n, d) - of tyCString: genCStringElem(p, n, d) - of tyTuple: genTupleElem(p, n, d) - else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') + of nkBracketExpr: genBracketExpr(p, n, d) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d) of nkDotExpr: genRecordField(p, n, d) of nkCheckedFieldExpr: genCheckedRecordField(p, n, d) |