164
164
# Same as cgen, for easier genAssignment comparison
165
165
TAssignmentFlag = enum
166
166
needToCopy
167
+ needToCopySinkParam
167
168
168
169
TAssignmentFlags = set [TAssignmentFlag ]
169
170
@@ -4734,6 +4735,31 @@ proc callAssign(
4734
4735
fty = f.globalGetValueType ()
4735
4736
discard g.b.buildCall2 (fty, f, [dest, src, shallow], " " )
4736
4737
4738
+ # TODO using a constant here results in compile-time differences in hash member
4739
+ # order which is weird
4740
+ let noUnwinds = toHashSet (
4741
+ [
4742
+ (" ansi_c" , " c_memchr" ),
4743
+ (" ansi_c" , " c_memcmp" ),
4744
+ (" ansi_c" , " c_memcpy" ),
4745
+ (" ansi_c" , " c_memmove" ),
4746
+ (" ansi_c" , " c_memset" ),
4747
+ (" ansi_c" , " c_strcmp" ),
4748
+ (" ansi_c" , " c_strlen" ),
4749
+ (" ansi_c" , " c_strstr" ),
4750
+ (" ansi_c" , " c_abort" ),
4751
+ (" ansi_c" , " c_malloc" ),
4752
+ (" ansi_c" , " c_calloc" ),
4753
+ (" ansi_c" , " c_free" ),
4754
+ (" ansi_c" , " c_realloc" ),
4755
+ (" nlvm_system" , " mmap" ),
4756
+ (" nlvm_system" , " munmap" ),
4757
+ (" system" , " mmap" ),
4758
+ (" system" , " munmap" ),
4759
+ (" system" , " rawQuit" ),
4760
+ ]
4761
+ )
4762
+
4737
4763
proc addNimFunction (g: LLGen , sym: PSym ): llvm.ValueRef =
4738
4764
# # Add a function prototype for a nim function to the given module
4739
4765
let
@@ -4743,6 +4769,18 @@ proc addNimFunction(g: LLGen, sym: PSym): llvm.ValueRef =
4743
4769
4744
4770
f = g.addNimFunction (name, ty)
4745
4771
4772
+ if sfImportc in sym.flags:
4773
+ if typ[0 ] != nil and typ[0 ].kind in {tyTuple, tyObject} and
4774
+ g.config.getSize (typ[0 ]) <= 16 :
4775
+ # TODO https://github.com/llvm/llvm-project/blob/6cbc64ed922cc69bc292d394ba5c681fa309f404/clang/lib/CodeGen/Targets/X86.cpp#L1783
4776
+ # TODO https://github.com/ziglang/zig/pull/9443
4777
+ g.config.message (
4778
+ sym.info,
4779
+ warnUser,
4780
+ " TODO: C ABI for small struct returns not implemented - there may be issues: " &
4781
+ $ name,
4782
+ )
4783
+
4746
4784
if sfNoReturn in sym.flags:
4747
4785
f.addFuncAttribute (g.attrNoReturn)
4748
4786
@@ -4761,64 +4799,98 @@ proc addNimFunction(g: LLGen, sym: PSym): llvm.ValueRef =
4761
4799
]:
4762
4800
f.addFuncAttribute (g.attrCold)
4763
4801
4764
- if (sym.originatingModule.name.s, sym.name.s) in
4765
- [(" system" , " quit" ), (" ansi_c" , " c_abort" )]:
4802
+ # C functions known to not raise exceptions - can't enable for all importc
4803
+ # functions because they might take a callback or use a global to cause
4804
+ # unwinding :/
4805
+ if (sym.originatingModule.name.s, sym.name.s) in noUnwinds:
4766
4806
f.addFuncAttribute (g.attrNoUnwind)
4767
4807
4768
4808
if sym.originatingModule.name.s == " system" and g.config.selectedGC notin {gcRegions}:
4769
- if sym.name.s in [" allocImpl" , " allocSharedImpl" ]:
4809
+ template allocsize (size, count: uint32 ): uint64 =
4810
+ uint64 (size) shl 32 or uint64 (count)
4811
+
4812
+ template allocsize (size: uint32 ): uint64 =
4813
+ allocsize (size, not 0 'u32 )
4814
+
4815
+ # TODO this constant should be set based on the _target_, not `nlvm` itself
4816
+ const MemAlign =
4817
+ when defined (nimMemAlignTiny):
4818
+ 4
4819
+ elif defined (useMalloc):
4820
+ when defined (amd64): 16 else : 8
4821
+ else :
4822
+ 16
4823
+
4824
+ # TODO using a constant here results in compile-time differences in hash member
4825
+ # order which is weird
4826
+ let allocDefaultAlignedFns = toTable (
4827
+ {
4828
+ " allocImpl" : (AllocFnKindUninitialized , allocsize (0 )),
4829
+ " allocSharedImpl" : (AllocFnKindUninitialized , allocsize (0 )),
4830
+ " alloc0Impl" : (AllocFnKindZeroed , allocsize (0 )),
4831
+ " allocShared0Impl" : (AllocFnKindZeroed , allocsize (0 )),
4832
+ " newObj" : (AllocFnKindZeroed , allocsize (1 )),
4833
+ " newObjRC1" : (AllocFnKindZeroed , allocsize (1 )),
4834
+ " newObjNoInit" : (AllocFnKindUninitialized , allocsize (1 )),
4835
+ " rawNewObj" : (AllocFnKindUninitialized , allocsize (1 )),
4836
+ " alloc" : (AllocFnKindUninitialized , allocsize (1 )),
4837
+ " rawAlloc" : (AllocFnKindUninitialized , allocsize (1 )),
4838
+ }
4839
+ )
4840
+
4841
+ # TODO using a constant here results in compile-time differences in hash member
4842
+ # order which is weird
4843
+ let allocParamAlignedFns = toTable (
4844
+ {
4845
+ " nimNewObj" : (AllocFnKindZeroed , allocsize (0 ), 1 ),
4846
+ " nimNewObjUninit" : (AllocFnKindUninitialized , allocsize (0 ), 1 ),
4847
+ " alignedAlloc" : (AllocFnKindUninitialized , allocsize (0 ), 1 ),
4848
+ " alignedAlloc0" : (AllocFnKindZeroed , allocsize (0 ), 1 ),
4849
+ }
4850
+ )
4851
+
4852
+ if sym.name.s in allocDefaultAlignedFns:
4853
+ let attrs = allocDefaultAlignedFns[sym.name.s]
4770
4854
f.addFuncAttribute (g.lc.createStringAttribute (" alloc-family" , " nimgc" ))
4771
4855
f.addFuncAttribute (
4772
- g.lc.createEnumAttribute (
4773
- attrAllockind, AllocFnKindAlloc or AllocFnKindUninitialized
4774
- )
4856
+ g.lc.createEnumAttribute (attrAllockind, AllocFnKindAlloc or attrs[0 ])
4775
4857
)
4776
- f.addFuncAttribute (g.lc.createEnumAttribute (attrAllocsize, cast [ uint32 ]( - 1 ) ))
4858
+ f.addFuncAttribute (g.lc.createEnumAttribute (attrAllocsize, attrs[ 1 ] ))
4777
4859
f.addAttributeAtIndex (
4778
- AttributeIndex (AttributeReturnIndex ), g.lc.createEnumAttribute (attrAlign, 16 )
4860
+ AttributeIndex (AttributeReturnIndex ),
4861
+ g.lc.createEnumAttribute (attrAlign, MemAlign ),
4779
4862
)
4780
4863
f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNonnull)
4781
4864
f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNoalias)
4782
- elif sym.name.s in [" alloc0Impl" , " allocShared0Impl" ]:
4865
+ elif sym.name.s in allocParamAlignedFns:
4866
+ let attrs = allocParamAlignedFns[sym.name.s]
4783
4867
f.addFuncAttribute (g.lc.createStringAttribute (" alloc-family" , " nimgc" ))
4784
4868
f.addFuncAttribute (
4785
- g.lc.createEnumAttribute (attrAllockind, AllocFnKindAlloc or AllocFnKindZeroed )
4869
+ g.lc.createEnumAttribute (
4870
+ attrAllockind, AllocFnKindAlloc or AllocFnKindAligned or attrs[0 ]
4871
+ )
4786
4872
)
4787
- f.addFuncAttribute (g.lc.createEnumAttribute (attrAllocsize, cast [ uint32 ]( - 1 ) ))
4873
+ f.addFuncAttribute (g.lc.createEnumAttribute (attrAllocsize, attrs[ 1 ] ))
4788
4874
f.addAttributeAtIndex (
4789
- AttributeIndex (AttributeReturnIndex ), g.lc.createEnumAttribute (attrAlign, 16 )
4875
+ AttributeIndex (attrs[ 2 ] + 1 ), g.lc.createEnumAttribute (attrAllocalign, 0 )
4790
4876
)
4791
4877
f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNonnull)
4792
4878
f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNoalias)
4793
- elif sym.name.s in [" alloc0" , " newObj" , " newObjRC1" , " rawAlloc0" , " allocShared0" ]:
4879
+ elif sym.name.s in [" dealloc" , " deallocShared" ]:
4880
+ f.addFuncAttribute (g.attrNoUnwind)
4794
4881
f.addFuncAttribute (g.lc.createStringAttribute (" alloc-family" , " nimgc" ))
4795
- f.addFuncAttribute (
4796
- g.lc.createEnumAttribute (attrAllockind, AllocFnKindAlloc or AllocFnKindZeroed )
4797
- )
4798
- f.addFuncAttribute (
4799
- g.lc.createEnumAttribute (attrAllocsize, uint64 (1 shl 32 ) + cast [uint32 ](- 1 ))
4800
- )
4882
+ f.addFuncAttribute (g.lc.createEnumAttribute (attrAllockind, AllocFnKindFree ))
4883
+
4801
4884
f.addAttributeAtIndex (
4802
- AttributeIndex (AttributeReturnIndex ), g.lc.createEnumAttribute (attrAlign, 16 )
4885
+ AttributeIndex (typ.len - 1 ), g.lc.createEnumAttribute (attrAllocptr, 0 )
4803
4886
)
4804
- f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNonnull)
4805
- f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNoalias)
4806
- elif sym.name.s in
4807
- [" alloc" , " rawAlloc" , " newObjNoInit" , " rawNewObj" , " rawAlloc" , " allocShared" ]:
4887
+ elif sym.name.s in [" rawDealloc" ]:
4888
+ f.addFuncAttribute (g.attrNoUnwind)
4808
4889
f.addFuncAttribute (g.lc.createStringAttribute (" alloc-family" , " nimgc" ))
4809
- f.addFuncAttribute (
4810
- g.lc.createEnumAttribute (
4811
- attrAllockind, AllocFnKindAlloc or AllocFnKindUninitialized
4812
- )
4813
- )
4814
- f.addFuncAttribute (
4815
- g.lc.createEnumAttribute (attrAllocsize, uint64 (1 shl 32 ) + cast [uint32 ](- 1 ))
4816
- )
4890
+ f.addFuncAttribute (g.lc.createEnumAttribute (attrAllockind, AllocFnKindFree ))
4817
4891
f.addAttributeAtIndex (
4818
- AttributeIndex (AttributeReturnIndex ), g.lc.createEnumAttribute (attrAlign, 16 )
4892
+ AttributeIndex (2 ), g.lc.createEnumAttribute (attrAllocptr, 0 )
4819
4893
)
4820
- f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNonnull)
4821
- f.addAttributeAtIndex (AttributeIndex (AttributeReturnIndex ), g.attrNoalias)
4822
4894
4823
4895
f
4824
4896
@@ -5388,7 +5460,7 @@ proc genBoundsCheckArray(g: LLGen, arr, firstOrd, lastOrd, a, b: llvm.ValueRef)
5388
5460
5389
5461
proc buildLoadVar (g: LLGen , typ: PType , v: llvm.ValueRef ): llvm.ValueRef =
5390
5462
if typ.skipTypes (abstractInst).kind in {tyVar, tyLent}:
5391
- g.b.buildLoad2 (g.ptrTy , v)
5463
+ g.b.buildLoad2 (g.llType ( last (typ. skipTypes (abstractInst))) , v)
5392
5464
else :
5393
5465
v
5394
5466
@@ -5427,14 +5499,12 @@ proc genOpenArrayConv(
5427
5499
else :
5428
5500
axp.v
5429
5501
v = g.buildLoadVar (n.typ, ax)
5430
-
5431
5502
(g.getNimSeqDataPtr (seqTy, v), g.loadNimSeqLen (v))
5432
5503
of tyOpenArray, tyVarargs:
5433
- let ax = g.buildLoadVar (n.typ, g.genNode (n, false ).v)
5434
-
5504
+ let ax = g.buildLoadVar (n.typ, g.genNode (n, true ).v)
5435
5505
(
5436
- g.b.buildLoad2 (g.ptrTy, g. buildOpenArrayDataGEP ( ax)),
5437
- g.b.buildLoad2 (g.intTy, g. buildOpenArrayLenGEP ( ax)),
5506
+ g.b.buildExtractValue (ax, 0 , g. nn ( " p " , ax)),
5507
+ g.b.buildExtractValue (ax, 1 , g. nn ( " l " , ax)),
5438
5508
)
5439
5509
of tyArray, tyUncheckedArray:
5440
5510
var v = g.genNode (n, true ).v
@@ -5798,9 +5868,8 @@ proc genAssignment(g: LLGen, dest, src: LLValue, typ: PType, flags: TAssignmentF
5798
5868
of tyString:
5799
5869
if optSeqDestructors in g.config.globalOptions:
5800
5870
discard g.b.buildStore (src.v, dest.v)
5801
- elif ({needToCopy} * flags == {} and src.storage != OnStatic ) or canMove (
5802
- g, src.lode
5803
- ):
5871
+ elif ({needToCopy, needToCopySinkParam} * flags == {} and src.storage != OnStatic ) or
5872
+ canMove (g, src.lode):
5804
5873
g.genRefAssign (dest, src.v)
5805
5874
else :
5806
5875
if (dest.storage == OnStack and g.config.selectedGC != gcGo) or
@@ -5961,9 +6030,15 @@ proc genConstBracket(g: LLGen, n: PNode): llvm.ValueRef =
5961
6030
for i, s in n.sons:
5962
6031
vals[i] = g.genConstInitializer (s)
5963
6032
let s = constArray (et, vals)
5964
- if typ.kind in {tyArray, tyUncheckedArray}:
6033
+ case typ.kind
6034
+ of tyArray, tyUncheckedArray:
5965
6035
s
5966
- else :
6036
+ of tyOpenArray:
6037
+ let lit = g.m.addPrivateConstant (s.typeOfX, g.nn (" .oa" , n))
6038
+ lit.setInitializer (s)
6039
+
6040
+ llvm.constNamedStruct (g.llOpenArrayType (), [lit, g.constInt64 (vals.len)])
6041
+ of tySequence:
5967
6042
let
5968
6043
ll = g.constNimInt (vals.len)
5969
6044
cap = g.constNimInt (vals.len + g.strLitFlag)
@@ -5980,6 +6055,8 @@ proc genConstBracket(g: LLGen, n: PNode): llvm.ValueRef =
5980
6055
lit = g.m.addPrivateConstant (payload.typeOfX, g.nn (" .seq" , n))
5981
6056
lit.setInitializer (payload)
5982
6057
lit
6058
+ else :
6059
+ raiseAssert " Unexpected const bracket: " & $ typ.kind
5983
6060
5984
6061
proc genConstObjConstr (g: LLGen , n: PNode ): llvm.ValueRef =
5985
6062
let
@@ -6748,6 +6825,8 @@ proc genMagicLengthStr(g: LLGen, n: PNode): LLValue =
6748
6825
fty = llvm.functionType (g.csizetTy, [g.primitives[tyCString]])
6749
6826
f = g.m.getOrInsertFunction (" strlen" , fty)
6750
6827
6828
+ f.addFuncAttribute (g.attrNoUnwind)
6829
+
6751
6830
let v1 = g.buildTruncOrExt (
6752
6831
g.b.buildCall2 (fty, f, [v], g.nn (" str.len.call" , n)), g.primitives[tyInt], false
6753
6832
)
@@ -7790,13 +7869,49 @@ proc genMagicMove(g: LLGen, n: PNode, load: bool): LLValue =
7790
7869
7791
7870
g.buildStoreNull (ty, tmpx.v)
7792
7871
g.genObjectInit (n[1 ].typ, tmpx.v)
7793
- let flags =
7794
- if not canMove (g, n[1 ]):
7795
- {needToCopy}
7872
+ if g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
7873
+ g.genAssignment (tmpx, g.maybeLoadValue (ty, ax, lx), n[1 ].typ, {})
7874
+ var op = getAttachedOp (g.graph, n.typ, attachedWasMoved)
7875
+ if op == nil :
7876
+ g.callReset (n[1 ].skipAddr.typ, ax)
7796
7877
else :
7797
- {}
7798
- g.genAssignment (tmpx, g.maybeLoadValue (ty, ax, lx), n[1 ].typ, flags)
7799
- g.callReset (n[1 ].skipAddr.typ, ax)
7878
+ case skipTypes (n[1 ].skipAddr.typ, abstractVar + {tyStatic}).kind
7879
+ of tyOpenArray, tyVarargs:
7880
+ # todo fixme generated `wasMoved` hooks for
7881
+ # openarrays, but it probably shouldn't?
7882
+ raiseAssert " TODO"
7883
+ # var s: string
7884
+ # if reifiedOpenArray(a.lode):
7885
+ # if a.t.kind in {tyVar, tyLent}:
7886
+ # s = "$1->Field0, $1->Field1" % [rdLoc(a)]
7887
+ # else:
7888
+ # s = "$1.Field0, $1.Field1" % [rdLoc(a)]
7889
+ # else:
7890
+ # s = "$1, $1Len_0" % [rdLoc(a)]
7891
+ # linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), s])
7892
+ else :
7893
+ let
7894
+ f = g.genFunctionWithBody (op).v
7895
+ fty = f.globalGetValueType ()
7896
+ discard g.b.buildCall2 (fty, f, [ax.v], " " )
7897
+ else :
7898
+ if n[1 ].kind == nkSym and isSinkParam (n[1 ].sym):
7899
+ let ty2 = g.llType (n[1 ].typ.skipTypes ({tySink}))
7900
+ let tmp2 =
7901
+ LLValue (v: g.localAlloca (ty2, g.nn (" move.tmp2" , n[1 ])), storage: OnStack )
7902
+
7903
+ g.buildStoreNull (ty2, tmp2.v)
7904
+ g.genObjectInit (n[1 ].typ.skipTypes ({tySink}), tmp2.v)
7905
+
7906
+ g.genAssignment (
7907
+ tmp2, g.maybeLoadValue (ty, ax, lx), n[1 ].typ, {needToCopySinkParam}
7908
+ )
7909
+ g.genAssignment (tmpx, g.buildLoadValue (ty2, tmp2), n[1 ].typ, {})
7910
+ g.callReset (n[1 ].typ.skipTypes ({tySink}), tmp2)
7911
+ else :
7912
+ g.genAssignment (tmpx, g.maybeLoadValue (ty, ax, lx), n[1 ].typ, {})
7913
+ g.callReset (n[1 ].skipAddr.typ, ax)
7914
+
7800
7915
g.maybeLoadValue (ty, tmpx, load)
7801
7916
7802
7917
proc genMagicDestroy (g: LLGen , n: PNode ) =
0 commit comments