more on arc codegen (#13178)

* arc codegen for union type

* add more tests

* fix offsetof

* fix tsizeof test

* fix style
This commit is contained in:
cooldome 2020-01-19 13:14:26 +00:00 • committed by Andreas Rumpf
commit 416b4c3612
4 changed files with 81 additions and 26 deletions

View file

@ -2204,12 +2204,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: else:
internalError(p.config, e.info, "unknown ast") internalError(p.config, e.info, "unknown ast")
let t = dotExpr[0].typ.skipTypes({tyTypeDesc}) let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
let tname = getTypeDesc(p.module, t)
let member = let member =
if t.kind == tyTuple: if t.kind == tyTuple:
"Field" & rope(dotExpr[1].sym.position) "Field" & rope(dotExpr[1].sym.position)
else: else: dotExpr[1].sym.loc.r
rope(dotExpr[1].sym.name.s) putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [tname, member])
putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [getTypeDesc(p.module, t), member])
of mChr: genSomeCast(p, e, d) of mChr: genSomeCast(p, e, d)
of mOrd: genOrd(p, e, d) of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
@ -2782,17 +2782,50 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
of nkRecCase: of nkRecCase:
getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info) getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
if count > 0: result.add ", " if count > 0: result.add ", "
# XXX select default case branch here! var branch = Zero
#for i in 1..<obj.len: if constOrNil != nil:
let selectedBranch = 1 ## find kind value, default is zero if not specified
result.add "{" # struct inside union for i in 1..<constOrNil.len:
if lastSon(obj[selectedBranch]).kind != nkSym: if constOrNil[i].kind == nkExprColonExpr:
result.add "{" 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 var countB = 0
getNullValueAux(p, t, lastSon(obj[selectedBranch]), constOrNil, result, countB, isConst, info) let b = lastSon(obj[selectedBranch])
if lastSon(obj[selectedBranch]).kind != nkSym: # 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 "}" 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 "}" result.add "}"
of nkSym: of nkSym:
if count > 0: result.add ", " if count > 0: result.add ", "
inc count inc count

View file

@ -508,15 +508,15 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
proc genRecordFieldsAux(m: BModule, n: PNode, proc genRecordFieldsAux(m: BModule, n: PNode,
rectype: PType, rectype: PType,
check: var IntSet): Rope = check: var IntSet, unionPrefix = ""): Rope =
result = nil result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
for i in 0..<n.len: 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: of nkRecCase:
if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux") 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, # prefix mangled name with "_U" to avoid clashes with other field names,
# since identifiers are not allowed to start with '_' # since identifiers are not allowed to start with '_'
var unionBody: Rope = nil var unionBody: Rope = nil
@ -525,7 +525,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
let k = lastSon(n[i]) let k = lastSon(n[i])
if k.kind != nkSym: 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 a != nil:
if tfPacked notin rectype.flags: if tfPacked notin rectype.flags:
unionBody.add("struct {") unionBody.add("struct {")
@ -535,11 +535,11 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
else: else:
unionBody.addf("#pragma pack(push, 1)$nstruct{", []) unionBody.addf("#pragma pack(push, 1)$nstruct{", [])
unionBody.add(a) 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: if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
unionBody.addf("#pragma pack(pop)$n", []) unionBody.addf("#pragma pack(pop)$n", [])
else: else:
unionBody.add(genRecordFieldsAux(m, k, rectype, check)) unionBody.add(genRecordFieldsAux(m, k, rectype, check, unionPrefix))
else: internalError(m.config, "genRecordFieldsAux(record case branch)") else: internalError(m.config, "genRecordFieldsAux(record case branch)")
if unionBody != nil: if unionBody != nil:
result.addf("union{$n$1};$n", [unionBody]) result.addf("union{$n$1};$n", [unionBody])
@ -548,7 +548,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if field.typ.kind == tyVoid: return if field.typ.kind == tyVoid: return
#assert(field.ast == nil) #assert(field.ast == nil)
let sname = mangleRecFieldName(m, field) let sname = mangleRecFieldName(m, field)
fillLoc(field.loc, locField, n, sname, OnUnknown) fillLoc(field.loc, locField, n, unionPrefix & sname, OnUnknown)
if field.alignment > 0: if field.alignment > 0:
result.addf "NIM_ALIGN($1) ", [rope(field.alignment)] result.addf "NIM_ALIGN($1) ", [rope(field.alignment)]
# for importcpp'ed objects, we only need to set field.loc, but don't # for importcpp'ed objects, we only need to set field.loc, but don't

View file

@ -4,7 +4,7 @@ discard """
""" """
when defined(cpp): when defined(cpp):
{.passC: "-std=gnu++17".} {.passC: "-std=gnu++2a".}
type type
TokenKind* = enum TokenKind* = enum
@ -24,6 +24,23 @@ type
else: discard else: discard
pos*: Natural 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 BaseLexer* = object of RootObj
input*: string input*: string
pos*: Natural pos*: Natural
@ -39,6 +56,8 @@ type
Parser[T: Lexer] = object Parser[T: Lexer] = object
l: T l: T
tok: Token tok: Token
tok2: Token2
tok3: Token3
allowTrailingComma: bool allowTrailingComma: bool
allowIdentifierObjectKey: bool allowIdentifierObjectKey: bool

View file

@ -74,20 +74,23 @@ proc strAlign(arg: string): string =
for i in 0 ..< minLen - arg.len: for i in 0 ..< minLen - arg.len:
result &= ' ' result &= ' '
macro c_offsetof(a: typed, b: untyped): int32 = macro c_offsetof(fieldAccess: typed): int32 =
## Bullet proof implementation that works on actual offsetof operator ## Bullet proof implementation that works on actual offsetof operator
## in the c backend. Assuming of course this implementation is ## in the c backend. Assuming of course this implementation is
## correct. ## correct.
let bliteral = let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0]
if b.kind == nnkStrLit: else: fieldAccess
b let a = s[0].getTypeInst
else: let b = s[1]
newLit(repr(b))
result = quote do: result = quote do:
var res: int32 var res: int32
{.emit: [res, " = offsetof(", `a`, ", ", `bliteral`, ");"] .} {.emit: [res, " = offsetof(", `a`, ", ", `b`, ");"] .}
res res
template c_offsetof(t: typedesc, a: untyped): int32 =
var x: ptr t
c_offsetof(x[].a)
macro c_sizeof(a: typed): int32 = macro c_sizeof(a: typed): int32 =
## Bullet proof implementation that works using the sizeof operator ## Bullet proof implementation that works using the sizeof operator
## in the c backend. Assuming of course this implementation is ## in the c backend. Assuming of course this implementation is