mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 02:43:41 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88f556b486 | ||
|
|
343b304461 | ||
|
|
37e3573b61 | ||
|
|
09d40ea41b | ||
|
|
326a4592f1 | ||
|
|
df71f4602e | ||
|
|
f496c0e14c | ||
|
|
9d9d860797 | ||
|
|
ef5c4ffaa2 | ||
|
|
95c9d4cd7b | ||
|
|
7f92d26470 | ||
|
|
284bbe2eb7 | ||
|
|
42ebed76e6 | ||
|
|
4fada54c6b | ||
|
|
9510e1a55c |
@@ -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
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
2103
compiler/nir/ast2ir.nim
Normal file
File diff suppressed because it is too large
Load Diff
78
compiler/nir/cir.nim
Normal file
78
compiler/nir/cir.nim
Normal 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
22
compiler/nir/nir.nim
Normal 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
314
compiler/nir/nirinsts.nim
Normal 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)
|
||||
78
compiler/nir/nirlineinfos.nim
Normal file
78
compiler/nir/nirlineinfos.nim
Normal 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
97
compiler/nir/nirslots.nim
Normal 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
339
compiler/nir/nirtypes.nim
Normal 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
426
compiler/nir/types2ir.nim
Normal 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
2
compiler/nir/utils.nim
Normal file
@@ -0,0 +1,2 @@
|
||||
template unreachable*(s = "unreachable") = raiseAssert s
|
||||
template todo*(s = "todo") = raiseAssert s
|
||||
@@ -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 """
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user