Compare commits

...

15 Commits

Author SHA1 Message Date
ringabout
88f556b486 merge upstream code 2023-10-04 15:07:11 +08:00
ringabout
343b304461 Merge remote-tracking branch 'upstream/araq-nir' into pr_ast2ir 2023-10-04 15:03:36 +08:00
Araq
37e3573b61 NIR: implemented builtin 2023-10-03 23:57:38 +02:00
ringabout
09d40ea41b adds entry point and debug code 2023-10-03 22:27:19 +08:00
Araq
326a4592f1 progress 2023-10-03 09:08:20 +02:00
araq
df71f4602e baby steps 2023-10-02 14:23:42 +02:00
araq
f496c0e14c progress 2023-10-01 12:53:38 +02:00
araq
9d9d860797 support for annotations that can be used for calling conventions 2023-10-01 10:34:37 +02:00
araq
ef5c4ffaa2 same chance recursive types work [CI skip] 2023-10-01 09:41:37 +02:00
Araq
95c9d4cd7b bugfix 2023-10-01 07:49:05 +02:00
araq
7f92d26470 type generation for closures 2023-10-01 01:43:06 +02:00
araq
284bbe2eb7 some varargs handling 2023-10-01 01:28:19 +02:00
araq
42ebed76e6 progress 2023-10-01 01:15:53 +02:00
araq
4fada54c6b WIP: translate the AST into the IR 2023-10-01 00:06:56 +02:00
araq
9510e1a55c NIR: An immediate representation for Nim. WIP 2023-09-30 21:02:01 +02:00
20 changed files with 3481 additions and 18 deletions

View File

@@ -936,7 +936,7 @@ type
# it won't cause problems
# for skModule the string literal to output for
# deprecated modules.
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
when defined(nimsuggest):
allUsages*: seq[TLineInfo]
@@ -2173,3 +2173,7 @@ const
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0

View File

@@ -95,11 +95,11 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
lineCg(p, cpsStmts, "$1 = 0;$n", [accessor])
else:
raiseAssert "unexpected set type kind"
of {tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyRange, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable}:
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
discard
proc specializeReset(p: BProc, a: TLoc) =

View File

@@ -1446,7 +1446,8 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])

View File

@@ -17,6 +17,8 @@ import
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas
import nir/ast2ir
import pipelineutils
when defined(nimPreviewSlimSystem):
@@ -2109,6 +2111,11 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
if sfInjectDestructors in m.module.flags:
transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN)
if sfMainModule in m.module.flags:
let moduleCon = initModuleCon(m.g.graph, m.config, m.module)
var procCon = initProcCon(moduleCon, nil)
genCode(procCon, transformedN)
if m.hcrOn:
addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard)
else:

View File

@@ -129,10 +129,6 @@ template withBlock(labl: PSym; body: untyped) =
body
popBlock(c, oldLen)
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
template forkT(body) =
let lab1 = c.forkI()
body

View File

@@ -13,6 +13,8 @@ type
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash

View File

@@ -22,6 +22,8 @@ import
modules,
modulegraphs, lineinfos, pathutils, vmprofiler
# ensure NIR compiles:
import nir / nir
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]

2103
compiler/nir/ast2ir.nim Normal file

File diff suppressed because it is too large Load Diff

78
compiler/nir/cir.nim Normal file
View File

@@ -0,0 +1,78 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# We produce C code as a list of tokens.
import std / assertions
import .. / ic / bitabs
type
Token = LitId # indexing into the tokens BiTable[string]
PredefinedToken = enum
IgnoreMe = "<unused>"
EmptyToken = ""
DeclPrefix = "" # the next token is the name of a definition
CurlyLe = "{"
CurlyRi = "}"
ParLe = "("
ParRi = ")"
BracketLe = "["
BracketRi = "]"
NewLine = "\n"
Semicolon = ";"
Comma = ", "
Space = " "
Colon = ":"
Dot = "."
Arrow = "->"
Star = "*"
Amp = "&"
AsgnOpr = " = "
ScopeOpr = "::"
ConstKeyword = "const "
StaticKeyword = "static "
NimString = "NimString"
StrLitPrefix = "(NimChar*)"
StrLitNamePrefix = "Qstr"
LoopKeyword = "while (true) "
WhileKeyword = "while ("
IfKeyword = "if ("
ElseKeyword = "else "
SwitchKeyword = "switch ("
CaseKeyword = "case "
DefaultKeyword = "default:"
BreakKeyword = "break"
NullPtr = "nullptr"
IfNot = "if (!("
ReturnKeyword = "return "
const
ModulePrefix = Token(int(ReturnKeyword)+1)
proc fillTokenTable(tab: var BiTable[string]) =
for e in EmptyToken..high(PredefinedToken):
let id = tab.getOrIncl $e
assert id == LitId(e)
type
GeneratedCode* = object
code: seq[LitId]
tokens: BiTable[string]
proc initGeneratedCode*(): GeneratedCode =
result = GeneratedCode(code: @[], tokens: initBiTable[string]())
fillTokenTable(result.tokens)
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
g.code.add Token(t)
proc add*(g: var GeneratedCode; s: string) {.inline.} =
g.code.add g.tokens.getOrIncl(s)

22
compiler/nir/nir.nim Normal file
View File

@@ -0,0 +1,22 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
## precious information. Can easily be translated into C. And to JavaScript, hopefully.
import nirtypes, nirinsts, ast2ir
when false:
type
Module* = object
types: TypeGraph
data: seq[Tree]
init: seq[Tree]
procs: seq[Tree]

314
compiler/nir/nirinsts.nim Normal file
View File

@@ -0,0 +1,314 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NIR instructions. Somewhat inspired by LLVM's instructions.
import std / [assertions, hashes, strformat]
import .. / ic / bitabs
import nirlineinfos, nirtypes
type
SymId* = distinct int
proc `$`*(s: SymId): string {.borrow.}
proc hash*(s: SymId): Hash {.borrow.}
proc `==`*(a, b: SymId): bool {.borrow.}
type
Opcode* = enum
Nop,
ImmediateVal,
IntVal,
StrVal,
SymDef,
SymUse,
ModuleId,
Typed, # with type ID
NilVal,
Label,
Goto,
CheckedGoto,
LoopLabel,
GotoLoop, # last atom
ModuleSymUse, # `module.x`
ArrayConstr,
ObjConstr,
Ret,
Yld,
Select,
SelectPair, # ((values...), Label)
SelectList, # (values...)
SelectValue, # (value)
SelectRange, # (valueA..valueB)
SummonGlobal,
SummonThreadLocal,
Summon, # x = Summon Typed <Type ID>; x begins to live
Kill, # `Kill x`: scope end for `x`
AddrOf,
ArrayAt, # addr(a[i])
FieldAt, # addr(obj.field)
Load, # a[]
Store, # a[] = b
Asgn, # a = b
SetExc,
TestExc,
Call,
IndirectCall,
CheckedCall, # call that can raise
CheckedIndirectCall, # call that can raise
CheckedAdd, # with overflow checking etc.
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
TestOf,
Emit,
ProcDecl
const
LastAtomicValue = GotoLoop
OpcodeBits = 8'u32
OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
ValueProducing* = {
ImmediateVal,
IntVal,
StrVal,
SymUse,
NilVal,
ModuleSymUse,
ArrayConstr,
ObjConstr,
CheckedAdd,
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
AddrOf,
Load,
ArrayAt,
FieldAt,
TestOf
}
type
Instr* = object # 8 bytes
x: uint32
info: PackedLineInfo
template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
template toX(k: Opcode; operand: uint32): uint32 =
uint32(k) or (operand shl OpcodeBits)
template toX(k: Opcode; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl OpcodeBits)
proc `$`*(n: Instr): string =
result = fmt"{n.kind}: {n.operand}"
type
Tree* = object
nodes: seq[Instr]
Values* = object
numbers: BiTable[int64]
strings: BiTable[string]
type
PatchPos* = distinct int
NodePos* = distinct int
const
InvalidPatchPos* = PatchPos(-1)
proc debug*(t: Tree) {.deprecated.} =
for i in t.nodes:
echo i
proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch*(tree: var Tree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(tree, info, kind)
body
patch(tree, pos)
proc len*(tree: Tree): int {.inline.} = tree.nodes.len
template rawSpan(n: Instr): int = int(operand(n))
proc nextChild(tree: Tree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
nextChild tree, pos
template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
proc span(tree: Tree; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc copyTree*(dest: var Tree; src: Tree) =
let pos = 0
let L = span(src, pos)
let d = dest.nodes.len
dest.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
dest.nodes[d+i] = src.nodes[pos+i]
type
LabelId* = distinct int
proc newLabel*(labelGen: var int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen
proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
assert k in {Label, LoopLabel}
result = LabelId labelGen
t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
inc labelGen
proc boolVal*(t: var Tree; info: PackedLineInfo; b: bool) =
t.nodes.add Instr(x: toX(ImmediateVal, uint32(b)), info: info)
proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
assert k in {Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId) {.inline.} =
let x = prepare(t, info, Summon)
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
patch t, x
proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
type
Value* = distinct Tree
proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
assert k in ValueProducing - ValueProducingAtoms
result = prepare(Tree(dest), info, k)
proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
patch(Tree(dest), pos)
proc localToValue*(info: PackedLineInfo; s: SymId): Value =
result = Value(Tree())
Tree(result).addSymUse info, s
proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
proc extractTemp*(v: Value): SymId =
if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
result = SymId(Tree(v)[NodePos 0].operand)
else:
result = SymId(-1)
proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(Tree(tree), info, kind)
body
patch(tree, pos)
proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
addTyped(Tree(t), info, typ)

View File

@@ -0,0 +1,78 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# For the line information we use 32 bits. They are used as follows:
# Bit 0 (AsideBit): If we have inline line information or not. If not, the
# remaining 31 bits are used as an index into a seq[(LitId, int, int)].
#
# We use 10 bits for the "file ID", this means a program can consist of as much
# as 1024 different files. (If it uses more files than that, the overflow bit
# would be set.)
# This means we have 21 bits left to encode the (line, col) pair. We use 7 bits for the column
# so 128 is the limit and 14 bits for the line number.
# The packed representation supports files with up to 16384 lines.
# Keep in mind that whenever any limit is reached the AsideBit is set and the real line
# information is kept in a side channel.
import std / assertions
const
AsideBit = 1
FileBits = 10
LineBits = 14
ColBits = 7
FileMax = (1 shl FileBits) - 1
LineMax = (1 shl LineBits) - 1
ColMax = (1 shl ColBits) - 1
static:
assert AsideBit + FileBits + LineBits + ColBits == 32
import .. / ic / bitabs # for LitId
type
PackedLineInfo* = distinct uint32
LineInfoManager* = object
aside*: seq[(LitId, int32, int32)]
proc pack*(m: var LineInfoManager; file: LitId; line, col: int32): PackedLineInfo =
if file.uint32 <= FileMax.uint32 and line <= LineMax and col <= ColMax:
let col = if col < 0'i32: 0'u32 else: col.uint32
let line = if line < 0'i32: 0'u32 else: line.uint32
# use inline representation:
result = PackedLineInfo((file.uint32 shl 1'u32) or (line shl uint32(AsideBit + FileBits)) or
(col shl uint32(AsideBit + FileBits + LineBits)))
else:
result = PackedLineInfo((m.aside.len shl 1) or AsideBit)
m.aside.add (file, line, col)
proc unpack*(m: LineInfoManager; i: PackedLineInfo): (LitId, int32, int32) =
let i = i.uint32
if (i and 1'u32) == 0'u32:
# inline representation:
result = (LitId((i shr 1'u32) and FileMax.uint32),
int32((i shr uint32(AsideBit + FileBits)) and LineMax.uint32),
int32((i shr uint32(AsideBit + FileBits + LineBits)) and ColMax.uint32))
else:
result = m.aside[int(i shr 1'u32)]
proc getFileId*(m: LineInfoManager; i: PackedLineInfo): LitId =
result = unpack(m, i)[0]
when isMainModule:
var m = LineInfoManager(aside: @[])
for i in 0'i32..<16388'i32:
for col in 0'i32..<100'i32:
let packed = pack(m, LitId(1023), i, col)
let u = unpack(m, packed)
assert u[0] == LitId(1023)
assert u[1] == i
assert u[2] == col
echo m.aside.len

97
compiler/nir/nirslots.nim Normal file
View File

@@ -0,0 +1,97 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Management of slots. Similar to "register allocation"
## in lower level languages.
import std / [assertions, tables]
import nirtypes, nirinsts
type
SlotManagerFlag* = enum
ReuseTemps,
ReuseVars
SlotManager* = object # "register allocator"
live: Table[SymId, TypeId]
dead: Table[TypeId, seq[SymId]]
flags: set[SlotManagerFlag]
inScope: seq[SymId]
locGen: ref int
proc initSlotManager*(flags: set[SlotManagerFlag]; generator: ref int): SlotManager {.inline.} =
SlotManager(flags: flags, locGen: generator)
proc allocRaw(m: var SlotManager; t: TypeId; f: SlotManagerFlag): SymId {.inline.} =
if f in m.flags and m.dead.hasKey(t) and m.dead[t].len > 0:
result = m.dead[t].pop()
else:
result = SymId(m.locGen[])
inc m.locGen[]
m.inScope.add result
m.live[result] = t
proc allocTemp*(m: var SlotManager; t: TypeId): SymId {.inline.} =
result = allocRaw(m, t, ReuseTemps)
proc allocVar*(m: var SlotManager; t: TypeId): SymId {.inline.} =
result = allocRaw(m, t, ReuseVars)
proc freeLoc*(m: var SlotManager; s: SymId) =
let t = m.live.getOrDefault(s)
assert t.int != 0
m.live.del s
m.dead.mgetOrPut(t, @[]).add s
iterator stillAlive*(m: SlotManager): (SymId, TypeId) =
for k, v in pairs(m.live):
yield (k, v)
proc getType*(m: SlotManager; s: SymId): TypeId {.inline.} = m.live[s]
proc openScope*(m: var SlotManager) =
m.inScope.add SymId(-1) # add marker
proc closeScope*(m: var SlotManager) =
var i = m.inScope.len - 1
while i >= 0:
if m.inScope[i] == SymId(-1):
m.inScope.setLen i-1
break
dec i
when isMainModule:
var m = initSlotManager({ReuseTemps}, new(int))
var g = initTypeGraph()
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5'u64
let finalArrayType = sealType(g, a)
let obj = g.openType ObjectDecl
g.addName "MyType"
g.addField "p", finalArrayType
let objB = sealType(g, obj)
let x = m.allocTemp(objB)
assert x.int == 0
let y = m.allocTemp(objB)
assert y.int == 1
let z = m.allocTemp(Int8Id)
assert z.int == 2
m.freeLoc y
let y2 = m.allocTemp(objB)
assert y2.int == 1

339
compiler/nir/nirtypes.nim Normal file
View File

@@ -0,0 +1,339 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Type system for NIR. Close to C's type system but without its quirks.
import std / [assertions, hashes]
import .. / ic / bitabs
type
NirTypeKind* = enum
VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal, IntVal,
AnnotationVal,
VarargsTy, # the `...` in a C prototype; also the last "atom"
APtrTy, # pointer to aliasable memory
UPtrTy, # pointer to unique/unaliasable memory
AArrayPtrTy, # pointer to array of aliasable memory
UArrayPtrTy, # pointer to array of unique/unaliasable memory
ArrayTy,
LastArrayTy, # array of unspecified size as a last field inside an object
ObjectTy,
UnionTy,
ProcTy,
ObjectDecl,
UnionDecl,
FieldDecl
const
TypeKindBits = 8'u32
TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
type
TypeNode* = object # 4 bytes
x: uint32
template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
template toX(k: NirTypeKind; operand: uint32): uint32 =
uint32(k) or (operand shl TypeKindBits)
template toX(k: NirTypeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl TypeKindBits)
type
TypeId* = distinct int
proc `==`*(a, b: TypeId): bool {.borrow.}
proc hash*(a: TypeId): Hash {.borrow.}
type
TypeGraph* = object
nodes: seq[TypeNode]
names: BiTable[string]
numbers: BiTable[uint64]
const
VoidId* = TypeId 0
Bool8Id* = TypeId 1
Char8Id* = TypeId 2
Int8Id* = TypeId 3
Int16Id* = TypeId 4
Int32Id* = TypeId 5
Int64Id* = TypeId 6
UInt8Id* = TypeId 7
UInt16Id* = TypeId 8
UInt32Id* = TypeId 9
UInt64Id* = TypeId 10
Float32Id* = TypeId 11
Float64Id* = TypeId 12
LastBuiltinId* = 12
proc initTypeGraph*(): TypeGraph =
result = TypeGraph(nodes: @[
TypeNode(x: toX(VoidTy, 0'u32)),
TypeNode(x: toX(BoolTy, 8'u32)),
TypeNode(x: toX(CharTy, 8'u32)),
TypeNode(x: toX(IntTy, 8'u32)),
TypeNode(x: toX(IntTy, 16'u32)),
TypeNode(x: toX(IntTy, 32'u32)),
TypeNode(x: toX(IntTy, 64'u32)),
TypeNode(x: toX(UIntTy, 8'u32)),
TypeNode(x: toX(UIntTy, 16'u32)),
TypeNode(x: toX(UIntTy, 32'u32)),
TypeNode(x: toX(UIntTy, 64'u32)),
TypeNode(x: toX(FloatTy, 32'u32)),
TypeNode(x: toX(FloatTy, 64'u32))
])
assert result.nodes.len == LastBuiltinId+1
type
TypePatchPos* = distinct int
const
InvalidTypePatchPos* = TypePatchPos(-1)
LastAtomicValue = VarargsTy
proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
result = TypePatchPos tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, 1'u32))
proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch(tree: var TypeGraph; pos: TypePatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
template rawSpan(n: TypeNode): int = int(operand(n))
proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield TypeId pos
nextChild tree, pos
template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
result = TypeId(n.int+1)
proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
proc span(tree: TypeGraph; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId a, TypeId b)
proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (TypeId a, TypeId b, TypeId c)
proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestUInt =
assert tree[n].kind == ArrayTy
result = tree.numbers[LitId tree[n].operand]
proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
FieldDecl}
result = prepare(tree, kind)
proc sealType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
# TODO: Search for an existing instance of this type in
# order to reduce memory consumption.
result = TypeId(p)
patch tree, p
proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
assert kind in {ObjectTy, UnionTy}
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, tree.names.getOrIncl(name)))
proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
assert kind in {ObjectTy, UnionTy}
tree.nodes.add TypeNode(x: toX(kind, tree.names.getOrIncl(name)))
proc addVarargs*(tree: var TypeGraph) =
tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
proc getFloat128Type*(tree: var TypeGraph): TypeId =
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
g.nodes.add g[id]
template firstSon(n: TypeId): TypeId = TypeId(n.int+1)
proc addType*(g: var TypeGraph; t: TypeId) =
# We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
if g[t].kind in {ObjectDecl, UnionDecl}:
assert g[t.firstSon].kind == NameVal
let name = LitId g[t.firstSon].operand
if g[t].kind == ObjectDecl:
g.nodes.add TypeNode(x: toX(ObjectTy, name))
else:
g.nodes.add TypeNode(x: toX(UnionTy, name))
else:
let pos = t.int
let L = span(g, pos)
let d = g.nodes.len
g.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
g.nodes[d+i] = g.nodes[pos+i]
proc addArrayLen*(g: var TypeGraph; len: uint64) =
g.nodes.add TypeNode(x: toX(IntVal, g.numbers.getOrIncl(len)))
proc addName*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl(name)))
proc addAnnotation*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl(name)))
proc addField*(g: var TypeGraph; name: string; typ: TypeId) =
let f = g.openType FieldDecl
g.addType typ
g.addName name
discard sealType(g, f)
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
case g[i].kind
of VoidTy: dest.add "void"
of IntTy:
dest.add "i"
dest.addInt g[i].operand
of UIntTy:
dest.add "u"
dest.addInt g[i].operand
of FloatTy:
dest.add "f"
dest.addInt g[i].operand
of BoolTy:
dest.add "b"
dest.addInt g[i].operand
of CharTy:
dest.add "c"
dest.addInt g[i].operand
of NameVal, AnnotationVal:
dest.add g.names[LitId g[i].operand]
of IntVal:
dest.add $g.numbers[LitId g[i].operand]
of VarargsTy:
dest.add "..."
of APtrTy:
dest.add "aptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UPtrTy:
dest.add "uptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of AArrayPtrTy:
dest.add "aArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UArrayPtrTy:
dest.add "uArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of ArrayTy:
dest.add "Array["
let (elems, len) = g.sons2(i)
toString(dest, g, elems)
dest.add ", "
toString(dest, g, len)
dest.add "]"
of LastArrayTy:
# array of unspecified size as a last field inside an object
dest.add "LastArrayTy["
toString(dest, g, g.elementType(i))
dest.add "]"
of ObjectTy:
dest.add "object "
dest.add g.names[LitId g[i].operand]
of UnionTy:
dest.add "union "
dest.add g.names[LitId g[i].operand]
of ProcTy:
dest.add "proc["
for t in sons(g, i): toString(dest, g, t)
dest.add "]"
of ObjectDecl:
dest.add "object["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of UnionDecl:
dest.add "union["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of FieldDecl:
let (typ, name) = g.sons2(i)
toString(dest, g, typ)
dest.add ' '
toString(dest, g, name)
proc toString*(dest: var string; g: TypeGraph) =
var i = 0
while i < g.len:
toString(dest, g, TypeId i)
dest.add '\n'
nextChild g, i
proc `$`(g: TypeGraph): string =
result = ""
toString(result, g)
when isMainModule:
var g = initTypeGraph()
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5'u64
let finalArrayType = sealType(g, a)
let obj = g.openType ObjectDecl
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl("MyType")))
g.addField "p", finalArrayType
discard sealType(g, obj)
echo g

426
compiler/nir/types2ir.nim Normal file
View File

@@ -0,0 +1,426 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import std / [assertions, tables, sets]
import ".." / [ast, types, options, sighashes, modulegraphs]
import nirtypes
type
TypesCon* = object
processed: Table[ItemId, TypeId]
recursionCheck: HashSet[ItemId]
g: TypeGraph
conf: ConfigRef
proc initTypesCon*(conf: ConfigRef): TypesCon =
TypesCon(g: initTypeGraph(), conf: conf)
proc mangle(c: var TypesCon; t: PType): string =
result = $sighashes.hashType(t, c.conf)
template cached(c: var TypesCon; t: PType; body: untyped) =
result = c.processed.getOrDefault(t.itemId)
if result.int == 0:
body
c.processed[t.itemId] = result
proc typeToIr*(c: var TypesCon; t: PType): TypeId
proc collectFieldTypes(c: var TypesCon; n: PNode; dest: var Table[ItemId, TypeId]) =
case n.kind
of nkRecList:
for i in 0..<n.len:
collectFieldTypes(c, n[i], dest)
of nkRecCase:
assert(n[0].kind == nkSym)
collectFieldTypes(c, n[0], dest)
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
collectFieldTypes c, lastSon(n[i]), dest
else: discard
of nkSym:
dest[n.sym.itemId] = typeToIr(c, n.sym.typ)
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
case n.kind
of nkRecList:
for i in 0..<n.len:
objectToIr(c, n[i], fieldTypes, unionId)
of nkRecCase:
assert(n[0].kind == nkSym)
objectToIr(c, n[0], fieldTypes, unionId)
let u = openType(c.g, UnionDecl)
c.g.addName "u_" & $unionId
inc unionId
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
let subObj = openType(c.g, ObjectDecl)
c.g.addName "uo_" & $unionId & "_" & $i
objectToIr c, lastSon(n[i]), fieldTypes, unionId
discard sealType(c.g, subObj)
else: discard
discard sealType(c.g, u)
of nkSym:
c.g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId]
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; t: PType): TypeId =
if t[0] != nil:
# ensure we emitted the base type:
discard typeToIr(c, t[0])
var unionId = 0
var fieldTypes = initTable[ItemId, TypeId]()
collectFieldTypes c, t.n, fieldTypes
let obj = openType(c.g, ObjectDecl)
c.g.addName mangle(c, t)
if t[0] != nil:
c.g.addNominalType(ObjectTy, mangle(c, t[0]))
else:
c.g.addBuiltinType VoidId # object does not inherit
if not lacksMTypeField(t):
let f2 = c.g.openType FieldDecl
let voidPtr = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, voidPtr)
c.g.addName "m_type"
discard sealType(c.g, f2) # FieldDecl
objectToIr c, t.n, fieldTypes, unionId
result = sealType(c.g, obj)
proc objectHeaderToIr(c: var TypesCon; t: PType): TypeId =
result = c.g.nominalType(ObjectTy, mangle(c, t))
proc tupleToIr(c: var TypesCon; t: PType): TypeId =
var fieldTypes = newSeq[TypeId](t.len)
for i in 0..<t.len:
fieldTypes[i] = typeToIr(c, t[i])
let obj = openType(c.g, ObjectDecl)
c.g.addName mangle(c, t)
for i in 0..<t.len:
c.g.addField "f_" & $i, fieldTypes[i]
result = sealType(c.g, obj)
proc procToIr(c: var TypesCon; t: PType; addEnv = false): TypeId =
var fieldTypes = newSeq[TypeId](0)
for i in 0..<t.len:
if not isCompileTimeOnly(t[i]):
fieldTypes.add typeToIr(c, t[i])
let obj = openType(c.g, ProcTy)
case t.callConv
of ccNimCall, ccFastCall, ccClosure: c.g.addAnnotation "__fastcall"
of ccStdCall: c.g.addAnnotation "__stdcall"
of ccCDecl: c.g.addAnnotation "__cdecl"
of ccSafeCall: c.g.addAnnotation "__safecall"
of ccSysCall: c.g.addAnnotation "__syscall"
of ccInline: c.g.addAnnotation "__inline"
of ccNoInline: c.g.addAnnotation "__noinline"
of ccThisCall: c.g.addAnnotation "__thiscall"
of ccNoConvention: c.g.addAnnotation ""
for i in 0..<fieldTypes.len:
c.g.addType fieldTypes[i]
if addEnv:
let a = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, a)
if tfVarargs in t.flags:
c.g.addVarargs()
result = sealType(c.g, obj)
proc nativeInt(c: TypesCon): TypeId =
case c.conf.target.intSize
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
proc openArrayToIr(c: var TypesCon; t: PType): TypeId =
# object (a: ArrayPtr[T], len: int)
let e = lastSon(t)
let mangledBase = mangle(c, e)
let typeName = "NimOpenArray" & mangledBase
let elementType = typeToIr(c, e)
let p = openType(c.g, ObjectDecl)
c.g.addName typeName
let f = c.g.openType FieldDecl
let arr = c.g.openType AArrayPtrTy
c.g.addType elementType
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
c.g.addField "len", c.nativeInt
result = sealType(c.g, p) # ObjectDecl
proc stringToIr(c: var TypesCon; t: PType): TypeId =
#[
NimStrPayload = object
cap: int
data: UncheckedArray[char]
NimStringV2 = object
len: int
p: ptr NimStrPayload
]#
let p = openType(c.g, ObjectDecl)
c.g.addName "NimStrPayload"
c.g.addField "cap", c.nativeInt
let f = c.g.openType FieldDecl
let arr = c.g.openType LastArrayTy
c.g.addBuiltinType Char8Id
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
let payload = sealType(c.g, p)
let str = openType(c.g, ObjectDecl)
c.g.addName "NimStringV2"
c.g.addField "len", c.nativeInt
let fp = c.g.openType FieldDecl
let ffp = c.g.openType APtrTy
c.g.addNominalType ObjectTy, "NimStrPayload"
discard sealType(c.g, ffp) # APtrTy
c.g.addName "p"
discard sealType(c.g, fp) # FieldDecl
result = sealType(c.g, str) # ObjectDecl
proc seqToIr(c: var TypesCon; t: PType): TypeId =
#[
NimSeqPayload[T] = object
cap: int
data: UncheckedArray[T]
NimSeqV2*[T] = object
len: int
p: ptr NimSeqPayload[T]
]#
let e = lastSon(t)
let mangledBase = mangle(c, e)
let payloadName = "NimSeqPayload" & mangledBase
let elementType = typeToIr(c, e)
let p = openType(c.g, ObjectDecl)
c.g.addName payloadName
c.g.addField "cap", c.nativeInt
let f = c.g.openType FieldDecl
let arr = c.g.openType LastArrayTy
c.g.addType elementType
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
let payload = sealType(c.g, p)
let sq = openType(c.g, ObjectDecl)
c.g.addName "NimSeqV2" & mangledBase
c.g.addField "len", c.nativeInt
let fp = c.g.openType FieldDecl
let ffp = c.g.openType APtrTy
c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
discard sealType(c.g, ffp) # APtrTy
c.g.addName "p"
discard sealType(c.g, fp) # FieldDecl
result = sealType(c.g, sq) # ObjectDecl
proc closureToIr(c: var TypesCon; t: PType): TypeId =
# struct {fn(args, void* env), env}
# typedef struct {$n" &
# "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
# "void* ClE_0;$n} $1;$n"
let mangledBase = mangle(c, t)
let typeName = "NimClosure" & mangledBase
let procType = procToIr(c, t, addEnv=true)
let p = openType(c.g, ObjectDecl)
c.g.addName typeName
let f = c.g.openType FieldDecl
c.g.addType procType
c.g.addName "ClP_0"
discard sealType(c.g, f) # FieldDecl
let f2 = c.g.openType FieldDecl
let voidPtr = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, voidPtr)
c.g.addName "ClE_0"
discard sealType(c.g, f2) # FieldDecl
result = sealType(c.g, p) # ObjectDecl
proc typeToIr*(c: var TypesCon; t: PType): TypeId =
case t.kind
of tyInt:
case int(getSize(c.conf, t))
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
of tyInt8: result = Int8Id
of tyInt16: result = Int16Id
of tyInt32: result = Int32Id
of tyInt64: result = Int64Id
of tyFloat:
case int(getSize(c.conf, t))
of 4: result = Float32Id
else: result = Float64Id
of tyFloat32: result = Float32Id
of tyFloat64: result = Float64Id
of tyFloat128: result = getFloat128Type(c.g)
of tyUInt:
case int(getSize(c.conf, t))
of 2: result = UInt16Id
of 4: result = UInt32Id
else: result = UInt64Id
of tyUInt8: result = UInt8Id
of tyUInt16: result = UInt16Id
of tyUInt32: result = UInt32Id
of tyUInt64: result = UInt64Id
of tyBool: result = Bool8Id
of tyChar: result = Char8Id
of tyVoid: result = VoidId
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
result = typeToIr(c, t.lastSon)
of tyEnum:
if firstOrd(c.conf, t) < 0:
result = Int32Id
else:
case int(getSize(c.conf, t))
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = Int32Id
of 8: result = Int64Id
else: result = Int32Id
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = typeToIr(c, t.lastSon)
else:
result = TypeId(-1)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = typeToIr(c, t.n.typ)
else:
result = TypeId(-1)
of tyArray:
cached(c, t):
var n = toInt64(lengthOrd(c.conf, t))
if n <= 0: n = 1 # make an array of at least one element
let elemType = typeToIr(c, t[1])
let a = openType(c.g, ArrayTy)
c.g.addType(elemType)
c.g.addArrayLen uint64(n)
result = sealType(c.g, a)
of tyPtr, tyRef:
cached(c, t):
let e = t.lastSon
if e.kind == tyUncheckedArray:
let elemType = typeToIr(c, e.lastSon)
let a = openType(c.g, AArrayPtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
else:
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, APtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyVar, tyLent:
cached(c, t):
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, APtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tySet:
let s = int(getSize(c.conf, t))
case s
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = UInt32Id
of 8: result = UInt64Id
else:
# array[U8, s]
cached(c, t):
let a = openType(c.g, ArrayTy)
c.g.addType(UInt8Id)
c.g.addArrayLen uint64(s)
result = sealType(c.g, a)
of tyPointer:
let a = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
result = sealType(c.g, a)
of tyObject:
# Objects are special as they can be recursive in Nim. This is easily solvable.
# We check if we are already "processing" t. If so, we produce `ObjectTy`
# instead of `ObjectDecl`.
cached(c, t):
if not c.recursionCheck.containsOrIncl(t.itemId):
result = objectToIr(c, t)
else:
result = objectHeaderToIr(c, t)
of tyTuple:
cached(c, t):
result = tupleToIr(c, t)
of tyProc:
cached(c, t):
if t.callConv == ccClosure:
result = closureToIr(c, t)
else:
result = procToIr(c, t)
of tyVarargs, tyOpenArray:
cached(c, t):
result = openArrayToIr(c, t)
of tyString:
cached(c, t):
result = stringToIr(c, t)
of tySequence:
cached(c, t):
result = seqToIr(c, t)
of tyCstring:
cached(c, t):
let a = openType(c.g, AArrayPtrTy)
c.g.addBuiltinType Char8Id
result = sealType(c.g, a)
of tyUncheckedArray:
# We already handled the `ptr UncheckedArray` in a special way.
cached(c, t):
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, LastArrayTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = TypeId(-1)

2
compiler/nir/utils.nim Normal file
View File

@@ -0,0 +1,2 @@
template unreachable*(s = "unreachable") = raiseAssert s
template todo*(s = "todo") = raiseAssert s

View File

@@ -25,7 +25,7 @@ import
ast, astalgo, idents, lowerings, magicsys, guards, msgs,
renderer, types, modulegraphs, options, spawn, lineinfos
from trees import getMagic, isTrue, getRoot
from trees import getMagic, getRoot
from strutils import `%`
discard """

View File

@@ -198,10 +198,6 @@ proc extractRange*(k: TNodeKind, n: PNode, a, b: int): PNode =
result = newNodeI(k, n.info, b-a+1)
for i in 0..b-a: result[i] = n[i+a]
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
proc getRoot*(n: PNode): PSym =
## ``getRoot`` takes a *path* ``n``. A path is an lvalue expression
## like ``obj.x[i].y``. The *root* of a path is the symbol that can be

View File

@@ -1521,7 +1521,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
frame = frame.next
jumpTo = findExceptionHandler(c, frame, raised)
case jumpTo.why:
case jumpTo.why
of ExceptionGotoHandler:
# Jump to the handler, do nothing when the `finally` block ends.
savedPC = -1

View File

@@ -321,10 +321,6 @@ proc isNotOpr(n: PNode): bool =
n.kind in nkCallKinds and n[0].kind == nkSym and
n[0].sym.magic == mNot
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
proc genWhile(c: PCtx; n: PNode) =
# lab1:
# cond, tmp