Skip to content

Commit 22d98a1

Browse files
committed
stdlib: add support for AAPCS64 variadics
1 parent d8f1736 commit 22d98a1

File tree

3 files changed

+189
-2
lines changed

3 files changed

+189
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,12 @@ getSwiftStdlibType(const clang::TypedefNameDecl *D,
311311
break;
312312

313313
case MappedCTypeKind::VaList:
314-
if (ClangTypeSize != ClangCtx.getTypeSize(ClangCtx.VoidPtrTy))
315-
return std::make_pair(Type(), "");
314+
315+
if (ClangTypeSize != ClangCtx.getTypeSize(ClangCtx.VoidPtrTy)){
316+
if(ClangCtx.getTargetInfo().getBuiltinVaListKind() != clang::TargetInfo::AArch64ABIBuiltinVaList)
317+
return std::make_pair(Type(), "");
318+
}
319+
316320
break;
317321

318322
case MappedCTypeKind::ObjCBool:

stdlib/public/core/CTypes.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,29 @@ extension UInt {
227227
}
228228
}
229229

230+
#if arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
231+
232+
@_fixed_layout
233+
public struct CVaListPointer {
234+
@_versioned // FIXME(sil-serialize-all)
235+
internal var value: (__stack: UnsafeMutablePointer<Int>?,
236+
__gr_top: UnsafeMutablePointer<Int>?,
237+
__vr_top: UnsafeMutablePointer<Int>?,
238+
__gr_off: Int32,
239+
__vr_off: Int32)
240+
241+
@_inlineable // FIXME(sil-serialize-all)
242+
public // @testable
243+
init(__stack: UnsafeMutablePointer<Int>?,
244+
__gr_top: UnsafeMutablePointer<Int>?,
245+
__vr_top: UnsafeMutablePointer<Int>?,
246+
__gr_off: Int32,
247+
__vr_off: Int32) {
248+
value = (__stack, __gr_top, __vr_top, __gr_off, __vr_off)
249+
}
250+
}
251+
252+
#else
230253
/// A wrapper around a C `va_list` pointer.
231254
@_fixed_layout
232255
public struct CVaListPointer {
@@ -248,6 +271,8 @@ extension CVaListPointer : CustomDebugStringConvertible {
248271
}
249272
}
250273

274+
#endif
275+
251276
@_versioned
252277
@_inlineable
253278
internal func _memcpy(

stdlib/public/core/VarArgs.swift

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,30 @@ internal let _registerSaveWords = _countGPRegisters + _countSSERegisters * _sseR
8585
internal let _countGPRegisters = 16
8686
@_versioned
8787
internal let _registerSaveWords = _countGPRegisters
88+
89+
#elseif arch(arm64)
90+
91+
// ARM IHI 0055B
92+
// va_list may refer to any paramenter may be in one of three memory locations:
93+
// 1. GP register save area x0 - x7
94+
// 2. FP/SIMD register save area q0 - q7
95+
// 3. Stack argument area
96+
//
97+
98+
@_versioned
99+
internal let _countGPRegisters = 8
100+
101+
@_versioned
102+
internal let _countFPRegisters = 8
103+
104+
//128bit, 2 64bit word
105+
@_versioned
106+
internal let _fpRegisterWords = 2
107+
108+
@_versioned
109+
internal let _registerSaveWords = _countGPRegisters + (_countFPRegisters * _fpRegisterWords)
110+
111+
88112
#endif
89113

90114
#if arch(s390x)
@@ -467,6 +491,140 @@ final internal class _VaListBuilder {
467491
internal var storage: ContiguousArray<Int>
468492
}
469493

494+
#elseif arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
495+
496+
497+
@_fixed_layout // FIXME(sil-serialize-all)
498+
@_versioned // FIXME(sil-serialize-all)
499+
final internal class _VaListBuilder {
500+
501+
@_inlineable // FIXME(sil-serialize-all)
502+
@_versioned // FIXME(sil-serialize-all)
503+
internal init() {
504+
// prepare the register save area
505+
allocated = _registerSaveWords
506+
storage = allocStorage(wordCount: allocated)
507+
// append stack arguments after register save area
508+
count = allocated
509+
}
510+
511+
@_inlineable // FIXME(sil-serialize-all)
512+
@_versioned // FIXME(sil-serialize-all)
513+
deinit {
514+
if let allocatedStorage = storage {
515+
deallocStorage(wordCount: allocated, storage: allocatedStorage)
516+
}
517+
}
518+
519+
@_inlineable // FIXME(sil-serialize-all)
520+
@_versioned // FIXME(sil-serialize-all)
521+
internal func append(_ arg: CVarArg) {
522+
var encoded = arg._cVarArgEncoding
523+
524+
if arg is _CVarArgPassedAsDouble
525+
&& fpRegistersUsed < _countFPRegisters {
526+
var startIndex = (fpRegistersUsed * _fpRegisterWords)
527+
for w in encoded {
528+
storage[startIndex] = w
529+
startIndex += 1
530+
}
531+
fpRegistersUsed += 1
532+
}else if encoded.count == 1
533+
&& !(arg is _CVarArgPassedAsDouble)
534+
&& gpRegistersUsed < _countGPRegisters {
535+
var startIndex = ( _fpRegisterWords * _countFPRegisters) + gpRegistersUsed
536+
storage[startIndex] = encoded[0]
537+
gpRegistersUsed += 1
538+
}else{
539+
//arguments in stack slot
540+
appendWords(encoded)
541+
}
542+
}
543+
544+
@_inlineable // FIXME(sil-serialize-all)
545+
@_versioned // FIXME(sil-serialize-all)
546+
internal func va_list() -> CVaListPointer {
547+
let vr_top = storage + (_fpRegisterWords * _countFPRegisters)
548+
let gr_top = vr_top + _countGPRegisters
549+
550+
return CVaListPointer(__stack: gr_top, __gr_top: gr_top,
551+
__vr_top: vr_top, __gr_off: -64, __vr_off: -128)
552+
}
553+
554+
@_inlineable // FIXME(sil-serialize-all)
555+
@_versioned // FIXME(sil-serialize-all)
556+
internal func appendWords(_ words: [Int]) {
557+
let newCount = count + words.count
558+
if newCount > allocated {
559+
let oldAllocated = allocated
560+
let oldStorage = storage
561+
let oldCount = count
562+
563+
allocated = max(newCount, allocated * 2)
564+
let newStorage = allocStorage(wordCount: allocated)
565+
storage = newStorage
566+
// count is updated below
567+
568+
if let allocatedOldStorage = oldStorage {
569+
newStorage.moveInitialize(from: allocatedOldStorage, count: oldCount)
570+
deallocStorage(wordCount: oldAllocated, storage: allocatedOldStorage)
571+
}
572+
}
573+
574+
let allocatedStorage = storage!
575+
for word in words {
576+
allocatedStorage[count] = word
577+
count += 1
578+
}
579+
}
580+
581+
@_inlineable // FIXME(sil-serialize-all)
582+
@_versioned // FIXME(sil-serialize-all)
583+
internal func rawSizeAndAlignment(
584+
_ wordCount: Int
585+
) -> (Builtin.Word, Builtin.Word) {
586+
return ((wordCount * MemoryLayout<Int>.stride)._builtinWordValue,
587+
requiredAlignmentInBytes._builtinWordValue)
588+
}
589+
590+
@_inlineable // FIXME(sil-serialize-all)
591+
@_versioned // FIXME(sil-serialize-all)
592+
internal func allocStorage(wordCount: Int) -> UnsafeMutablePointer<Int> {
593+
let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
594+
let rawStorage = Builtin.allocRaw(rawSize, rawAlignment)
595+
return UnsafeMutablePointer<Int>(rawStorage)
596+
}
597+
598+
@_versioned // FIXME(sil-serialize-all)
599+
internal func deallocStorage(
600+
wordCount: Int, storage: UnsafeMutablePointer<Int>
601+
) {
602+
let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
603+
Builtin.deallocRaw(storage._rawValue, rawSize, rawAlignment)
604+
}
605+
606+
@_versioned // FIXME(sil-serialize-all)
607+
internal let requiredAlignmentInBytes = MemoryLayout<Double>.alignment
608+
609+
@_versioned // FIXME(sil-serialize-all)
610+
internal var count = 0
611+
612+
@_versioned // FIXME(sil-serialize-all)
613+
internal var allocated = 0
614+
615+
@_versioned // FIXME(sil-serialize-all)
616+
internal var storage: UnsafeMutablePointer<Int>!
617+
618+
@_versioned // FIXME(sil-serialize-all)
619+
internal var gpRegistersUsed = 0
620+
621+
@_versioned // FIXME(sil-serialize-all)
622+
internal var fpRegistersUsed = 0
623+
624+
@_versioned // FIXME(sil-serialize-all)
625+
internal var overflowWordsUsed = 0
626+
}
627+
470628
#else
471629

472630
/// An object that can manage the lifetime of storage backing a

0 commit comments

Comments
 (0)