Skip to content

Commit

Permalink
cbuilder: second half of cgen (nim-lang#24432)
Browse files Browse the repository at this point in the history
Follows up nim-lang#24423, needed more refactoring than I expected, sorry for
ugly diff.

With this pretty much all of the raw C code generating parts of the
codegen are abstracted into the cbuilder API (to my knowledge at least).
The current design of NIFC does not implement everything the codegen
generates, such things have mostly not been adapted, they are the
following along with how I'm guessing they could be implemented:

* C++ specific codegen: Maybe a dialect of NIFC for generating C++?
* `codegenDecl` pragma: Could be passed as a pragma to NIFC
* C macros, currently only used for line info IIRC i.e. `nimln_(123)`:
Just inline them when generating NIFC
* Other C defines & `#line`: Maybe as NIFC directives or line infos?
* There is also [this
`#ifndef`](https://github.com/nim-lang/Nim/blob/21420d8b0976dc034feb90ab2878ae0dd63121ae/compiler/cgen.nim#L2249)
when generating headers but NIFC shouldn't need it
* `alignof`/`offsetof`: Is in `cbuilder` but not implemented in NIFC,
should be easy

For now we can disable C++ and the `codegenDecl` pragma when generating
NIFC but since cbuilder is mostly designed to generate NIFC as a flag
when booting the compiler, this hinders the ability to run the CI
against NIFC. Maybe we could also make cbuilder able to generate both C
and NIFC at runtime, this would be a large refactor but wouldn't be too
difficult.

Other missing abstractions before being able to generate NIFC are:

* Primitive types and symbols i.e. `int`, `void*`, `NI`, `NIM_NULL` are
currently still constant string literals, `NU8`, `NU16` etc are also
sometimes generated like `"NU" & $bits`.
* NIFC identifiers, i.e. adding `.c` to imported symbols and properly
mangling generated ones. Not sure how difficult this is going to be.
  • Loading branch information
metagn authored Nov 14, 2024
1 parent 21420d8 commit 726195d
Show file tree
Hide file tree
Showing 7 changed files with 485 additions and 294 deletions.
6 changes: 6 additions & 0 deletions compiler/cbuilderbase.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ proc addLineEndDedent*(builder: var Builder, s: string) =
builder.addDedent(s)
builder.addNewline()

proc addLineComment*(builder: var Builder, comment: string) =
# probably no-op on nifc
builder.add("// ")
builder.add(comment)
builder.addNewline()

proc addIntValue*(builder: var Builder, val: int) =
builder.buf.addInt(val)

Expand Down
57 changes: 56 additions & 1 deletion compiler/cbuilderdecls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,19 @@ proc addUnnamedParam(builder: var Builder, params: var ProcParamBuilder, typ: Sn
params.needsComma = true
builder.add(typ)

proc addProcTypedParam(builder: var Builder, paramBuilder: var ProcParamBuilder, callConv: TCallingConvention, name: string, rettype, params: Snippet) =
if paramBuilder.needsComma:
builder.add(", ")
else:
paramBuilder.needsComma = true
builder.add(CallingConvToStr[callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
builder.add(params)

proc addVarargsParam(builder: var Builder, params: var ProcParamBuilder) =
# does not exist in NIFC, needs to be proc pragma
if params.needsComma:
Expand All @@ -481,6 +494,20 @@ template addProcParams(builder: var Builder, params: out ProcParamBuilder, body:
body
finishProcParamBuilder(builder, params)

type SimpleProcParam = tuple
name, typ: string

proc cProcParams(params: varargs[SimpleProcParam]): Snippet =
if params.len == 0: return "(void)"
result = "("
for i in 0 ..< params.len:
if i != 0: result.add(", ")
result.add(params[i].typ)
if params[i].name.len != 0:
result.add(" ")
result.add(params[i].name)
result.add(")")

template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention,
name: string, rettype: Snippet, paramBuilder: typed) =
# on nifc should build something like (proc name params type pragmas
Expand All @@ -502,6 +529,15 @@ proc addProcHeader(builder: var Builder, callConv: TCallingConvention,
addProcHeaderWithParams(builder, callConv, name, rettype):
builder.add(params)

proc addProcHeader(builder: var Builder, name: string, rettype, params: Snippet, isConstructor = false) =
# no callconv
builder.add(rettype)
builder.add(" ")
if isConstructor:
builder.add("__attribute__((constructor)) ")
builder.add(name)
builder.add(params)

proc addProcHeader(builder: var Builder, m: BModule, prc: PSym, name: string, params, rettype: Snippet, addAttributes: bool) =
# on nifc should build something like (proc name params type pragmas
# with no body given
Expand Down Expand Up @@ -560,14 +596,33 @@ proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, param
builder.addLineEnd(";")

proc addProcVar(builder: var Builder, callConv: TCallingConvention,
name: string, params, rettype: Snippet, isStatic = false) =
name: string, params, rettype: Snippet,
isStatic = false, isVolatile = false) =
# on nifc, builds full variable
if isStatic:
builder.add("static ")
builder.add(CallingConvToStr[callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
if isVolatile:
builder.add("volatile ")
builder.add(name)
builder.add(")")
builder.add(params)
# ensure we are just adding a variable:
builder.addLineEnd(";")

proc addProcVar(builder: var Builder,
name: string, params, rettype: Snippet,
isStatic = false, isVolatile = false) =
# no callconv
if isStatic:
builder.add("static ")
builder.add(rettype)
builder.add(" (*")
if isVolatile:
builder.add("volatile ")
builder.add(name)
builder.add(")")
builder.add(params)
Expand Down
17 changes: 17 additions & 0 deletions compiler/cbuilderexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ proc ptrConstType(t: Snippet): Snippet =
proc ptrType(t: Snippet): Snippet =
t & "*"

proc cppRefType(t: Snippet): Snippet =
t & "&"

const
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
"N_STDCALL", "N_CDECL", "N_SAFECALL",
Expand All @@ -32,6 +35,20 @@ proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
proc procPtrTypeUnnamed(callConv: TCallingConvention, rettype, params: Snippet): Snippet =
CallingConvToStr[callConv] & "_PTR(" & rettype & ", )" & params

type CppCaptureKind = enum None, ByReference, ByCopy

template addCppLambda(builder: var Builder, captures: CppCaptureKind, params: Snippet, body: typed) =
builder.add("[")
case captures
of None: discard
of ByReference: builder.add("&")
of ByCopy: builder.add("=")
builder.add("] ")
builder.add(params)
builder.addLineEndIndent(" {")
body
builder.addLineEndDedent("}")

proc cCast(typ, value: Snippet): Snippet =
"((" & typ & ") " & value & ")"

Expand Down
5 changes: 1 addition & 4 deletions compiler/ccgthreadvars.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,6 @@ proc generateThreadVarsSize(m: BModule) =
sfCompileToCpp in m.module.flags: ExternC
else: None
m.s[cfsProcs].addDeclWithVisibility(externc):
m.s[cfsProcs].addProcHeaderWithParams(ccNoConvention, "NimThreadVarsSize", "NI"):
var params: ProcParamBuilder
m.s[cfsProcs].addProcParams(params):
discard
m.s[cfsProcs].addProcHeader("NimThreadVarsSize", "NI", cProcParams())
m.s[cfsProcs].finishProcHeaderWithBody():
m.s[cfsProcs].addReturn(cCast("NI", cSizeof("NimThreadVars")))
Loading

0 comments on commit 726195d

Please sign in to comment.