diff options
author | metagn <metagngn@gmail.com> | 2024-10-03 20:35:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-03 19:35:21 +0200 |
commit | 89978b48baeed0c745d45d666a9786c8d9457581 (patch) | |
tree | b5cf3cf90d1913bbf492b09afa3157898555e57b | |
parent | d6a71a10671b66ee4f5be09f99234b3d834e7fce (diff) | |
download | Nim-89978b48baeed0c745d45d666a9786c8d9457581.tar.gz |
use cbuilder for seq type generation (#24202)
`addSimpleStruct` is just so the compiler doesn't use so much extra computation on analyzing the `typ` parameter for `addStruct`, which doesn't change anything for `seq` types. We could probably still get away with using `addStruct` instead, or making `addStruct` accept `nil` as the `typ` argument but this would be even more computation. There were a lot of hidden issues with `addStruct` being a template & template argument substitution, so most of the behavior is moved into `startStruct`/`finishStruct` procs. This is turning out to be a lot of code for just a couple of changed lines, we might have to split `cbuilder` into multiple modules.
-rw-r--r-- | compiler/cbuilder.nim | 109 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 20 |
2 files changed, 89 insertions, 40 deletions
diff --git a/compiler/cbuilder.nim b/compiler/cbuilder.nim index 6fc0bd881..bb1bdfe27 100644 --- a/compiler/cbuilder.nim +++ b/compiler/cbuilder.nim @@ -5,14 +5,19 @@ type template newBuilder(s: string): Builder = s -proc addField(obj: var Builder; name, typ: Snippet) = +proc addField(obj: var Builder; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") = obj.add('\t') obj.add(typ) obj.add(" ") obj.add(name) + if isFlexArray: + obj.add("[SEQ_DECL_SIZE]") + if initializer.len != 0: + obj.add(initializer) obj.add(";\n") -proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool; initializer: Snippet) = +proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool = false; initializer: Snippet = "") = + ## for fields based on an `skField` symbol obj.add('\t') if field.alignment > 0: obj.add("NIM_ALIGN(") @@ -32,6 +37,13 @@ proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bo obj.add(initializer) obj.add(";\n") +type + BaseClassKind = enum + bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti + StructBuilderInfo = object + baseKind: BaseClassKind + preFieldsLen: int + proc structOrUnion(t: PType): Snippet = let t = t.skipTypes({tyAlias, tySink}) if tfUnion in t.flags: "union" @@ -40,47 +52,80 @@ proc structOrUnion(t: PType): Snippet = proc ptrType(t: Snippet): Snippet = t & "*" -template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: string; body: typed) = - if tfPacked in typ.flags: +proc startSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet): StructBuilderInfo = + result = StructBuilderInfo(baseKind: bcNone) + obj.add("struct ") + obj.add(name) + if baseType.len != 0: + if m.compileToCpp: + result.baseKind = bcCppInherit + else: + result.baseKind = bcSupField + if result.baseKind == bcCppInherit: + obj.add(" : public ") + obj.add(baseType) + obj.add(" ") + obj.add("{\n") + result.preFieldsLen = obj.len + if result.baseKind == bcSupField: + obj.addField(name = "Sup", typ = baseType) + +proc finishSimpleStruct(obj: var Builder; m: BModule; info: StructBuilderInfo) = + if info.baseKind == bcNone and info.preFieldsLen == obj.len: + # no fields were added, add dummy field + obj.addField(name = "dummy", typ = "char") + obj.add("};\n") + +template addSimpleStruct(obj: var Builder; m: BModule; name: string; baseType: Snippet; body: typed) = + ## for independent structs, not directly based on a Nim type + let info = startSimpleStruct(obj, m, name, baseType) + body + finishSimpleStruct(obj, m, info) + +proc startStruct(obj: var Builder; m: BModule; t: PType; name: string; baseType: Snippet): StructBuilderInfo = + result = StructBuilderInfo(baseKind: bcNone) + if tfPacked in t.flags: if hasAttribute in CC[m.config.cCompiler].props: - obj.add(structOrUnion(typ)) + obj.add(structOrUnion(t)) obj.add(" __attribute__((__packed__))") else: obj.add("#pragma pack(push, 1)\n") - obj.add(structOrUnion(typ)) + obj.add(structOrUnion(t)) else: - obj.add(structOrUnion(typ)) + obj.add(structOrUnion(t)) obj.add(" ") obj.add(name) - type BaseClassKind = enum - bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti - var baseKind = bcNone - if typ.kind == tyObject: - if typ.baseClass == nil: - if lacksMTypeField(typ): - baseKind = bcNone + if t.kind == tyObject: + if t.baseClass == nil: + if lacksMTypeField(t): + result.baseKind = bcNone elif optTinyRtti in m.config.globalOptions: - baseKind = bcNoneTinyRtti + result.baseKind = bcNoneTinyRtti else: - baseKind = bcNoneRtti + result.baseKind = bcNoneRtti elif m.compileToCpp: - baseKind = bcCppInherit + result.baseKind = bcCppInherit + else: + result.baseKind = bcSupField + elif baseType.len != 0: + if m.compileToCpp: + result.baseKind = bcCppInherit else: - baseKind = bcSupField - if baseKind == bcCppInherit: + result.baseKind = bcSupField + if result.baseKind == bcCppInherit: obj.add(" : public ") obj.add(baseType) obj.add(" ") obj.add("{\n") - let currLen = obj.len - case baseKind + result.preFieldsLen = obj.len + case result.baseKind of bcNone: # rest of the options add a field or don't need it due to inheritance, # we need to add the dummy field for uncheckedarray ahead of time # so that it remains trailing - if typ.itemId notin m.g.graph.memberProcsPerType and - typ.n != nil and typ.n.len == 1 and typ.n[0].kind == nkSym and - typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray: + if t.itemId notin m.g.graph.memberProcsPerType and + t.n != nil and t.n.len == 1 and t.n[0].kind == nkSym and + t.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray: # only consists of flexible array field, add *initial* dummy field obj.addField(name = "dummy", typ = "char") of bcCppInherit: discard @@ -90,13 +135,21 @@ template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseT obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2"))) of bcSupField: obj.addField(name = "Sup", typ = baseType) - body - if baseKind == bcNone and currLen == obj.len and typ.itemId notin m.g.graph.memberProcsPerType: + +proc finishStruct(obj: var Builder; m: BModule; t: PType; info: StructBuilderInfo) = + if info.baseKind == bcNone and info.preFieldsLen == obj.len and + t.itemId notin m.g.graph.memberProcsPerType: # no fields were added, add dummy field obj.addField(name = "dummy", typ = "char") obj.add("};\n") - if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props: - result.add("#pragma pack(pop)\n") + if tfPacked in t.flags and hasAttribute notin CC[m.config.cCompiler].props: + obj.add("#pragma pack(pop)\n") + +template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: Snippet; body: typed) = + ## for structs built directly from a Nim type + let info = startStruct(obj, m, typ, name, baseType) + body + finishStruct(obj, m, typ, info) template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) = ## adds a field with a `struct { ... }` type, building it according to `body` diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 5b5218a3e..2c2556336 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -967,18 +967,14 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes m.typeCache[sig] = result & seqStar(m) if not isImportedType(t): if skipTypes(t.elementType, typedescInst).kind != tyEmpty: - const - cppSeq = "struct $2 : #TGenericSeq {$n" - cSeq = "struct $2 {$n" & - " #TGenericSeq Sup;$n" - if m.compileToCpp: - appcg(m, m.s[cfsSeqTypes], - cppSeq & " $1 data[SEQ_DECL_SIZE];$n" & - "};$n", [getTypeDescAux(m, t.elementType, check, kind), result]) - else: - appcg(m, m.s[cfsSeqTypes], - cSeq & " $1 data[SEQ_DECL_SIZE];$n" & - "};$n", [getTypeDescAux(m, t.elementType, check, kind), result]) + var struct = newBuilder("") + let baseType = cgsymValue(m, "TGenericSeq") + struct.addSimpleStruct(m, name = result, baseType = baseType): + struct.addField( + name = "data", + typ = getTypeDescAux(m, t.elementType, check, kind), + isFlexArray = true) + m.s[cfsSeqTypes].add struct else: result = rope("TGenericSeq") result.add(seqStar(m)) |