diff options
author | cooldome <cdome@bk.ru> | 2020-01-19 13:14:26 +0000 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2020-01-19 14:14:26 +0100 |
commit | 416b4c3612f444608218619947ecf290060ee8f6 (patch) | |
tree | c55c2650005888e57482bbe3be441968e30961aa | |
parent | bc14453f69b9bde449cb52655eb6ffe571d6a28b (diff) | |
download | Nim-416b4c3612f444608218619947ecf290060ee8f6.tar.gz |
more on arc codegen (#13178)
* arc codegen for union type * add more tests * fix offsetof * fix tsizeof test * fix style
-rw-r--r-- | compiler/ccgexprs.nim | 55 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 14 | ||||
-rw-r--r-- | tests/destructor/tarc3.nim | 21 | ||||
-rw-r--r-- | tests/misc/tsizeof.nim | 17 |
4 files changed, 81 insertions, 26 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index e52be902b..eed29ff4b 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2204,12 +2204,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "unknown ast") let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) + let tname = getTypeDesc(p.module, t) let member = if t.kind == tyTuple: "Field" & rope(dotExpr[1].sym.position) - else: - rope(dotExpr[1].sym.name.s) - putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [getTypeDesc(p.module, t), member]) + else: dotExpr[1].sym.loc.r + putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [tname, member]) of mChr: genSomeCast(p, e, d) of mOrd: genOrd(p, e, d) of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: @@ -2782,17 +2782,50 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode, of nkRecCase: getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info) if count > 0: result.add ", " - # XXX select default case branch here! - #for i in 1..<obj.len: - let selectedBranch = 1 - result.add "{" # struct inside union - if lastSon(obj[selectedBranch]).kind != nkSym: - result.add "{" + var branch = Zero + if constOrNil != nil: + ## find kind value, default is zero if not specified + for i in 1..<constOrNil.len: + if constOrNil[i].kind == nkExprColonExpr: + if constOrNil[i][0].sym.name.id == obj[0].sym.name.id: + branch = getOrdValue(constOrNil[i][1]) + break + elif i == obj[0].sym.position: + branch = getOrdValue(constOrNil[i]) + break + + var selectedBranch = -1 + block branchSelection: + for i in 1 ..< obj.len: + for j in 0 .. obj[i].len - 2: + if obj[i][j].kind == nkRange: + let x = getOrdValue(obj[i][j][0]) + let y = getOrdValue(obj[i][j][1]) + if branch >= x and branch <= y: + selectedBranch = i + break branchSelection + elif getOrdValue(obj[i][j]) == branch: + selectedBranch = i + break branchSelection + if obj[i].len == 1: + # else branch + selectedBranch = i + assert(selectedBranch >= 1) + + result.add "{" var countB = 0 - getNullValueAux(p, t, lastSon(obj[selectedBranch]), constOrNil, result, countB, isConst, info) - if lastSon(obj[selectedBranch]).kind != nkSym: + let b = lastSon(obj[selectedBranch]) + # designated initilization is the only way to init non first element of unions + # branches are allowed to have no members (b.len == 0), in this case they don't need initializer + if b.kind == nkRecList and b.len > 0: + result.add "._i" & $selectedBranch & " = {" + getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info) result.add "}" + elif b.kind == nkSym: + result.add "." & lastSon(obj[selectedBranch]).sym.loc.r & " = " + getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info) result.add "}" + of nkSym: if count > 0: result.add ", " inc count diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 56f227e37..2bcaa5dc3 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -508,15 +508,15 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope = proc genRecordFieldsAux(m: BModule, n: PNode, rectype: PType, - check: var IntSet): Rope = + check: var IntSet, unionPrefix = ""): Rope = result = nil case n.kind of nkRecList: for i in 0..<n.len: - result.add(genRecordFieldsAux(m, n[i], rectype, check)) + result.add(genRecordFieldsAux(m, n[i], rectype, check, unionPrefix)) of nkRecCase: if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux") - result.add(genRecordFieldsAux(m, n[0], rectype, check)) + result.add(genRecordFieldsAux(m, n[0], rectype, check, unionPrefix)) # prefix mangled name with "_U" to avoid clashes with other field names, # since identifiers are not allowed to start with '_' var unionBody: Rope = nil @@ -525,7 +525,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, of nkOfBranch, nkElse: let k = lastSon(n[i]) if k.kind != nkSym: - let a = genRecordFieldsAux(m, k, rectype, check) + let a = genRecordFieldsAux(m, k, rectype, check, unionPrefix & "_i" & $i & ".") if a != nil: if tfPacked notin rectype.flags: unionBody.add("struct {") @@ -535,11 +535,11 @@ proc genRecordFieldsAux(m: BModule, n: PNode, else: unionBody.addf("#pragma pack(push, 1)$nstruct{", []) unionBody.add(a) - unionBody.addf("};$n", []) + unionBody.addf("} _i$1;$n", [rope($i)]) if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props: unionBody.addf("#pragma pack(pop)$n", []) else: - unionBody.add(genRecordFieldsAux(m, k, rectype, check)) + unionBody.add(genRecordFieldsAux(m, k, rectype, check, unionPrefix)) else: internalError(m.config, "genRecordFieldsAux(record case branch)") if unionBody != nil: result.addf("union{$n$1};$n", [unionBody]) @@ -548,7 +548,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, if field.typ.kind == tyVoid: return #assert(field.ast == nil) let sname = mangleRecFieldName(m, field) - fillLoc(field.loc, locField, n, sname, OnUnknown) + fillLoc(field.loc, locField, n, unionPrefix & sname, OnUnknown) if field.alignment > 0: result.addf "NIM_ALIGN($1) ", [rope(field.alignment)] # for importcpp'ed objects, we only need to set field.loc, but don't diff --git a/tests/destructor/tarc3.nim b/tests/destructor/tarc3.nim index 1ca4c70e9..d3b9639ad 100644 --- a/tests/destructor/tarc3.nim +++ b/tests/destructor/tarc3.nim @@ -4,7 +4,7 @@ discard """ """ when defined(cpp): - {.passC: "-std=gnu++17".} + {.passC: "-std=gnu++2a".} type TokenKind* = enum @@ -24,6 +24,23 @@ type else: discard pos*: Natural + + Token2* = object + case kind*: TokenKind + of tkString: strVal*: string + of tkNumber: numVal*: float + of tkInt64, tkColon..tkComma: + str1*: array[2, string] + float: float + else: discard + pos*: Natural + + Token3* = object + case kind*: TokenKind + of tkNumber: numVal*: float + of tkInt64, tkComma..tkString: ff: seq[float] + else: str1*: string + BaseLexer* = object of RootObj input*: string pos*: Natural @@ -39,6 +56,8 @@ type Parser[T: Lexer] = object l: T tok: Token + tok2: Token2 + tok3: Token3 allowTrailingComma: bool allowIdentifierObjectKey: bool diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index a2a9fe59e..7b92d3639 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -74,20 +74,23 @@ proc strAlign(arg: string): string = for i in 0 ..< minLen - arg.len: result &= ' ' -macro c_offsetof(a: typed, b: untyped): int32 = +macro c_offsetof(fieldAccess: typed): int32 = ## Bullet proof implementation that works on actual offsetof operator ## in the c backend. Assuming of course this implementation is ## correct. - let bliteral = - if b.kind == nnkStrLit: - b - else: - newLit(repr(b)) + let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] + else: fieldAccess + let a = s[0].getTypeInst + let b = s[1] result = quote do: var res: int32 - {.emit: [res, " = offsetof(", `a`, ", ", `bliteral`, ");"] .} + {.emit: [res, " = offsetof(", `a`, ", ", `b`, ");"] .} res +template c_offsetof(t: typedesc, a: untyped): int32 = + var x: ptr t + c_offsetof(x[].a) + macro c_sizeof(a: typed): int32 = ## Bullet proof implementation that works using the sizeof operator ## in the c backend. Assuming of course this implementation is |