Skip to content

Commit 283cddb

Browse files
authored
Merge pull request #20708 from futurejones/swift-4.2-aarch64-VarArgs
[stdlib][SR-2239]: add support for AArch64 variadics
2 parents 50537bd + 3e2793c commit 283cddb

File tree

3 files changed

+178
-2
lines changed

3 files changed

+178
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,11 @@ 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+
if (ClangTypeSize != ClangCtx.getTypeSize(ClangCtx.VoidPtrTy)) {
315+
if (ClangCtx.getTargetInfo().getBuiltinVaListKind() !=
316+
clang::TargetInfo::AArch64ABIBuiltinVaList)
317+
return std::make_pair(Type(), "");
318+
}
316319
break;
317320

318321
case MappedCTypeKind::ObjCBool:

stdlib/public/core/CTypes.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,29 @@ extension UInt {
221221
}
222222
}
223223

224+
#if arch(arm64) && os(Linux)
225+
@_fixed_layout
226+
public struct CVaListPointer {
227+
@_versioned // FIXME(sil-serialize-all)
228+
internal var value: (__stack: UnsafeMutablePointer<Int>?,
229+
__gr_top: UnsafeMutablePointer<Int>?,
230+
__vr_top: UnsafeMutablePointer<Int>?,
231+
__gr_off: Int32,
232+
__vr_off: Int32)
233+
234+
@_inlineable // FIXME(sil-serialize-all)
235+
public // @testable
236+
init(__stack: UnsafeMutablePointer<Int>?,
237+
__gr_top: UnsafeMutablePointer<Int>?,
238+
__vr_top: UnsafeMutablePointer<Int>?,
239+
__gr_off: Int32,
240+
__vr_off: Int32) {
241+
value = (__stack, __gr_top, __vr_top, __gr_off, __vr_off)
242+
}
243+
}
244+
245+
#else
246+
224247
/// A wrapper around a C `va_list` pointer.
225248
@_fixed_layout
226249
public struct CVaListPointer {
@@ -242,6 +265,8 @@ extension CVaListPointer : CustomDebugStringConvertible {
242265
}
243266
}
244267

268+
#endif
269+
245270
@inlinable
246271
internal func _memcpy(
247272
dest destination: UnsafeMutableRawPointer,

stdlib/public/core/VarArgs.swift

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,23 @@ internal let _registerSaveWords = _countGPRegisters + _countSSERegisters * _sseR
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+
@_versioned
103+
internal let _countGPRegisters = 8
104+
@_versioned
105+
internal let _countFPRegisters = 8
106+
@_versioned
107+
internal let _fpRegisterWords = 16 / MemoryLayout<Int>.size
108+
@_versioned
109+
internal let _registerSaveWords = _countGPRegisters + (_countFPRegisters * _fpRegisterWords)
93110
#endif
94111

95112
#if arch(s390x)
@@ -476,6 +493,137 @@ final internal class _VaListBuilder {
476493
internal var storage: ContiguousArray<Int>
477494
}
478495

496+
#elseif arch(arm64) && os(Linux)
497+
498+
@_fixed_layout // FIXME(sil-serialize-all)
499+
@_versioned // FIXME(sil-serialize-all)
500+
final internal class _VaListBuilder {
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+
if let allocatedOldStorage = oldStorage {
568+
newStorage.moveInitialize(from: allocatedOldStorage, count: oldCount)
569+
deallocStorage(wordCount: oldAllocated, storage: allocatedOldStorage)
570+
}
571+
}
572+
573+
let allocatedStorage = storage!
574+
for word in words {
575+
allocatedStorage[count] = word
576+
count += 1
577+
}
578+
}
579+
580+
@_inlineable // FIXME(sil-serialize-all)
581+
@_versioned // FIXME(sil-serialize-all)
582+
internal func rawSizeAndAlignment(
583+
_ wordCount: Int
584+
) -> (Builtin.Word, Builtin.Word) {
585+
return ((wordCount * MemoryLayout<Int>.stride)._builtinWordValue,
586+
requiredAlignmentInBytes._builtinWordValue)
587+
}
588+
589+
@_inlineable // FIXME(sil-serialize-all)
590+
@_versioned // FIXME(sil-serialize-all)
591+
internal func allocStorage(wordCount: Int) -> UnsafeMutablePointer<Int> {
592+
let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
593+
let rawStorage = Builtin.allocRaw(rawSize, rawAlignment)
594+
return UnsafeMutablePointer<Int>(rawStorage)
595+
}
596+
597+
@_versioned // FIXME(sil-serialize-all)
598+
internal func deallocStorage(
599+
wordCount: Int, storage: UnsafeMutablePointer<Int>
600+
) {
601+
let (rawSize, rawAlignment) = rawSizeAndAlignment(wordCount)
602+
Builtin.deallocRaw(storage._rawValue, rawSize, rawAlignment)
603+
}
604+
605+
@_versioned // FIXME(sil-serialize-all)
606+
internal let requiredAlignmentInBytes = MemoryLayout<Double>.alignment
607+
608+
@_versioned // FIXME(sil-serialize-all)
609+
internal var count = 0
610+
611+
@_versioned // FIXME(sil-serialize-all)
612+
internal var allocated = 0
613+
614+
@_versioned // FIXME(sil-serialize-all)
615+
internal var storage: UnsafeMutablePointer<Int>!
616+
617+
@_versioned // FIXME(sil-serialize-all)
618+
internal var gpRegistersUsed = 0
619+
620+
@_versioned // FIXME(sil-serialize-all)
621+
internal var fpRegistersUsed = 0
622+
623+
@_versioned // FIXME(sil-serialize-all)
624+
internal var overflowWordsUsed = 0
625+
}
626+
479627
#else
480628

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

0 commit comments

Comments
 (0)