Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cbuilder: add switch stmt, use for ccgreset and ccgtrav #24408

Merged
merged 1 commit into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions compiler/cbuilderdecls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -471,9 +471,31 @@ template addProcParams(builder: var Builder, params: out ProcParamBuilder, body:
body
finishProcParamBuilder(builder, params)

template addProcHeaderWithParams(builder: var Builder, callConv: TCallingConvention,
name: string, rettype: Snippet, paramBuilder: typed) =
# on nifc should build something like (proc name params type pragmas
# with no body given
# or enforce this with secondary builder object
builder.add(CallingConvToStr[callConv])
builder.add("(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
paramBuilder

proc addProcHeader(builder: var Builder, callConv: TCallingConvention,
name: string, rettype, params: Snippet) =
# on nifc should build something like (proc name params type pragmas
# with no body given
# or enforce this with secondary builder object
addProcHeaderWithParams(builder, callConv, name, rettype):
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
# or enforce this with secondary builder object
let noreturn = isNoReturn(m, prc)
if sfPure in prc.flags and hasDeclspec in extccomp.CC[m.config.cCompiler].props:
builder.add("__declspec(naked) ")
Expand Down Expand Up @@ -525,3 +547,18 @@ proc addProcVar(builder: var Builder, m: BModule, prc: PSym, name: string, param
builder.add(" __attribute__((noreturn))")
# ensure we are just adding a variable:
builder.add(";\n")

proc addProcVar(builder: var Builder, callConv: TCallingConvention,
name: string, params, rettype: Snippet, isStatic = false) =
# on nifc, builds full variable
if isStatic:
builder.add("static ")
builder.add(CallingConvToStr[callConv])
builder.add("_PTR(")
builder.add(rettype)
builder.add(", ")
builder.add(name)
builder.add(")")
builder.add(params)
# ensure we are just adding a variable:
builder.add(";\n")
3 changes: 3 additions & 0 deletions compiler/cbuilderexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ proc procPtrTypeUnnamed(rettype, params: Snippet): Snippet =
proc procPtrTypeUnnamedNimCall(rettype, params: Snippet): Snippet =
rettype & "(N_RAW_NIMCALL*)" & params

proc procPtrTypeUnnamed(callConv: TCallingConvention, rettype, params: Snippet): Snippet =
CallingConvToStr[callConv] & "_PTR(" & rettype & ", )" & params

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

Expand Down
55 changes: 55 additions & 0 deletions compiler/cbuilderstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,61 @@ template addForRangeInclusive(builder: var Builder, i, start, bound: Snippet, bo
body
builder.add("}\n")

template addSwitchStmt(builder: var Builder, val: Snippet, body: typed) =
builder.add("switch (")
builder.add(val)
builder.add(") {\n")
body
builder.add("}\n")

template addSingleSwitchCase(builder: var Builder, val: Snippet, body: typed) =
builder.add("case ")
builder.add(val)
builder.add(":\n")
body

type
SwitchCaseState = enum
None, Of, Else, Finished
SwitchCaseBuilder = object
state: SwitchCaseState

proc addCase(builder: var Builder, info: var SwitchCaseBuilder, val: Snippet) =
if info.state != Of:
assert info.state == None
info.state = Of
builder.add("case ")
builder.add(val)
builder.add(":\n")

proc addCaseRange(builder: var Builder, info: var SwitchCaseBuilder, first, last: Snippet) =
if info.state != Of:
assert info.state == None
info.state = Of
builder.add("case ")
builder.add(first)
builder.add(" ... ")
builder.add(last)
builder.add(":\n")

proc addCaseElse(builder: var Builder, info: var SwitchCaseBuilder) =
assert info.state == None
info.state = Else
builder.add("default:\n")

template addSwitchCase(builder: var Builder, info: out SwitchCaseBuilder, caseBody, body: typed) =
info = SwitchCaseBuilder(state: None)
caseBody
info.state = Finished
body

template addSwitchElse(builder: var Builder, body: typed) =
builder.add("default:\n")
body

proc addBreak(builder: var Builder) =
builder.add("break;\n")

template addScope(builder: var Builder, body: typed) =
builder.add("{")
body
Expand Down
61 changes: 34 additions & 27 deletions compiler/ccgreset.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,28 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
if disc.loc.snippet == "": fillObjectFields(p.module, typ)
if disc.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.snippet])
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
lineF(p, cpsStmts, "default:$n", [])
specializeResetN(p, accessor, lastSon(branch), typ)
lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n", [])
specializeResetT(p, "$1.$2" % [accessor, disc.loc.snippet], disc.loc.t)
let discField = dotField(accessor, disc.loc.snippet)
p.s(cpsStmts).addSwitchStmt(discField):
for i in 1..<n.len:
let branch = n[i]
assert branch.kind in {nkOfBranch, nkElse}
var caseBuilder: SwitchCaseBuilder
p.s(cpsStmts).addSwitchCase(caseBuilder):
if branch.kind == nkOfBranch:
genCaseRange(p, branch, caseBuilder)
else:
p.s(cpsStmts).addCaseElse(caseBuilder)
do:
specializeResetN(p, accessor, lastSon(branch), typ)
p.s(cpsStmts).addBreak()
specializeResetT(p, discField, disc.loc.t)
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
if field.loc.snippet == "": fillObjectFields(p.module, typ)
if field.loc.t == nil:
internalError(p.config, n.info, "specializeResetN()")
specializeResetT(p, "$1.$2" % [accessor, field.loc.snippet], field.loc.t)
specializeResetT(p, dotField(accessor, field.loc.snippet), field.loc.t)
else: internalError(p.config, n.info, "specializeResetN()")

proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
Expand All @@ -58,10 +61,8 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
of tyArray:
let arraySize = lengthOrd(p.config, typ.indexType)
var i: TLoc = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt))
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
[i.snippet, arraySize])
specializeResetT(p, ropecg(p.module, "$1[$2]", [accessor, i.snippet]), typ.elementType)
lineF(p, cpsStmts, "}$n", [])
p.s(cpsStmts).addForRangeExclusive(i.snippet, cIntValue(0), cIntValue(arraySize)):
specializeResetT(p, subscript(accessor, i.snippet), typ.elementType)
of tyObject:
var x = typ.baseClass
if x != nil: x = x.skipTypes(skipPtrs)
Expand All @@ -70,28 +71,34 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
of tyTuple:
let typ = getUniqueType(typ)
for i, a in typ.ikids:
specializeResetT(p, ropecg(p.module, "$1.Field$2", [accessor, i]), a)
specializeResetT(p, dotField(accessor, "Field" & $i), a)

of tyString, tyRef, tySequence:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1, NIM_NIL);$n", [accessor])
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
cCast("void**", cAddr(accessor)),
"NIM_NIL")

of tyProc:
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, "#unsureAsgnRef((void**)&$1.ClE_0, NIM_NIL);$n", [accessor])
lineCg(p, cpsStmts, "$1.ClP_0 = NIM_NIL;$n", [accessor])
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "unsureAsgnRef"),
cCast("void**", cAddr(dotField(accessor, "ClE_0"))),
"NIM_NIL")
p.s(cpsStmts).addFieldAssignment(accessor, "ClP_0", "NIM_NIL")
else:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
p.s(cpsStmts).addAssignment(accessor, "NIM_NIL")
of tyChar, tyBool, tyEnum, tyRange, tyInt..tyUInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
p.s(cpsStmts).addAssignment(accessor, cIntValue(0))
of tyCstring, tyPointer, tyPtr, tyVar, tyLent:
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [accessor])
p.s(cpsStmts).addAssignment(accessor, "NIM_NIL")
of tySet:
case mapSetType(p.config, typ)
of ctArray:
lineCg(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n",
[accessor, getTypeDesc(p.module, typ)])
let t = getTypeDesc(p.module, typ)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimZeroMem"),
accessor,
cSizeof(t))
of ctInt8, ctInt16, ctInt32, ctInt64:
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
p.s(cpsStmts).addAssignment(accessor, cIntValue(0))
else:
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
Expand Down
53 changes: 29 additions & 24 deletions compiler/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -959,26 +959,26 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
result = i

proc genCaseRange(p: BProc, branch: PNode) =
proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder) =
for j in 0..<branch.len-1:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[p.config.cCompiler].props:
var litA = newBuilder("")
var litB = newBuilder("")
genLiteral(p, branch[j][0], litA)
genLiteral(p, branch[j][1], litB)
lineF(p, cpsStmts, "case $1 ... $2:$n", [extract(litA), extract(litB)])
p.s(cpsStmts).addCaseRange(info, extract(litA), extract(litB))
else:
var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal:
var litA = newBuilder("")
genLiteral(p, v, litA)
lineF(p, cpsStmts, "case $1:$n", [extract(litA)])
p.s(cpsStmts).addCase(info, extract(litA))
inc(v.intVal)
else:
var litA = newBuilder("")
genLiteral(p, branch[j], litA)
lineF(p, cpsStmts, "case $1:$n", [extract(litA)])
p.s(cpsStmts).addCase(info, extract(litA))

proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
# analyse 'case' statement:
Expand All @@ -993,26 +993,31 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =

# generate switch part (might be empty):
if splitPoint+1 < n.len:
lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
var hasDefault = false
for i in splitPoint+1..<n.len:
# bug #4230: avoid false sharing between branches:
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
var branch = n[i]
if branch.kind == nkOfBranch:
genCaseRange(p, branch)
else:
# else part of case statement:
lineF(p, cpsStmts, "default:$n", [])
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n", [])
if not hasDefault:
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __builtin_unreachable();$n", [])
elif hasAssume in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
lineF(p, cpsStmts, "}$n", [])
let rca = rdCharLoc(a)
p.s(cpsStmts).addSwitchStmt(rca):
var hasDefault = false
for i in splitPoint+1..<n.len:
# bug #4230: avoid false sharing between branches:
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
var branch = n[i]
var caseBuilder: SwitchCaseBuilder
p.s(cpsStmts).addSwitchCase(caseBuilder):
if branch.kind == nkOfBranch:
genCaseRange(p, branch, caseBuilder)
else:
# else part of case statement:
hasDefault = true
p.s(cpsStmts).addCaseElse(caseBuilder)
do:
exprBlock(p, branch.lastSon, d)
p.s(cpsStmts).addBreak()
if not hasDefault:
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
p.s(cpsStmts).addSwitchElse():
p.s(cpsStmts).addCallStmt("__builtin_unreachable")
elif hasAssume in CC[p.config.cCompiler].props:
p.s(cpsStmts).addSwitchElse():
p.s(cpsStmts).addCallStmt("__assume", cIntValue(0))
if lend != "": fixLabel(p, lend)

proc genCase(p: BProc, t: PNode, d: var TLoc) =
Expand Down
Loading