From cfd8f8b8577ec43a5bdc4269ddda61d071a287fc Mon Sep 17 00:00:00 2001 From: metagn Date: Wed, 6 Nov 2024 07:08:35 +0300 Subject: [PATCH] cbuilder: ccgexprs sweep part 3 (end) (#24410) This finishes `ccgexprs` minus the sweeping refactors like moving `NIM_NIL`, `NU8`, `NCSTRING` etc into constants. --- compiler/cbuilderbase.nim | 2 + compiler/cbuilderdecls.nim | 6 + compiler/cbuilderexprs.nim | 4 +- compiler/cbuilderstmts.nim | 34 ++ compiler/ccgexprs.nim | 762 ++++++++++++++++++++++--------------- 5 files changed, 492 insertions(+), 316 deletions(-) diff --git a/compiler/cbuilderbase.nim b/compiler/cbuilderbase.nim index d6b71645fc..a441d4d687 100644 --- a/compiler/cbuilderbase.nim +++ b/compiler/cbuilderbase.nim @@ -34,6 +34,8 @@ template cIntValue*(val: int64): Snippet = $val template cIntValue*(val: uint64): Snippet = $val template cIntValue*(val: Int128): Snippet = $val +template cUintValue*(val: uint): Snippet = $val & "U" + import std/formatfloat proc addFloatValue*(builder: var Builder, val: float) = diff --git a/compiler/cbuilderdecls.nim b/compiler/cbuilderdecls.nim index 081a197d79..23d91557c6 100644 --- a/compiler/cbuilderdecls.nim +++ b/compiler/cbuilderdecls.nim @@ -381,6 +381,12 @@ template addAnonUnion(obj: var Builder; body: typed) = body obj.add("};\n") +template addUnionType(obj: var Builder; body: typed) = + ## adds a union type i.e. `union { ... }` with fields according to `body` + obj.add "union{\n" + body + obj.add("}") + type DeclVisibility = enum None Extern diff --git a/compiler/cbuilderexprs.nim b/compiler/cbuilderexprs.nim index 58ac496002..bd07f8bee9 100644 --- a/compiler/cbuilderexprs.nim +++ b/compiler/cbuilderexprs.nim @@ -78,10 +78,12 @@ proc initCallBuilder(builder: var Builder, callee: Snippet): CallBuilder = builder.add(callee) builder.add("(") +const cArgumentSeparator = ", " + proc addArgumentSeparator(builder: var Builder) = # no-op on NIFC # used by "single argument" builders - builder.add(", ") + builder.add(cArgumentSeparator) template addArgument(builder: var Builder, call: var CallBuilder, valueBody: typed) = if call.needsComma: diff --git a/compiler/cbuilderstmts.nim b/compiler/cbuilderstmts.nim index aaba9eb7ca..a402f04204 100644 --- a/compiler/cbuilderstmts.nim +++ b/compiler/cbuilderstmts.nim @@ -203,3 +203,37 @@ template addIncr(builder: var Builder, val: Snippet) = template addDecr(builder: var Builder, val: Snippet) = builder.add(val) builder.add("--;\n") + +proc addInPlaceOp(builder: var Builder, binOp: TypedBinaryOp, t: Snippet, a, b: Snippet) = + builder.add(a) + builder.add(' ') + builder.add(typedBinaryOperators[binOp]) + builder.add("= ") + builder.add(b) + builder.add(";\n") + +proc addInPlaceOp(builder: var Builder, binOp: UntypedBinaryOp, a, b: Snippet) = + builder.add(a) + builder.add(' ') + builder.add(untypedBinaryOperators[binOp]) + builder.add("= ") + builder.add(b) + builder.add(";\n") + +proc cInPlaceOp(binOp: TypedBinaryOp, t: Snippet, a, b: Snippet): Snippet = + result = "" + result.add(a) + result.add(' ') + result.add(typedBinaryOperators[binOp]) + result.add("= ") + result.add(b) + result.add(";\n") + +proc cInPlaceOp(binOp: UntypedBinaryOp, a, b: Snippet): Snippet = + result = "" + result.add(a) + result.add(' ') + result.add(untypedBinaryOperators[binOp]) + result.add("= ") + result.add(b) + result.add(";\n") diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 1be7f2dc2b..4bf35dbe1c 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -328,6 +328,9 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) = else: internalError(p.config, a.lode.info, "cannot handle " & $a.t.kind) +template cgCall(p: BProc, name: string, args: varargs[untyped]): untyped = + cCall(cgsymValue(p.module, name), args) + proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating # the assignment operation in C. @@ -378,7 +381,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = let rs = rdLoc(src) p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"), cCast("void**", rad), - cCall(cgsymValue(p.module, "copyString"), rs)) + cgCall(p, "copyString", rs)) of tyProc: if containsGarbageCollectedRef(dest.t): # optimize closure assignment: @@ -558,11 +561,13 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) = d.lode = n d.snippet = r -proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: string) = +proc binaryStmt(p: BProc, e: PNode, d: var TLoc, op: TypedBinaryOp) = if d.k != locNone: internalError(p.config, e.info, "binaryStmt") var a = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) - lineCg(p, cpsStmts, "$1 $2 $3;$n", [rdLoc(a), op, rdLoc(b)]) + let ra = rdLoc(a) + let rb = rdLoc(b) + p.s(cpsStmts).addInPlaceOp(op, getSimpleTypeDesc(p.module, e[1].typ), ra, rb) proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, cpname: string) = if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr") @@ -572,32 +577,37 @@ proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, cpname: string) = let rb = rdLoc(b) p.s(cpsStmts).addCallStmt(cgsymValue(p.module, cpname), bra, rb) -template unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = - if d.k != locNone: internalError(p.config, e.info, "unaryStmt") - var a: TLoc = initLocExpr(p, e[1]) - lineCg(p, cpsStmts, frmt, [rdLoc(a)]) - -template binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) = +template binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: untyped) = assert(e[1].typ != nil) assert(e[2].typ != nil) - var a = initLocExpr(p, e[1]) - var b = initLocExpr(p, e[2]) - putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)])) + block: + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) + let ra {.inject.} = rdLoc(a) + let rb {.inject.} = rdLoc(b) + putIntoDest(p, d, e, frmt) -template binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) = +template binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: untyped) = assert(e[1].typ != nil) assert(e[2].typ != nil) - var a = initLocExpr(p, e[1]) - var b = initLocExpr(p, e[2]) - putIntoDest(p, d, e, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc])) + block: + var a = initLocExpr(p, e[1]) + var b = initLocExpr(p, e[2]) + let ra {.inject.} = rdCharLoc(a) + let rb {.inject.} = rdCharLoc(b) + putIntoDest(p, d, e, frmt) -template unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a: TLoc = initLocExpr(p, e[1]) - putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a)])) +template unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: untyped) = + block: + var a: TLoc = initLocExpr(p, e[1]) + let ra {.inject.} = rdLoc(a) + putIntoDest(p, d, e, frmt) -template unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) = - var a: TLoc = initLocExpr(p, e[1]) - putIntoDest(p, d, e, ropecg(p.module, frmt, [rdCharLoc(a)])) +template unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: untyped) = + block: + var a: TLoc = initLocExpr(p, e[1]) + let ra {.inject.} = rdCharLoc(a) + putIntoDest(p, d, e, frmt) template binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; cpname: string): Rope = @@ -1460,13 +1470,13 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = let ra = rdLoc(a) if skipTypes(e[i + 1].typ, abstractVarRange).kind == tyChar: inc(L) - appends.add(cCall(cgsymValue(p.module, "appendChar"), rstmp, ra)) + appends.add(cgCall(p, "appendChar", rstmp, ra)) else: if e[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, e[i + 1].strVal.len) else: lens.add(lenExpr(p, a)) - appends.add(cCall(cgsymValue(p.module, "appendString"), rstmp, ra)) + appends.add(cgCall(p, "appendString", rstmp, ra)) var exprL = cIntValue(L) for len in lens: exprL = cOp(Add, "NI", exprL, len) @@ -1507,13 +1517,13 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = let ra = rdLoc(a) if skipTypes(e[i + 2].typ, abstractVarRange).kind == tyChar: inc(L) - appends.add(cCall(cgsymValue(p.module, "appendChar"), rsd, ra)) + appends.add(cgCall(p, "appendChar", rsd, ra)) else: if e[i + 2].kind in {nkStrLit..nkTripleStrLit}: inc(L, e[i + 2].strVal.len) else: lens.add(lenExpr(p, a)) - appends.add(cCall(cgsymValue(p.module, "appendString"), rsd, ra)) + appends.add(cgCall(p, "appendString", rsd, ra)) var exprL = cIntValue(L) for len in lens: exprL = cOp(Add, "NI", exprL, len) @@ -1525,7 +1535,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = else: call = initLoc(locCall, e, OnHeap) let rd = rdLoc(dest) - call.snippet = cCall(cgsymValue(p.module, "resizeString"), + call.snippet = cgCall(p, "resizeString", rd, exprL) genAssignment(p, dest, call, {}) @@ -1544,7 +1554,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = var call = initLoc(locCall, e, OnHeap) let ra = rdLoc(a) call.snippet = cCast(getTypeDesc(p.module, e[1].typ), - cCall(cgsymValue(p.module, "incrSeqV3"), + cgCall(p, "incrSeqV3", if not p.module.compileToCpp: cCast(ptrType("TGenericSeq"), ra) else: ra, genTypeInfoV1(p.module, seqType, e.info))) # emit the write barrier if required, but we can always move here, so @@ -1611,7 +1621,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = # newObjRC1() would clash with unsureAsgnRef() - which is used by gcGo to # implement the write barrier b.snippet = cCast(getTypeDesc(p.module, typ), - cCall(cgsymValue(p.module, "newObj"), + cgCall(p, "newObj", ti, sizeExpr)) let raa = addrLoc(p.config, a) @@ -1622,7 +1632,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = else: # use newObjRC1 as an optimization b.snippet = cCast(getTypeDesc(p.module, typ), - cCall(cgsymValue(p.module, "newObjRC1"), + cgCall(p, "newObjRC1", ti, sizeExpr)) let ra = a.rdLoc @@ -1630,7 +1640,7 @@ proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope; needsInit: bool) = p.s(cpsStmts).addAssignment(ra, rb) else: b.snippet = cCast(getTypeDesc(p.module, typ), - cCall(cgsymValue(p.module, "newObj"), + cgCall(p, "newObj", ti, sizeExpr)) genAssignment(p, a, b, {}) @@ -1666,7 +1676,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = if p.config.selectedGC == gcGo: # we need the write barrier call.snippet = cCast(st, - cCall(cgsymValue(p.module, "newSeq"), typinfo, length)) + cgCall(p, "newSeq", typinfo, length)) let rad = addrLoc(p.config, dest) let rc = call.rdLoc p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"), @@ -1674,7 +1684,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = rc) else: call.snippet = cCast(st, - cCall(cgsymValue(p.module, "newSeqRC1"), typinfo, length)) + cgCall(p, "newSeqRC1", typinfo, length)) let rd = dest.rdLoc let rc = call.rdLoc p.s(cpsStmts).addAssignment(rd, rc) @@ -1685,7 +1695,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = let st = getTypeDesc(p.module, seqtype) let typinfo = genTypeInfoV1(p.module, seqtype, dest.lode.info) call.snippet = cCast(st, - cCall(cgsymValue(p.module, "newSeq"), typinfo, length)) + cgCall(p, "newSeq", typinfo, length)) genAssignment(p, dest, call, {}) proc genNewSeq(p: BProc, e: PNode) = @@ -1729,7 +1739,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = if d.k == locNone: d = getTemp(p, e.typ, needsInit=false) # bug #22560 let ra = a.rdLoc let dres = cCast(getTypeDesc(p.module, seqtype), - cCall(cgsymValue(p.module, "nimNewSeqOfCap"), + cgCall(p, "nimNewSeqOfCap", genTypeInfoV1(p.module, seqtype, e.info), ra)) putIntoDest(p, d, e, dres) @@ -1914,21 +1924,20 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) = for i in 0..Field1-1)") - else: - unaryExpr(p, e, d, "($1.Field1-1)") + unaryExpr(p, e, d, cOp(Sub, "NI", lenA, cIntValue(1))) else: - if isDeref: - unaryExpr(p, e, d, "$1->Field1") - else: - unaryExpr(p, e, d, "$1.Field1") + unaryExpr(p, e, d, lenA) of tyCstring: - if op == mHigh: unaryExpr(p, e, d, "(#nimCStrLen($1)-1)") - else: unaryExpr(p, e, d, "#nimCStrLen($1)") + if op == mHigh: + unaryExpr(p, e, d, cOp(Sub, "NI", cgCall(p, "nimCStrLen", ra), cIntValue(1))) + else: + unaryExpr(p, e, d, cgCall(p, "nimCStrLen", ra)) of tyString: var a: TLoc = initLocExpr(p, e[1]) var x = lenExpr(p, a) - if op == mHigh: x = "($1-1)" % [x] + if op == mHigh: x = cOp(Sub, "NI", x, cIntValue(1)) putIntoDest(p, d, e, x) of tySequence: # we go through a temporary here because people write bullshit code. var tmp: TLoc = getIntTemp(p) var a = initLocExpr(p, e[1]) var x = lenExpr(p, a) - if op == mHigh: x = "($1-1)" % [x] + if op == mHigh: x = cOp(Sub, "NI", x, cIntValue(1)) p.s(cpsStmts).addAssignment(tmp.snippet, x) putIntoDest(p, d, e, tmp.snippet) of tyArray: # YYY: length(sideeffect) is optimized away incorrectly? - if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(p.config, typ))) - else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ))) + if op == mHigh: putIntoDest(p, d, e, cIntValue(lastOrd(p.config, typ))) + else: putIntoDest(p, d, e, cIntValue(lengthOrd(p.config, typ))) else: internalError(p.config, e.info, "genArrayLen()") proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = @@ -2185,17 +2207,16 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = let t = skipTypes(e[1].typ, {tyVar}) var call = initLoc(locCall, e, OnHeap) + let ra = rdLoc(a) + let rb = rdLoc(b) + let rt = getTypeDesc(p.module, t) + let rti = genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info) + var pExpr: Snippet if not p.module.compileToCpp: - const setLenPattern = "($3) #setLengthSeqV2(($1)?&($1)->Sup:NIM_NIL, $4, $2)" - call.snippet = ropecg(p.module, setLenPattern, [ - rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) - + pExpr = cIfExpr(ra, cAddr(derefField(ra, "Sup")), "NIM_NIL") else: - const setLenPattern = "($3) #setLengthSeqV2($1, $4, $2)" - call.snippet = ropecg(p.module, setLenPattern, [ - rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), - genTypeInfoV1(p.module, t.skipTypes(abstractInst), e.info)]) + pExpr = ra + call.snippet = cCast(rt, cgCall(p, "setLengthSeqV2", pExpr, rti, rb)) genAssignment(p, a, call, {}) gcUsage(p.config, e) @@ -2209,8 +2230,7 @@ proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = var b = initLocExpr(p, e[2]) var call = initLoc(locCall, e, OnHeap) - call.snippet = ropecg(p.module, "#setLengthStr($1, $2)", [ - rdLoc(a), rdLoc(b)]) + call.snippet = cgCall(p, "setLengthStr", rdLoc(a), rdLoc(b)) genAssignment(p, a, call, {}) gcUsage(p.config, e) @@ -2228,17 +2248,14 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = genAssignment(p, a, b, {}) genAssignment(p, b, tmp, {}) -proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType; result: var Rope) = +proc rdSetElemLoc(conf: ConfigRef; a: TLoc, typ: PType; result: var Snippet) = # read a location of an set element; it may need a subtraction operation # before the set operation - result.add "(" - result.add rdCharLoc(a) + result = rdCharLoc(a) let setType = typ.skipTypes(abstractPtrs) assert(setType.kind == tySet) if firstOrd(conf, setType) != 0: - result.add " - " - result.add rope(firstOrd(conf, setType)) - result.add ")" + result = cOp(Sub, "NU", result, cIntValue(firstOrd(conf, setType))) proc fewCmps(conf: ConfigRef; s: PNode): bool = # this function estimates whether it is better to emit code @@ -2251,26 +2268,49 @@ proc fewCmps(conf: ConfigRef; s: PNode): bool = else: result = s.len <= 8 # 8 seems to be a good value -template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = - var elem = newRopeAppender() +template binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: untyped) = + var elem {.inject.}: Snippet = "" rdSetElemLoc(p.config, b, a.t, elem) - putIntoDest(p, d, e, frmt % [rdLoc(a), elem]) + let ra {.inject.} = rdLoc(a) + putIntoDest(p, d, e, frmt) proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = - case int(getSize(p.config, skipTypes(e[1].typ, abstractVar))) - of 1: binaryExprIn(p, e, a, b, d, "(($1 &((NU8)1<<((NU)($2)&7U)))!=0)") - of 2: binaryExprIn(p, e, a, b, d, "(($1 &((NU16)1<<((NU)($2)&15U)))!=0)") - of 4: binaryExprIn(p, e, a, b, d, "(($1 &((NU32)1<<((NU)($2)&31U)))!=0)") - of 8: binaryExprIn(p, e, a, b, d, "(($1 &((NU64)1<<((NU)($2)&63U)))!=0)") - else: binaryExprIn(p, e, a, b, d, "(($1[(NU)($2)>>3] &(1U<<((NU)($2)&7U)))!=0)") + let s = int(getSize(p.config, skipTypes(e[1].typ, abstractVar))) + case s + of 1, 2, 4, 8: + let mask = s * 8 - 1 + let rt = "NU" & $(s * 8) + binaryExprIn(p, e, a, b, d, + # ((a & ((NU8) 1 << ((NU) elem & 7U))) != 0) + # ((a & ((NU16) 1 << ((NU) elem & 15U))) != 0) + # ((a & ((NU32) 1 << ((NU) elem & 31U))) != 0) + # ((a & ((NU64) 1 << ((NU) elem & 63U))) != 0) + cOp(NotEqual, + cOp(BitAnd, rt, ra, + cOp(Shl, rt, cCast(rt, cIntValue(1)), + cOp(BitAnd, "NU", cCast("NU", elem), cUintValue(mask.uint)))), + cIntValue(0))) + else: + # ((a[(NU)(elem)>>3] &(1U<<((NU)(elem)&7U)))!=0) + binaryExprIn(p, e, a, b, d, + cOp(NotEqual, + cOp(BitAnd, "NU8", + subscript(ra, cOp(Shr, "NU", cCast("NU", elem), cIntValue(3))), + cOp(Shl, "NU8", + cUintValue(1), + cOp(BitAnd, "NU", + cCast("NU", elem), + cUintValue(7)))), + cIntValue(0))) -template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) = +template binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: untyped) = assert(d.k == locNone) var a = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) - var elem = newRopeAppender() + var elem {.inject.}: Snippet = "" rdSetElemLoc(p.config, b, a.t, elem) - lineF(p, cpsStmts, frmt, [rdLoc(a), elem]) + let ra {.inject.} = rdLoc(a) + p.s(cpsStmts).add(frmt) proc genInOp(p: BProc, e: PNode, d: var TLoc) = var a, b, x, y: TLoc @@ -2286,19 +2326,29 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = a = initLocExpr(p, ea) b = initLoc(locExpr, e, OnUnknown) if e[1].len > 0: - b.snippet = rope("(") + var val: Snippet = "" for i in 0..= $2 && $1 <= $3", - [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)]) + let rca = rdCharLoc(a) + let rcx = rdCharLoc(x) + let rcy = rdCharLoc(y) + currentExpr = cOp(And, + cOp(GreaterEqual, rca, rcx), + cOp(LessEqual, rca, rcy)) else: x = initLocExpr(p, it) - b.snippet.addf("$1 == $2", [rdCharLoc(a), rdCharLoc(x)]) - if i < e[1].len - 1: b.snippet.add(" || ") - b.snippet.add(")") + let rca = rdCharLoc(a) + let rcx = rdCharLoc(x) + currentExpr = cOp(Equal, rca, rcx) + if val.len == 0: + val = currentExpr + else: + val = cOp(Or, val, currentExpr) + b.snippet = val else: # handle the case of an empty set b.snippet = cIntValue(0) @@ -2311,93 +2361,123 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = genInExprAux(p, e, a, b, d) proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = - const - lookupOpr: array[mLeSet..mXorSet, string] = [ - "for ($1 = 0; $1 < $2; $1++) { $n" & - " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & - " if (!$3) break;}$n", - "for ($1 = 0; $1 < $2; $1++) { $n" & - " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & - " if (!$3) break;}$n" & - "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n", - "&", - "|", - "& ~", - "^"] var a, b: TLoc var i: TLoc var setType = skipTypes(e[1].typ, abstractVar) var size = int(getSize(p.config, setType)) case size of 1, 2, 4, 8: + let bits = size * 8 + let rt = "NU" & $bits case op of mIncl: - case size - of 1: binaryStmtInExcl(p, e, d, "$1 |= ((NU8)1)<<(($2) & 7);$n") - of 2: binaryStmtInExcl(p, e, d, "$1 |= ((NU16)1)<<(($2) & 15);$n") - of 4: binaryStmtInExcl(p, e, d, "$1 |= ((NU32)1)<<(($2) & 31);$n") - of 8: binaryStmtInExcl(p, e, d, "$1 |= ((NU64)1)<<(($2) & 63);$n") - else: assert(false, $size) + let mask = bits - 1 + binaryStmtInExcl(p, e, d, + cInPlaceOp(BitOr, rt, ra, + cOp(Shl, rt, cCast(rt, cIntValue(1)), + cOp(BitAnd, "NU", elem, cIntValue(mask))))) of mExcl: - case size - of 1: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU8)1) << (($2) & 7));$n") - of 2: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU16)1) << (($2) & 15));$n") - of 4: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU32)1) << (($2) & 31));$n") - of 8: binaryStmtInExcl(p, e, d, "$1 &= ~(((NU64)1) << (($2) & 63));$n") - else: assert(false, $size) + let mask = bits - 1 + binaryStmtInExcl(p, e, d, + cInPlaceOp(BitAnd, rt, ra, cOp(BitNot, rt, + cOp(Shl, rt, cCast(rt, cIntValue(1)), + cOp(BitAnd, "NU", elem, cIntValue(mask)))))) of mCard: - if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)") - else: unaryExprChar(p, e, d, "#countBits64($1)") - of mLtSet: binaryExprChar(p, e, d, "((($1 & ~ $2)==0)&&($1 != $2))") - of mLeSet: binaryExprChar(p, e, d, "(($1 & ~ $2)==0)") - of mEqSet: binaryExpr(p, e, d, "($1 == $2)") - of mMulSet: binaryExpr(p, e, d, "($1 & $2)") - of mPlusSet: binaryExpr(p, e, d, "($1 | $2)") - of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)") - of mXorSet: binaryExpr(p, e, d, "($1 ^ $2)") + let name = if size <= 4: "countBits32" else: "countBits64" + unaryExprChar(p, e, d, cgCall(p, name, ra)) + of mLtSet: + binaryExprChar(p, e, d, cOp(And, + cOp(Equal, cOp(BitAnd, rt, ra, cOp(BitNot, rt, rb)), cIntValue(0)), + cOp(NotEqual, ra, rb))) + of mLeSet: + binaryExprChar(p, e, d, + cOp(Equal, cOp(BitAnd, rt, ra, cOp(BitNot, rt, rb)), cIntValue(0))) + of mEqSet: binaryExpr(p, e, d, cOp(Equal, ra, rb)) + of mMulSet: binaryExpr(p, e, d, cOp(BitAnd, rt, ra, rb)) + of mPlusSet: binaryExpr(p, e, d, cOp(BitOr, rt, ra, rb)) + of mMinusSet: binaryExpr(p, e, d, cOp(BitAnd, rt, ra, cOp(BitNot, rt, rb))) + of mXorSet: binaryExpr(p, e, d, cOp(BitXor, rt, ra, rb)) of mInSet: genInOp(p, e, d) else: internalError(p.config, e.info, "genSetOp()") else: case op - of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n") - of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n") + of mIncl: + binaryStmtInExcl(p, e, d, cInPlaceOp(BitOr, "NU8", + subscript(ra, cOp(Shr, "NU", cCast("NU", elem), cIntValue(3))), + cOp(Shl, "NU8", cUintValue(1), cOp(BitAnd, "NU", elem, cUintValue(7))))) + of mExcl: + binaryStmtInExcl(p, e, d, cInPlaceOp(BitAnd, "NU8", + subscript(ra, cOp(Shr, "NU", cCast("NU", elem), cIntValue(3))), + cOp(BitNot, "NU8", + cOp(Shl, "NU8", cUintValue(1), cOp(BitAnd, "NU", elem, cUintValue(7)))))) of mCard: var a: TLoc = initLocExpr(p, e[1]) - putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size])) + let rca = rdCharLoc(a) + putIntoDest(p, d, e, cgCall(p, "cardSet", rca, cIntValue(size))) of mLtSet, mLeSet: i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, e[1]) b = initLocExpr(p, e[2]) if d.k == locNone: d = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyBool)) + discard "for ($1 = 0; $1 < $2; $1++) { $n" & + " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & + " if (!$3) break;}$n" + let ri = rdLoc(i) + let rd = rdLoc(d) + let ra = rdLoc(a) + let rb = rdLoc(b) + p.s(cpsStmts).addForRangeExclusive(ri, cIntValue(0), cIntValue(size)): + p.s(cpsStmts).addAssignment(rd, cOp(Equal, + cOp(BitAnd, "NU8", + subscript(ra, ri), + cOp(BitNot, "NU8", subscript(rb, ri))), + cIntValue(0))) + p.s(cpsStmts).addSingleIfStmt(cOp(Not, rd)): + p.s(cpsStmts).addBreak() if op == mLtSet: - linefmt(p, cpsStmts, lookupOpr[mLtSet], - [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) - else: - linefmt(p, cpsStmts, lookupOpr[mLeSet], - [rdLoc(i), size, rdLoc(d), rdLoc(a), rdLoc(b)]) + discard "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n" + p.s(cpsStmts).addSingleIfStmt(rd): + p.s(cpsStmts).addAssignment(rd, cOp(NotEqual, + cgCall(p, "nimCmpMem", ra, rb, cIntValue(size)), + cIntValue(0))) of mEqSet: assert(e[1].typ != nil) assert(e[2].typ != nil) var a = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) - putIntoDest(p, d, e, ropecg(p.module, "(#nimCmpMem($1, $2, $3)==0)", [a.rdCharLoc, b.rdCharLoc, size])) + let rca = a.rdCharLoc + let rcb = b.rdCharLoc + putIntoDest(p, d, e, cOp(Equal, + cgCall(p, "nimCmpMem", rca, rcb, cIntValue(size)), + cIntValue(0))) of mMulSet, mPlusSet, mMinusSet, mXorSet: # we inline the simple for loop for better code generation: i = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, e[1]) b = initLocExpr(p, e[2]) if d.k == locNone: d = getTemp(p, setType) - lineF(p, cpsStmts, - "for ($1 = 0; $1 < $2; $1++) $n" & - " $3[$1] = $4[$1] $6 $5[$1];$n", [ - rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b), - rope(lookupOpr[op])]) + let ri = rdLoc(i) + let rd = rdLoc(d) + let ra = rdLoc(a) + let rb = rdLoc(b) + p.s(cpsStmts).addForRangeExclusive(ri, cIntValue(0), cIntValue(size)): + p.s(cpsStmts).addAssignmentWithValue(subscript(rd, ri)): + let x = subscript(ra, ri) + let y = subscript(rb, ri) + let lookup = + case op + of mMulSet: cOp(BitAnd, "NU8", x, y) + of mPlusSet: cOp(BitOr, "NU8", x, y) + of mMinusSet: cOp(BitAnd, "NU8", x, cOp(BitNot, "NU8", y)) + of mXorSet: cOp(BitXor, "NU8", x, y) + else: "" # unreachable + p.s(cpsStmts).add(lookup) of mInSet: genInOp(p, e, d) else: internalError(p.config, e.info, "genSetOp") proc genOrd(p: BProc, e: PNode, d: var TLoc) = - unaryExprChar(p, e, d, "$1") + unaryExprChar(p, e, d, ra) proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = const @@ -2435,7 +2515,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = # (* (destType*) (&val)) putIntoDest(p, d, e, cDeref(cCast(ptrType(destTyp), wrapPar(cAddr(val)))), a.storage) elif etyp.kind == tyBool and srcTyp.kind in IntegralTypes: - putIntoDest(p, d, e, "(($1) != 0)" % [rdCharLoc(a)], a.storage) + putIntoDest(p, d, e, cOp(NotEqual, rdCharLoc(a), cIntValue(0)), a.storage) else: if etyp.kind == tyPtr: # generates the definition of structs for casts like cast[ptr object](addr x)[] @@ -2460,12 +2540,21 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = let destsize = getSize(p.config, destt) let srcsize = getSize(p.config, srct) + let srcTyp = getTypeDesc(p.module, e[1].typ) + let destTyp = getTypeDesc(p.module, e.typ) if destsize > srcsize: - linefmt(p, cpsLocals, "union { $1 dest; $2 source; } LOC$3;$n #nimZeroMem(&LOC$3, sizeof(LOC$3));$n", - [getTypeDesc(p.module, e.typ), getTypeDesc(p.module, e[1].typ), lbl]) + p.s(cpsLocals).addVarWithType(kind = Local, name = "LOC" & lbl): + p.s(cpsLocals).addUnionType(): + p.s(cpsLocals).addField(name = "dest", typ = destTyp) + p.s(cpsLocals).addField(name = "source", typ = srcTyp) + p.s(cpsLocals).addCallStmt(cgsymValue(p.module, "nimZeroMem"), + cAddr("LOC" & lbl), + cSizeof("LOC" & lbl)) else: - linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", - [getTypeDesc(p.module, e[1].typ), getTypeDesc(p.module, e.typ), lbl]) + p.s(cpsLocals).addVarWithType(kind = Local, name = "LOC" & lbl): + p.s(cpsLocals).addUnionType(): + p.s(cpsLocals).addField(name = "source", typ = srcTyp) + p.s(cpsLocals).addField(name = "dest", typ = destTyp) tmp.k = locExpr tmp.lode = lodeTyp srct tmp.storage = OnStack @@ -2492,11 +2581,11 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = genLiteral(p, n[1], dest, first) var last = newBuilder("") genLiteral(p, n[2], dest, last) - linefmt(p, cpsStmts, "if ($1 > ($5)($3)){ #raiseRangeErrorNoArgs(); ", - [rdCharLoc(a), extract(first), extract(last), - raiser, getTypeDesc(p.module, n0t)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + let rca = rdCharLoc(a) + let rt = getTypeDesc(p.module, n0t) + p.s(cpsStmts).addSingleIfStmt(cOp(GreaterThan, rca, cCast(rt, extract(last)))): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseRangeErrorNoArgs")) + raiseInstr(p, p.s(cpsStmts)) else: let raiser = @@ -2506,20 +2595,23 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) = else: "raiseRangeErrorI" cgsym(p.module, raiser) - let boundaryCast = - if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64}: - "(NI64)" - else: - "" var first = newBuilder("") genLiteral(p, n[1], dest, first) var last = newBuilder("") genLiteral(p, n[2], dest, last) - linefmt(p, cpsStmts, "if ($5($1) < $2 || $5($1) > $3){ $4($1, $2, $3); ", - [rdCharLoc(a), extract(first), extract(last), - raiser, boundaryCast]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + let rca = rdCharLoc(a) + let boundRca = + if n0t.skipTypes(abstractVarRange).kind in {tyUInt, tyUInt32, tyUInt64}: + cCast("NI64", rca) + else: + rca + let firstVal = extract(first) + let lastVal = extract(last) + p.s(cpsStmts).addSingleIfStmt(cOp(Or, + cOp(LessThan, boundRca, firstVal), + cOp(GreaterThan, boundRca, lastVal))): + p.s(cpsStmts).addCallStmt(raiser, rca, firstVal, lastVal) + raiseInstr(p, p.s(cpsStmts)) if sameBackendTypeIgnoreRange(dest, n[0].typ): # don't cast so an address can be taken for `var` conversions @@ -2540,21 +2632,21 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) = proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc = initLocExpr(p, n[0]) putIntoDest(p, d, n, - ropecg(p.module, "#nimToCStringConv($1)", [rdLoc(a)]), -# "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc], - a.storage) + cgCall(p, "nimToCStringConv", rdLoc(a)), +# "($1 ? $1->data : (NCSTRING)\"\")" % [a.rdLoc], + a.storage) proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = var a: TLoc = initLocExpr(p, n[0]) if p.module.compileToCpp: # fixes for const qualifier; bug #12703; bug #19588 putIntoDest(p, d, n, - ropecg(p.module, "#cstrToNimstr((NCSTRING) $1)", [rdLoc(a)]), - a.storage) + cgCall(p, "cstrToNimstr", cCast("NCSTRING", rdLoc(a))), + a.storage) else: putIntoDest(p, d, n, - ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), - a.storage) + cgCall(p, "cstrToNimstr", rdLoc(a)), + a.storage) gcUsage(p.config, n) proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = @@ -2563,34 +2655,39 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = var b = e[2] if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": x = initLocExpr(p, e[2]) - putIntoDest(p, d, e, - ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) + let lx = lenExpr(p, x) + putIntoDest(p, d, e, cOp(Equal, lx, cIntValue(0))) elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "": x = initLocExpr(p, e[1]) - putIntoDest(p, d, e, - ropecg(p.module, "($1 == 0)", [lenExpr(p, x)])) + let lx = lenExpr(p, x) + putIntoDest(p, d, e, cOp(Equal, lx, cIntValue(0))) else: - binaryExpr(p, e, d, "#eqStrings($1, $2)") + binaryExpr(p, e, d, cgCall(p, "eqStrings", ra, rb)) proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) = if {optNaNCheck, optInfCheck} * p.options != {}: - const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"] + const opr: array[mAddF64..mDivF64, TypedBinaryOp] = [Add, Sub, Mul, Div] assert(e[1].typ != nil) assert(e[2].typ != nil) var a = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) - putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))", - [opr[m], rdLoc(a), rdLoc(b), - getSimpleTypeDesc(p.module, e[1].typ)])) + let ra = rdLoc(a) + let rb = rdLoc(b) + let rt = getSimpleTypeDesc(p.module, e[1].typ) + putIntoDest(p, d, e, cOp(opr[m], rt, cCast(rt, ra), cCast(rt, rb))) if optNaNCheck in p.options: - linefmt(p, cpsStmts, "if ($1 != $1){ #raiseFloatInvalidOp(); ", [rdLoc(d)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + let rd = rdLoc(d) + p.s(cpsStmts).addSingleIfStmt(cOp(NotEqual, rd, rd)): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseFloatInvalidOp")) + raiseInstr(p, p.s(cpsStmts)) if optInfCheck in p.options: - linefmt(p, cpsStmts, "if ($1 != 0.0 && $1*0.5 == $1) { #raiseFloatOverflow($1); ", [rdLoc(d)]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + let rd = rdLoc(d) + p.s(cpsStmts).addSingleIfStmt(cOp(And, + cOp(NotEqual, rd, cFloatValue(0.0)), + cOp(Equal, cOp(Mul, rt, rd, cFloatValue(0.5)), rd))): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseFloatOverflow"), rd) + raiseInstr(p, p.s(cpsStmts)) else: binaryArith(p, e, d, m) @@ -2632,20 +2729,19 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) = case skipTypes(a.t, abstractVar+{tyStatic}).kind of tyOpenArray, tyVarargs: # todo fixme generated `wasMoved` hooks for # openarrays, but it probably shouldn't? + let ra = rdLoc(a) var s: string if reifiedOpenArray(a.lode): if a.t.kind in {tyVar, tyLent}: - s = "$1->Field0, $1->Field1" % [rdLoc(a)] + s = derefField(ra, "Field0") & cArgumentSeparator & derefField(ra, "Field1") else: - s = "$1.Field0, $1.Field1" % [rdLoc(a)] + s = dotField(ra, "Field0") & cArgumentSeparator & dotField(ra, "Field1") else: - s = "$1, $1Len_0" % [rdLoc(a)] - linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), s]) + s = ra & cArgumentSeparator & ra & "Len_0" + p.s(cpsStmts).addCallStmt(rdLoc(b), s) else: - if p.module.compileToCpp: - linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), rdLoc(a)]) - else: - linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), byRefLoc(p, a)]) + let val = if p.module.compileToCpp: rdLoc(a) else: byRefLoc(p, a) + p.s(cpsStmts).addCallStmt(rdLoc(b), val) else: if n[1].kind == nkSym and isSinkParam(n[1].sym): var tmp = getTemp(p, n[1].typ.skipTypes({tySink})) @@ -2663,20 +2759,28 @@ proc genDestroy(p: BProc; n: PNode) = case t.kind of tyString: var a: TLoc = initLocExpr(p, arg) - if optThreads in p.config.globalOptions: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #deallocShared($1.p);$n" & - "}$n", [rdLoc(a)]) - else: - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #dealloc($1.p);$n" & - "}$n", [rdLoc(a)]) + let ra = rdLoc(a) + let rp = dotField(ra, "p") + p.s(cpsStmts).addSingleIfStmt( + cOp(And, rp, + cOp(Not, cOp(BitAnd, "NI", + derefField(rp, "cap"), + "NIM_STRLIT_FLAG")))): + let fn = if optThreads in p.config.globalOptions: "deallocShared" else: "dealloc" + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, fn), rp) of tySequence: var a: TLoc = initLocExpr(p, arg) - linefmt(p, cpsStmts, "if ($1.p && !($1.p->cap & NIM_STRLIT_FLAG)) {$n" & - " #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" & - "}$n", - [rdLoc(a), getTypeDesc(p.module, t.elementType)]) + let ra = rdLoc(a) + let rp = dotField(ra, "p") + let rt = getTypeDesc(p.module, t.elementType) + p.s(cpsStmts).addSingleIfStmt( + cOp(And, rp, + cOp(Not, cOp(BitAnd, "NI", + derefField(rp, "cap"), + "NIM_STRLIT_FLAG")))): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "alignedDealloc"), + rp, + cAlignof(rt)) else: discard "nothing to do" else: let t = n[1].typ.skipTypes(abstractVar) @@ -2736,7 +2840,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mGetTypeInfoV2: genGetTypeInfoV2(p, e, d) of mSwap: genSwap(p, e, d) of mInc, mDec: - const opr: array[mInc..mDec, string] = ["+=", "-="] + const opr: array[mInc..mDec, TypedBinaryOp] = [Add, Sub] const fun64: array[mInc..mDec, string] = ["nimAddInt64", "nimSubInt64"] const fun: array[mInc..mDec, string] = ["nimAddInt","nimSubInt"] let underlying = skipTypes(e[1].typ, {tyGenericInst, tyAlias, tySink, tyVar, tyLent, tyRange, tyDistinct}) @@ -2763,7 +2867,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = var call = initLoc(locCall, e, OnHeap) var dest = initLocExpr(p, e[1]) var b = initLocExpr(p, e[2]) - call.snippet = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) + call.snippet = cgCall(p, "addChar", rdLoc(dest), rdLoc(b)) genAssignment(p, dest, call, {}) of mAppendStrStr: genStrAppend(p, e, d) of mAppendSeqElem: @@ -2773,17 +2877,25 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: genSeqElemAppend(p, e, d) of mEqStr: genStrEquals(p, e, d) - of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)") - of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)") + of mLeStr: + binaryExpr(p, e, d, cOp(LessEqual, + cgCall(p, "cmpStrings", ra, rb), + cIntValue(0))) + of mLtStr: + binaryExpr(p, e, d, cOp(LessThan, + cgCall(p, "cmpStrings", ra, rb), + cIntValue(0))) of mIsNil: genIsNil(p, e, d) - of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)") - of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)") + of mBoolToStr: + genDollarIt(p, e, d, cgCall(p, "nimBoolToStr", it)) + of mCharToStr: + genDollarIt(p, e, d, cgCall(p, "nimCharToStr", it)) of mCStrToStr: if p.module.compileToCpp: # fixes for const qualifier; bug #12703; bug #19588 - genDollar(p, e, d, "#cstrToNimstr((NCSTRING) $1)") + genDollarIt(p, e, d, cgCall(p, "cstrToNimstr", cCast("NCSTRING", it))) else: - genDollar(p, e, d, "#cstrToNimstr($1)") + genDollarIt(p, e, d, cgCall(p, "cstrToNimstr", it)) of mStrToStr, mUnown: expr(p, e[1], d) of generatedMagics: genCall(p, e, d) of mEnumToStr: @@ -2809,10 +2921,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mNewSeqOfCap: genNewSeqOfCap(p, e, d) of mSizeOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t, dkVar)]) + putIntoDest(p, d, e, cCast("NI", cSizeof(getTypeDesc(p.module, t, dkVar)))) of mAlignOf: let t = e[1].typ.skipTypes({tyTypeDesc}) - putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t, dkVar)]) + putIntoDest(p, d, e, cCast("NI", cAlignof(getTypeDesc(p.module, t, dkVar)))) of mOffsetOf: var dotExpr: PNode if e[1].kind == nkDotExpr: @@ -2828,17 +2940,23 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if t.kind == tyTuple: "Field" & rope(dotExpr[1].sym.position) else: dotExpr[1].sym.loc.snippet - putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [tname, member]) + putIntoDest(p,d,e, cCast("NI", cOffsetof(tname, member))) of mChr: genSomeCast(p, e, d) of mOrd: genOrd(p, e, d) of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: genArrayLen(p, e, d, op) of mGCref: # only a magic for the old GCs - unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n") + var a: TLoc = initLocExpr(p, e[1]) + let ra = rdLoc(a) + p.s(cpsStmts).addSingleIfStmt(ra): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCref"), ra) of mGCunref: # only a magic for the old GCs - unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n") + var a: TLoc = initLocExpr(p, e[1]) + let ra = rdLoc(a) + p.s(cpsStmts).addSingleIfStmt(ra): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimGCunref"), ra) of mSetLengthStr: genSetLengthStr(p, e, d) of mSetLengthSeq: genSetLengthSeq(p, e, d) of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, @@ -2867,8 +2985,14 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = cgsym(p.module, $opr.loc.snippet) # make sure we have pointer-initialising code for hot code reloading if not wasDeclared and p.hcrOn: - p.module.s[cfsDynLibInit].addf("\t$1 = ($2) hcrGetProc($3, \"$1\");$n", - [mangleDynLibProc(prc), getTypeDesc(p.module, prc.loc.t), getModuleDllPath(p.module, prc)]) + let name = mangleDynLibProc(prc) + let rt = getTypeDesc(p.module, prc.loc.t) + p.module.s[cfsDynLibInit].add('\t') + p.module.s[cfsDynLibInit].addAssignmentWithValue(name): + p.module.s[cfsDynLibInit].addCast(rt): + p.module.s[cfsDynLibInit].addCall("hcrGetProc", + getModuleDllPath(p.module, prc), + '"' & name & '"') genCall(p, e, d) of mDefault, mZeroDefault: genDefault(p, e, d) of mEcho: genEcho(p, e[1].skipConv) @@ -2900,7 +3024,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mWasMoved: genWasMoved(p, e) of mMove: genMove(p, e, d) of mDestroy: genDestroy(p, e) - of mAccessEnv: unaryExpr(p, e, d, "$1.ClE_0") + of mAccessEnv: unaryExpr(p, e, d, dotField(ra, "ClE_0")) of mAccessTypeField: genAccessTypeField(p, e, d) of mSlice: genSlice(p, e, d) of mTrace: discard "no code to generate" @@ -2929,26 +3053,34 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = if d.k == locNone: d = getTemp(p, e.typ) if getSize(p.config, e.typ) > 8: # big set: - linefmt(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n", - [rdLoc(d), getTypeDesc(p.module, e.typ)]) + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"), + rdLoc(d), + cSizeof(getTypeDesc(p.module, e.typ))) for it in e.sons: if it.kind == nkRange: idx = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, it[0]) b = initLocExpr(p, it[1]) - var aa = newRopeAppender() + var aa: Snippet = "" rdSetElemLoc(p.config, a, e.typ, aa) - var bb = newRopeAppender() + var bb: Snippet = "" rdSetElemLoc(p.config, b, e.typ, bb) - lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & - "$2[(NU)($1)>>3] |=(1U<<((NU)($1)&7U));$n", [rdLoc(idx), rdLoc(d), - aa, bb]) + let ri = rdLoc(idx) + let rd = rdLoc(d) + p.s(cpsStmts).addForRangeInclusive(ri, aa, bb): + p.s(cpsStmts).addInPlaceOp(BitOr, "NU8", + subscript(rd, cOp(Shr, "NU", cCast("NU", ri), cIntValue(3))), + cOp(Shl, "NU8", cUintValue(1), + cOp(BitAnd, "NU", cCast("NU", ri), cUintValue(7)))) else: a = initLocExpr(p, it) - var aa = newRopeAppender() + var aa: Snippet = "" rdSetElemLoc(p.config, a, e.typ, aa) - lineF(p, cpsStmts, "$1[(NU)($2)>>3] |=(1U<<((NU)($2)&7U));$n", - [rdLoc(d), aa]) + let rd = rdLoc(d) + p.s(cpsStmts).addInPlaceOp(BitOr, "NU8", + subscript(rd, cOp(Shr, "NU", cCast("NU", aa), cIntValue(3))), + cOp(Shl, "NU8", cUintValue(1), + cOp(BitAnd, "NU", cCast("NU", aa), cUintValue(7)))) else: # small set var ts = "NU" & $(getSize(p.config, e.typ) * 8) @@ -2958,21 +3090,24 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = idx = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter a = initLocExpr(p, it[0]) b = initLocExpr(p, it[1]) - var aa = newRopeAppender() + var aa: Snippet = "" rdSetElemLoc(p.config, a, e.typ, aa) - var bb = newRopeAppender() + var bb: Snippet = "" rdSetElemLoc(p.config, b, e.typ, bb) - - lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" & - "$2 |=(($5)(1)<<(($1)%(sizeof($5)*8)));$n", [ - rdLoc(idx), rdLoc(d), aa, bb, rope(ts)]) + let ri = rdLoc(idx) + let rd = rdLoc(d) + p.s(cpsStmts).addForRangeInclusive(ri, aa, bb): + p.s(cpsStmts).addInPlaceOp(BitOr, ts, rd, + cOp(Shl, ts, cCast(ts, cIntValue(1)), + cOp(Mod, ts, ri, cOp(Mul, ts, cSizeof(ts), cIntValue(8))))) else: a = initLocExpr(p, it) - var aa = newRopeAppender() + var aa: Snippet = "" rdSetElemLoc(p.config, a, e.typ, aa) - lineF(p, cpsStmts, - "$1 |=(($3)(1)<<(($2)%(sizeof($3)*8)));$n", - [rdLoc(d), aa, rope(ts)]) + let rd = rdLoc(d) + p.s(cpsStmts).addInPlaceOp(BitOr, ts, rd, + cOp(Shl, ts, cCast(ts, cIntValue(1)), + cOp(Mod, ts, aa, cOp(Mul, ts, cSizeof(ts), cIntValue(8))))) proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = var rec: TLoc @@ -3090,27 +3225,23 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = let dest = skipTypes(n.typ, abstractPtrs) if optObjCheck in p.options and not isObjLackingTypeField(dest): var nilCheck = "" - var r = newRopeAppender() + var r: Snippet = "" rdMType(p, a, nilCheck, r) if optTinyRtti in p.config.globalOptions: let checkFor = $getObjDepth(dest) let token = $genDisplayElem(MD5Digest(hashType(dest, p.config))) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObjDisplayCheck($2, $3, $4)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor, token]) - else: - linefmt(p, cpsStmts, "if (!#isObjDisplayCheck($1, $2, $3)){ #raiseObjectConversionError(); ", - [r, checkFor, token]) + let objCheck = cOp(Not, cgCall(p, "isObjDisplayCheck", r, checkFor, token)) + let check = if nilCheck != "": cOp(And, nilCheck, objCheck) else: objCheck + p.s(cpsStmts).addSingleIfStmt(check): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseObjectConversionError")) + raiseInstr(p, p.s(cpsStmts)) else: let checkFor = genTypeInfoV1(p.module, dest, n.info) - if nilCheck != "": - linefmt(p, cpsStmts, "if ($1 && !#isObj($2, $3)){ #raiseObjectConversionError(); ", - [nilCheck, r, checkFor]) - else: - linefmt(p, cpsStmts, "if (!#isObj($1, $2)){ #raiseObjectConversionError(); ", - [r, checkFor]) - raiseInstr(p, p.s(cpsStmts)) - linefmt p, cpsStmts, "}$n", [] + let objCheck = cOp(Not, cgCall(p, "isObj", r, checkFor)) + let check = if nilCheck != "": cOp(And, nilCheck, objCheck) else: objCheck + p.s(cpsStmts).addSingleIfStmt(check): + p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseObjectConversionError")) + raiseInstr(p, p.s(cpsStmts)) if n[0].typ.kind != tyObject: let destTyp = getTypeDesc(p.module, n.typ) @@ -3473,7 +3604,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if ex.kind != nkEmpty: genLineDir(p, n) var a: TLoc = initLocExprSingleUse(p, ex) - line(p, cpsStmts, "(void)(" & a.snippet & ");\L") + p.s(cpsStmts).addStmt(): + p.s(cpsStmts).add(cCast("void", a.snippet)) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt, nkHiddenTryStmt: case p.config.exc