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

vm: implement case string in bytecode #1148

Merged
merged 4 commits into from
Jan 30, 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
2 changes: 0 additions & 2 deletions compiler/vm/packed_env.nim
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,6 @@ proc loadEnv*(dst: var TCtx, src: PackedEnv) =

of cnstSliceListInt: co.intSlices = loadSliceList[BiggestInt](src, id)
of cnstSliceListFloat: co.floatSlices = loadSliceList[BiggestFloat](src, id)
of cnstSliceListStr: co.strSlices = loadSliceList[ConstantId](src, id)
of cnstNode: unreachable()

co
Expand Down Expand Up @@ -871,7 +870,6 @@ func storeEnv*(enc: var PackedEncoder, dst: var PackedEnv, c: TCtx) =

of cnstSliceListInt: dst.storeSliceList(c.intSlices)
of cnstSliceListFloat: dst.storeSliceList(c.floatSlices)
of cnstSliceListStr: dst.storeSliceList(c.strSlices)
of cnstNode:
# node constants are not created in a non-compiletime context
unreachable()
Expand Down
31 changes: 2 additions & 29 deletions compiler/vm/vm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2013,39 +2013,12 @@ proc rawExecute(c: var TCtx, t: var VmThread, pc: var int): YieldReason =
for s in list.items:
if v in s: return true

func cmp(a: string, b: VmString): int =
let minLen = min(a.len, b.len)
if minLen > 0:
result = cmpMem(unsafeAddr a[0], b.data.rawPointer, minLen)
if result == 0:
result = a.len - b.len

var cond = false
case value.kind
of cnstInt: cond = regs[ra].intVal == value.intVal
of cnstString: cond = regs[ra].strVal == value.strVal
of cnstFloat: cond = regs[ra].floatVal == value.floatVal
of cnstSliceListInt: cond = regs[ra].intVal in value.intSlices
of cnstSliceListFloat: cond = regs[ra].floatVal in value.floatSlices
of cnstSliceListStr:
# string slice-lists don't store the strings directly, but the ID of
# a constant instead
let str = regs[ra].strVal
for s in value.strSlices.items:
let a = c.constants[s.a].strVal
let r = cmp(a, str)
if s.a == s.b:
# no need to compare the string with both slice elements if
# they're the same
if r == 0:
cond = true
break
else:
let b = c.constants[s.b].strVal
if r <= 0 and cmp(b, str) >= 0:
cond = true
break

else:
unreachable(value.kind)

Expand Down Expand Up @@ -2200,7 +2173,7 @@ proc rawExecute(c: var TCtx, t: var VmThread, pc: var int): YieldReason =
# cases where non-NimNode PNodes need to be stored in registers
# seems unnecessary however.
regs[ra] = TFullReg(kind: rkNimNode, nimNode: cnst.node)
of cnstSliceListInt..cnstSliceListStr:
of cnstSliceListInt..cnstSliceListFloat:
# A slice-list must not be used with `LdConst`
assert false

Expand All @@ -2212,7 +2185,7 @@ proc rawExecute(c: var TCtx, t: var VmThread, pc: var int): YieldReason =
of cnstString:
# load the string literal directly into the destination
deref(regs[ra].handle).strVal.newVmString(cnst.strVal, c.allocator)
of cnstInt, cnstFloat, cnstNode, cnstSliceListInt..cnstSliceListStr:
of cnstInt, cnstFloat, cnstNode, cnstSliceListInt..cnstSliceListFloat:
raiseVmError(VmEvent(kind: vmEvtErrInternal, msg: "illegal constant"))
of opcLdGlobal:
let rb = instr.regBx - wordExcess
Expand Down
4 changes: 0 additions & 4 deletions compiler/vm/vmdef.nim
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,6 @@ type
# slice-lists are used for implementing `opcBranch` (branch for case stmt)
cnstSliceListInt
cnstSliceListFloat
cnstSliceListStr

ConstantId* = int ## The ID of a `VmConstant`. Currently just an index into
## `TCtx.constants`
Expand All @@ -368,9 +367,6 @@ type
intSlices*: seq[Slice[BiggestInt]]
of cnstSliceListFloat:
floatSlices*: seq[Slice[BiggestFloat]]
of cnstSliceListStr:
strSlices*: seq[Slice[ConstantId]] ## Stores the ids of string constants
## as a storage optimization

VmArgs* = object
ra*, rb*, rc*: Natural
Expand Down
43 changes: 33 additions & 10 deletions compiler/vm/vmgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -757,11 +757,6 @@ proc genBranchLit(c: var TCtx, n: CgNode, t: PType): int =
cnst.floatSlices.fillSliceList(values):
it.floatVal

of tyString:
cnst = VmConstant(kind: cnstSliceListStr)
cnst.strSlices.fillSliceList(values):
c.toStringCnst(it.strVal)

else:
unreachable(t.kind)

Expand Down Expand Up @@ -801,16 +796,44 @@ proc genCase(c: var TCtx; n: CgNode) =
var endings: seq[TPosition] = @[]
withDest(tmp):
c.gen(n[0], tmp)
# branch tmp, codeIdx
# fjmp elseLabel

# iterate of/else branches
for i in 1..<n.len:
let branch = n[i]
if isOfBranch(branch):
let b = genBranchLit(c, branch, selType)
c.gABx(branch, opcBranch, tmp, b)
let elsePos = c.xjmp(branch.lastSon, opcFJmp, tmp)
var elsePos: TPosition
if selType.kind == tyString:
# special handling for string case statements: generate a sequence
# of comparisons
let
cond = c.getTemp(slotTempInt)
# we re-use the `endings` list for collecting the jumps to the
# body:
start = endings.len

for j in 0..<branch.len - 1:
let
it = branch[j]
val = c.genx(it)
# generate: ``if tmp == label: goto body``
c.gABC(it, opcEqStr, cond, tmp, val)
endings.add c.xjmp(it, opcTJmp, cond)
c.freeTemp(val)

c.freeTemp(cond)
# emit a jump to the next branch:
elsePos = c.xjmp(branch.lastSon, opcJmp)
# patch the jumps to the body:
for j in start..<endings.len:
c.patch(endings[j])
endings.setLen(start)
else:
# branch tmp, codeIdx
# fjmp elseLabel
let b = genBranchLit(c, branch, selType)
c.gABx(branch, opcBranch, tmp, b)
elsePos = c.xjmp(branch.lastSon, opcFJmp, tmp)

c.gen(branch.lastSon)
if i < n.len-1:
endings.add(c.xjmp(branch.lastSon, opcJmp, 0))
Expand Down
2 changes: 1 addition & 1 deletion compiler/vm/vmutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ proc codeListing*(c: TCtx; start = 0; last = -1): seq[DebugVmCodeEntry] =
of cnstFloat: newFloatNode(nkFloatLit, cnst.floatVal)
of cnstString: newStrNode(nkStrLit, cnst.strVal)
of cnstNode: cnst.node
of cnstSliceListInt..cnstSliceListStr:
of cnstSliceListInt..cnstSliceListFloat:
# XXX: translate into an `nkOfBranch`?
newNode(nkEmpty)
else:
Expand Down
Loading