Skip to content

Commit deb0f1f

Browse files
authored
Merge pull request #20862 from futurejones/master-aarch64-VarArgs
[stdlib][SR-2239]: add support for AArch64 variadics
2 parents fb8b9e1 + 4a03b3c commit deb0f1f

File tree

3 files changed

+170
-2
lines changed

3 files changed

+170
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,11 @@ getSwiftStdlibType(const clang::TypedefNameDecl *D,
322322
break;
323323

324324
case MappedCTypeKind::VaList:
325-
if (ClangTypeSize != ClangCtx.getTypeSize(ClangCtx.VoidPtrTy))
326-
return std::make_pair(Type(), "");
325+
if (ClangTypeSize != ClangCtx.getTypeSize(ClangCtx.VoidPtrTy)) {
326+
if (ClangCtx.getTargetInfo().getBuiltinVaListKind() !=
327+
clang::TargetInfo::AArch64ABIBuiltinVaList)
328+
return std::make_pair(Type(), "");
329+
}
327330
break;
328331

329332
case MappedCTypeKind::ObjCBool:

stdlib/public/core/CTypes.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,29 @@ extension UInt {
219219
}
220220

221221
/// A wrapper around a C `va_list` pointer.
222+
#if arch(arm64) && os(Linux)
223+
@_fixed_layout
224+
public struct CVaListPointer {
225+
@usableFromInline // unsafe-performance
226+
internal var value: (__stack: UnsafeMutablePointer<Int>?,
227+
__gr_top: UnsafeMutablePointer<Int>?,
228+
__vr_top: UnsafeMutablePointer<Int>?,
229+
__gr_off: Int32,
230+
__vr_off: Int32)
231+
232+
@inlinable // unsafe-performance
233+
public // @testable
234+
init(__stack: UnsafeMutablePointer<Int>?,
235+
__gr_top: UnsafeMutablePointer<Int>?,
236+
__vr_top: UnsafeMutablePointer<Int>?,
237+
__gr_off: Int32,
238+
__vr_off: Int32) {
239+
value = (__stack, __gr_top, __vr_top, __gr_off, __vr_off)
240+
}
241+
}
242+
243+
#else
244+
222245
@_fixed_layout
223246
public struct CVaListPointer {
224247
@usableFromInline // unsafe-performance
@@ -238,6 +261,8 @@ extension CVaListPointer : CustomDebugStringConvertible {
238261
}
239262
}
240263

264+
#endif
265+
241266
@inlinable
242267
internal func _memcpy(
243268
dest destination: UnsafeMutableRawPointer,

stdlib/public/core/VarArgs.swift

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,23 @@ internal let _registerSaveWords = _countGPRegisters + _countFPRegisters * _fpReg
9090
internal let _countGPRegisters = 16
9191
@usableFromInline
9292
internal let _registerSaveWords = _countGPRegisters
93+
94+
#elseif arch(arm64) && os(Linux)
95+
// ARM Procedure Call Standard for aarch64. (IHI0055B)
96+
// The va_list type may refer to any parameter in a parameter list may be in one
97+
// of three memory locations depending on its type and position in the argument
98+
// list :
99+
// 1. GP register save area x0 - x7
100+
// 2. 128-bit FP/SIMD register save area q0 - q7
101+
// 3. Stack argument area
102+
@usableFromInline
103+
internal let _countGPRegisters = 8
104+
@usableFromInline
105+
internal let _countFPRegisters = 8
106+
@usableFromInline
107+
internal let _fpRegisterWords = 16 / MemoryLayout<Int>.size
108+
@usableFromInline
109+
internal let _registerSaveWords = _countGPRegisters + (_countFPRegisters * _fpRegisterWords)
93110
#endif
94111

95112
#if arch(s390x)
@@ -498,6 +515,129 @@ final internal class _VaListBuilder {
498515
Builtin.addressof(&self.header)))
499516
}
500517
}
518+
#elseif arch(arm64) && os(Linux)
519+
520+
@_fixed_layout // FIXME(sil-serialize-all)
521+
@usableFromInline // FIXME(sil-serialize-all)
522+
final internal class _VaListBuilder {
523+
@usableFromInline // FIXME(sil-serialize-all)
524+
internal init() {
525+
// Prepare the register save area.
526+
allocated = _registerSaveWords
527+
storage = allocStorage(wordCount: allocated)
528+
// Append stack arguments after register save area.
529+
count = allocated
530+
}
531+
532+
@usableFromInline // FIXME(sil-serialize-all)
533+
deinit {
534+
if let allocatedStorage = storage {
535+
deallocStorage(wordCount: allocated, storage: allocatedStorage)
536+
}
537+
}
538+
539+
@usableFromInline // FIXME(sil-serialize-all)
540+
internal func append(_ arg: CVarArg) {
541+
var encoded = arg._cVarArgEncoding
542+
543+
if arg is _CVarArgPassedAsDouble
544+
&& fpRegistersUsed < _countFPRegisters {
545+
var startIndex = (fpRegistersUsed * _fpRegisterWords)
546+
for w in encoded {
547+
storage[startIndex] = w
548+
startIndex += 1
549+
}
550+
fpRegistersUsed += 1
551+
} else if encoded.count == 1
552+
&& !(arg is _CVarArgPassedAsDouble)
553+
&& gpRegistersUsed < _countGPRegisters {
554+
var startIndex = ( _fpRegisterWords * _countFPRegisters) + gpRegistersUsed
555+
storage[startIndex] = encoded[0]
556+
gpRegistersUsed += 1
557+
} else {
558+
// Arguments in stack slot.
559+
appendWords(encoded)
560+
}
561+
}
562+
563+
@usableFromInline // FIXME(sil-serialize-all)
564+
internal func va_list() -> CVaListPointer {
565+
let vr_top = storage + (_fpRegisterWords * _countFPRegisters)
566+
let gr_top = vr_top + _countGPRegisters
567+
568+
return CVaListPointer(__stack: gr_top, __gr_top: gr_top,
569+
__vr_top: vr_top, __gr_off: -64, __vr_off: -128)
570+
}
571+
572+
@usableFromInline // FIXME(sil-serialize-all)
573+
internal func appendWords(_ words: [Int]) {
574+
let newCount = count + words.count
575+
if newCount > allocated {
576+
let oldAllocated = allocated
577+
let oldStorage = storage
578+
let oldCount = count
579+
580+
allocated = max(newCount, allocated * 2)
581+
let newStorage = allocStorage(wordCount: allocated)
582+
storage = newStorage
583+
// Count is updated below.
584+
if let allocatedOldStorage = oldStorage {
585+
newStorage.moveInitialize(from: allocatedOldStorage, count: oldCount)
586+
deallocStorage(wordCount: oldAllocated, storage: allocatedOldStorage)
587+
}
588+
}
589+
590+
let allocatedStorage = storage!
591+
for word in words {
592+
allocatedStorage[count] = word
593+
count += 1
594+
}
595+
}
596+
597+
@usableFromInline // FIXME(sil-serialize-all)
598+
internal func rawSizeAndAlignment(
599+
_ wordCount: Int
600+
) -> (Builtin.Word, Builtin.Word) {
601+
return ((wordCount * MemoryLayout<Int>.stride)._builtinWordValue,
602+
requiredAlignmentInBytes._builtinWordValue)
603+
}
604+
605+
@usableFromInline // FIXME(sil-serialize-all)
606+
internal func allocStorage(wordCount: Int) -> UnsafeMutablePointer<Int> {
607+
let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
608+
let rawStorage = Builtin.allocRaw(rawSize, rawAlignment)
609+
return UnsafeMutablePointer<Int>(rawStorage)
610+
}
611+
612+
@usableFromInline // FIXME(sil-serialize-all)
613+
internal func deallocStorage(
614+
wordCount: Int, storage: UnsafeMutablePointer<Int>
615+
) {
616+
let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
617+
Builtin.deallocRaw(storage._rawValue, rawSize, rawAlignment)
618+
}
619+
620+
@usableFromInline // FIXME(sil-serialize-all)
621+
internal let requiredAlignmentInBytes = MemoryLayout<Double>.alignment
622+
623+
@usableFromInline // FIXME(sil-serialize-all)
624+
internal var count = 0
625+
626+
@usableFromInline // FIXME(sil-serialize-all)
627+
internal var allocated = 0
628+
629+
@usableFromInline // FIXME(sil-serialize-all)
630+
internal var storage: UnsafeMutablePointer<Int>!
631+
632+
@usableFromInline // FIXME(sil-serialize-all)
633+
internal var gpRegistersUsed = 0
634+
635+
@usableFromInline // FIXME(sil-serialize-all)
636+
internal var fpRegistersUsed = 0
637+
638+
@usableFromInline // FIXME(sil-serialize-all)
639+
internal var overflowWordsUsed = 0
640+
}
501641

502642
#else
503643

0 commit comments

Comments
 (0)