Skip to content

Commit 7cfaf9f

Browse files
committed
[stdlib][SR-2239] Refactor AAPCS64 variable argument list support.
This refactoring uses large portions of the already existing code for x86_64 and s390 to implement AAPCS64 __VaListBuilder. The parts where each implementation differ are the x86_64 header, and the order of the general and vector registers. The changes also addresses many of the request from the reviewers in #20862 which were not addressed originally, like the reuse of the already existing code, and the generalizations for the code to be useful for platforms different than Linux (Android, for example).
1 parent 62c4036 commit 7cfaf9f

File tree

3 files changed

+68
-149
lines changed

3 files changed

+68
-149
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,19 @@ getSwiftStdlibType(const clang::TypedefNameDecl *D,
322322
break;
323323

324324
case MappedCTypeKind::VaList:
325-
if (ClangTypeSize != ClangCtx.getTypeSize(ClangCtx.VoidPtrTy)) {
326-
if (ClangCtx.getTargetInfo().getBuiltinVaListKind() !=
327-
clang::TargetInfo::AArch64ABIBuiltinVaList)
325+
switch (ClangCtx.getTargetInfo().getBuiltinVaListKind()) {
326+
case clang::TargetInfo::CharPtrBuiltinVaList:
327+
case clang::TargetInfo::VoidPtrBuiltinVaList:
328+
case clang::TargetInfo::PowerABIBuiltinVaList:
329+
case clang::TargetInfo::AAPCSABIBuiltinVaList:
330+
assert(ClangCtx.getTypeSize(ClangCtx.VoidPtrTy) == ClangTypeSize &&
331+
"expected va_list type to be sizeof(void *)");
332+
break;
333+
case clang::TargetInfo::AArch64ABIBuiltinVaList:
334+
break;
335+
case clang::TargetInfo::PNaClABIBuiltinVaList:
336+
case clang::TargetInfo::SystemZBuiltinVaList:
337+
case clang::TargetInfo::X86_64ABIBuiltinVaList:
328338
return std::make_pair(Type(), "");
329339
}
330340
break;

stdlib/public/core/CTypes.swift

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,15 @@ extension UInt {
219219
}
220220

221221
/// A wrapper around a C `va_list` pointer.
222-
#if arch(arm64) && os(Linux)
222+
#if arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Windows))
223223
@_fixed_layout
224224
public struct CVaListPointer {
225225
@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)
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)
231231

232232
@inlinable // unsafe-performance
233233
public // @testable
@@ -236,7 +236,17 @@ public struct CVaListPointer {
236236
__vr_top: UnsafeMutablePointer<Int>?,
237237
__gr_off: Int32,
238238
__vr_off: Int32) {
239-
value = (__stack, __gr_top, __vr_top, __gr_off, __vr_off)
239+
_value = (__stack, __gr_top, __vr_top, __gr_off, __vr_off)
240+
}
241+
}
242+
243+
extension CVaListPointer : CustomDebugStringConvertible {
244+
public var debugDescription: String {
245+
return "(\(_value.__stack.debugDescription), " +
246+
"\(_value.__gr_top.debugDescription), " +
247+
"\(_value.__vr_top.debugDescription), " +
248+
"\(_value.__gr_off), " +
249+
"\(_value.__vr_off))"
240250
}
241251
}
242252

stdlib/public/core/VarArgs.swift

Lines changed: 38 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ internal let _countGPRegisters = 16
9191
@usableFromInline
9292
internal let _registerSaveWords = _countGPRegisters
9393

94-
#elseif arch(arm64) && os(Linux)
94+
#elseif arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Windows))
9595
// ARM Procedure Call Standard for aarch64. (IHI0055B)
9696
// The va_list type may refer to any parameter in a parameter list may be in one
9797
// of three memory locations depending on its type and position in the argument
@@ -408,7 +408,7 @@ extension Float80 : CVarArg, _CVarArgAligned {
408408
public var _cVarArgEncoding: [Int] {
409409
return _encodeBitsAsWords(self)
410410
}
411-
411+
412412
/// Returns the required alignment in bytes of
413413
/// the value returned by `_cVarArgEncoding`.
414414
@inlinable // FIXME(sil-serialize-all)
@@ -419,7 +419,7 @@ extension Float80 : CVarArg, _CVarArgAligned {
419419
}
420420
#endif
421421

422-
#if arch(x86_64) || arch(s390x)
422+
#if arch(x86_64) || arch(s390x) || (arch(arm64) && !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Windows)))
423423

424424
/// An object that can manage the lifetime of storage backing a
425425
/// `CVaListPointer`.
@@ -429,6 +429,7 @@ extension Float80 : CVarArg, _CVarArgAligned {
429429
@_fixed_layout
430430
@usableFromInline // c-abi
431431
final internal class __VaListBuilder {
432+
#if arch(x86_64) || arch(s390x)
432433
@_fixed_layout // c-abi
433434
@usableFromInline
434435
internal struct Header {
@@ -445,15 +446,19 @@ final internal class __VaListBuilder {
445446
@usableFromInline // c-abi
446447
internal var reg_save_area: UnsafeMutablePointer<Int>?
447448
}
449+
#endif
448450

449451
@usableFromInline // c-abi
450452
internal var gpRegistersUsed = 0
451453
@usableFromInline // c-abi
452454
internal var fpRegistersUsed = 0
453455

456+
#if arch(x86_64) || arch(s390x)
454457
@usableFromInline // c-abi
455458
final // Property must be final since it is used by Builtin.addressof.
456459
internal var header = Header()
460+
#endif
461+
457462
@usableFromInline // c-abi
458463
internal var storage: ContiguousArray<Int>
459464

@@ -470,12 +475,16 @@ final internal class __VaListBuilder {
470475
internal func append(_ arg: CVarArg) {
471476
var encoded = arg._cVarArgEncoding
472477

473-
#if arch(x86_64)
478+
#if arch(x86_64) || arch(arm64)
474479
let isDouble = arg is _CVarArgPassedAsDouble
475480

476481
if isDouble && fpRegistersUsed < _countFPRegisters {
477-
var startIndex = _countGPRegisters
478-
+ (fpRegistersUsed * _fpRegisterWords)
482+
#if arch(arm64)
483+
var startIndex = fpRegistersUsed * _fpRegisterWords
484+
#else
485+
var startIndex = _countGPRegisters
486+
+ (fpRegistersUsed * _fpRegisterWords)
487+
#endif
479488
for w in encoded {
480489
storage[startIndex] = w
481490
startIndex += 1
@@ -485,7 +494,12 @@ final internal class __VaListBuilder {
485494
else if encoded.count == 1
486495
&& !isDouble
487496
&& gpRegistersUsed < _countGPRegisters {
488-
storage[gpRegistersUsed] = encoded[0]
497+
#if arch(arm64)
498+
let startIndex = ( _fpRegisterWords * _countFPRegisters) + gpRegistersUsed
499+
#else
500+
let startIndex = gpRegistersUsed
501+
#endif
502+
storage[startIndex] = encoded[0]
489503
gpRegistersUsed += 1
490504
}
491505
else {
@@ -510,139 +524,24 @@ final internal class __VaListBuilder {
510524

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

648547
#else

0 commit comments

Comments
 (0)