Skip to content

Commit

Permalink
[Backport 1.6] Itanium mangling scheme nim-lang#23301
Browse files Browse the repository at this point in the history
  • Loading branch information
jmgomez committed Feb 12, 2024
1 parent ac1dc03 commit 3139a5a
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 8 deletions.
94 changes: 87 additions & 7 deletions compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,94 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name):
result.add "_0"


proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result

proc makeUnique(m: BModule; s: PSym, name: string = ""): Rope =
let str = if name == "": s.name.s else: name
result.add str
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item

proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s
if makeUnique:
name = $makeUnique(m, s, name)
"N" & encodeName(s.owner.name.s) & encodeName(name) & "E"

proc elementType*(n: PType): PType {.inline.} = n.sons[^1]

proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind

proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
result.add encodeSym(m, s, makeUnique)
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
result.add encodeType(m, s.typ[i])

if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
else:
m.g.mangledPrcs.incl(result)

proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r
if result == nil:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_"
result.add rope s.itemId.item
if $s.loc.r == "":
var result: Rope
if s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
m.g.config.symbolFiles == disabledSf:
result = mangleProc(m, s, false).rope
else:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item # s.disamb #
if m.hcrOn:
result.add "_"
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
Expand Down
6 changes: 5 additions & 1 deletion compiler/ccgutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import
ast, types, hashes, strutils, msgs, wordrecg,
platform, trees, options, cgendata

import std/[hashes, strutils]

when defined(nimPreviewSlimSystem):
import std/assertions

proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
case n.kind
of nkStmtList:
Expand Down Expand Up @@ -141,4 +146,3 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
if s.position == 0 and retType != nil and retType.kind == tyLent:
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)

1 change: 1 addition & 0 deletions compiler/cgendata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]

TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
Expand Down
192 changes: 192 additions & 0 deletions tests/codegen/titaniummangle.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
discard """
targets: "c cpp"
matrix: "--debugger:native"
ccodecheck: "'_ZN14titaniummangle8testFuncE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE6stringN14titaniummangle3FooE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3int7varargsI6stringE'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle3BooE'"
ccodecheck: "'_ZN8testFunc8testFuncE8typeDescIN14titaniummangle17EnumAnotherSampleEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI14uncheckedArrayI3intEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3setIN14titaniummangle10EnumSampleEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE4procI6string6stringE'"
ccodecheck: "'_ZN8testFunc8testFuncE3intN10Comparable10ComparableE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI3int3intE7cstring'"
ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI5float5floatE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrIN14titaniummangle3FooEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3ptrI3intEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3refIN14titaniummangle3FooEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3varIN14titaniummangle3FooEE5int325int323refIN14titaniummangle3FooEE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE3varI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9openArrayI6stringE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE5arrayI7range013intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI3intE'"
ccodecheck: "'_ZN14titaniummangle8testFuncE10Container2I5int325int32E'"
ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI10Container2I5int325int32EE'"
"""

#When debugging this notice that if one check fails, it can be due to any of the above.

type
Comparable = concept x, y
(x < y) is bool

type
Foo = object
a: int32
b: int32

FooTuple = tuple
a: int
b: int
Container[T] = object
data: T
Container2[T, T2] = object
data: T
data2: T2

Boo = distinct Foo

Coo = Foo

Doo = Boo | Foo

TestProc = proc(a:string): string

type EnumSample = enum
a, b, c

type EnumAnotherSample = enum
a2, b2, c2

proc testFunc(a: set[EnumSample]) =
echo $a

proc testFunc(a: typedesc) =
echo $a

proc testFunc(a: ptr Foo) =
echo repr a

proc testFunc(s: string, a: Coo) =
echo repr a

proc testFunc(s: int, a: Comparable) =
echo repr a

proc testFunc(a: TestProc) =
let b = ""
echo repr a("")

proc testFunc(a: ref Foo) =
echo repr a

proc testFunc(b: Boo) =
echo repr b

proc testFunc(a: ptr UncheckedArray[int]) =
echo repr a

proc testFunc(a: ptr int) =
echo repr a

proc testFunc(a: ptr ptr int) =
echo repr a

proc testFunc(e: FooTuple, str: cstring) =
echo e

proc testFunc(e: (float, float)) =
echo e

proc testFunc(e: EnumSample) =
echo e

proc testFunc(e: var int) =
echo e

proc testFunc(e: var Foo, a, b: int32, refFoo: ref Foo) =
echo e

proc testFunc(xs: Container[int]) =
let a = 2
echo xs

proc testFunc(xs: Container2[int32, int32]) =
let a = 2
echo xs

proc testFunc(xs: Container[Container2[int32, int32]]) =
let a = 2
echo xs

proc testFunc(xs: seq[int]) =
let a = 2
echo xs

proc testFunc(xs: openArray[string]) =
let a = 2
echo xs

proc testFunc(xs: array[2, int]) =
let a = 2
echo xs

proc testFunc(e: EnumAnotherSample) =
echo e

proc testFunc(a, b: int) =
echo "hola"
discard

proc testFunc(a: int, xs: varargs[string]) =
let a = 10
for x in xs:
echo x

proc testFunc() =
var a = 2
var aPtr = a.addr
var foo = Foo()
let refFoo : ref Foo = new(Foo)
let b = Foo().Boo()
let d: Doo = Foo()
testFunc("", Coo())
testFunc(1, )
testFunc(b)
testFunc(EnumAnotherSample)
var t = [1, 2]
let uArr = cast[ptr UncheckedArray[int]](t.addr)
testFunc(uArr)
testFunc({})
testFunc(proc(s:string): string = "test")
testFunc(20, a.int32)
testFunc(20, 2)
testFunc(EnumSample.c)
testFunc(EnumAnotherSample.c2)
testFunc((2, 1), "adios")
testFunc((22.1, 1.2))
testFunc(a.addr)
testFunc(foo.addr)
testFunc(aPtr.addr)
testFunc(refFoo)
testFunc(foo, 2, 1, refFoo)
testFunc(a)
testFunc(@[2, 1, 2])
testFunc(@["hola"])
testFunc(2, "hola", "adios")
let arr: array[2, int] = [2, 1]
testFunc(arr)
testFunc(Container[int](data: 10))
let c2 = Container2[int32, int32](data: 10, data2: 20)
testFunc(c2)
testFunc(Container[Container2[int32, int32]](data: c2))


testFunc()

0 comments on commit 3139a5a

Please sign in to comment.