mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This code has only been tested on x86_64, but is designed to work on the other platforms supported by Apple. Swift SVN r11561
191 lines
4.1 KiB
Swift
191 lines
4.1 KiB
Swift
protocol CVarArg {
|
|
func encode() -> Word[]
|
|
}
|
|
|
|
let _x86_64CountGPRegisters = 6
|
|
let _x86_64CountSSERegisters = 8
|
|
let _x86_64SSERegisterWords = 2
|
|
let _x86_64RegisterSaveWords = _x86_64CountGPRegisters + _x86_64CountSSERegisters * _x86_64SSERegisterWords
|
|
|
|
@asmname="swift_runningOnX86_64" func swift_runningOnX86_64() -> Bool
|
|
|
|
func withVaList<R>(args: CVarArg[], f: (CVaList)->R) -> R {
|
|
var argList: C_va_list = makeC_va_list()
|
|
for a in args {
|
|
argList.append(a)
|
|
}
|
|
return f(argList)
|
|
}
|
|
|
|
|
|
// FIXME: workaround for <rdar://problem/15715225>
|
|
func sizeof(_:Word.metatype) -> Int {
|
|
return Int(Word(Builtin.sizeof(Word)))
|
|
}
|
|
|
|
func encodeBitsAsWords<T: CVarArg>(x: T) -> Word[] {
|
|
var result = Array<Word>(
|
|
(sizeof(T) + sizeof(Word) - 1) / sizeof(Word), 0)
|
|
|
|
c_memcpy(result.base, addressof(&x), UInt64(sizeof(T)))
|
|
return result
|
|
}
|
|
|
|
// CVarArg conformances for the integer types. Everything smaller
|
|
// than a CInt must be promoted to CInt or CUnsignedInt before
|
|
// encoding.
|
|
|
|
// Signed types
|
|
extension Int64 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(self)
|
|
}
|
|
}
|
|
|
|
extension Int32 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(self)
|
|
}
|
|
}
|
|
|
|
extension Int16 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(CInt(self))
|
|
}
|
|
}
|
|
|
|
extension Int8 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(CInt(self))
|
|
}
|
|
}
|
|
|
|
// Unsigned types
|
|
extension UInt64 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(self)
|
|
}
|
|
}
|
|
|
|
extension UInt32 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(self)
|
|
}
|
|
}
|
|
|
|
extension UInt16 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(CUnsignedInt(self))
|
|
}
|
|
}
|
|
|
|
extension UInt8 : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(CUnsignedInt(self))
|
|
}
|
|
}
|
|
|
|
extension COpaquePointer : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(self)
|
|
}
|
|
}
|
|
|
|
extension Float : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(Double(self))
|
|
}
|
|
}
|
|
|
|
extension Double : CVarArg {
|
|
func encode() -> Word[] {
|
|
return encodeBitsAsWords(self)
|
|
}
|
|
}
|
|
|
|
protocol C_va_list {
|
|
func append(arg: CVarArg)
|
|
|
|
@conversion
|
|
func __conversion() -> COpaquePointer
|
|
}
|
|
|
|
struct BasicC_va_list : C_va_list {
|
|
|
|
func append(arg: CVarArg) {
|
|
for x in arg.encode() {
|
|
storage.append(x)
|
|
}
|
|
}
|
|
|
|
@conversion
|
|
func __conversion() -> COpaquePointer {
|
|
return COpaquePointer(storage.base)
|
|
}
|
|
|
|
var storage: Word[] = Array<Word>()
|
|
}
|
|
|
|
func &&<T: LogicValue>(a: T, b: @auto_closure () -> T) -> T {
|
|
return a ? b() : a
|
|
}
|
|
|
|
func ||<T: LogicValue>(a: T, b: @auto_closure () -> T) -> T {
|
|
return a ? a : b()
|
|
}
|
|
|
|
struct X86_64_va_list : C_va_list {
|
|
|
|
struct Header {
|
|
var gp_offset = CUnsignedInt(0)
|
|
var fp_offset = CUnsignedInt(_x86_64CountGPRegisters * sizeof(Word))
|
|
var overflow_arg_area: UnsafePointer<Word> = UnsafePointer<Word>.null()
|
|
var reg_save_area: UnsafePointer<Word> = UnsafePointer<Word>.null()
|
|
}
|
|
|
|
init() {
|
|
// prepare the register save area
|
|
storage = Array(_x86_64RegisterSaveWords, Word(0))
|
|
}
|
|
|
|
func append(arg: CVarArg) {
|
|
var encoded = arg.encode()
|
|
|
|
if ((arg as Float) || (arg as Double)) && sseRegistersUsed < _x86_64CountSSERegisters {
|
|
var startIndex = _x86_64CountGPRegisters + (sseRegistersUsed * _x86_64SSERegisterWords)
|
|
var endIndex = startIndex + encoded.count
|
|
storage[startIndex..endIndex] = encoded
|
|
++sseRegistersUsed
|
|
}
|
|
else if encoded.count == 1 && gpRegistersUsed < _x86_64CountGPRegisters {
|
|
storage[gpRegistersUsed++] = encoded[0]
|
|
}
|
|
else {
|
|
for w in encoded {
|
|
storage.append(w)
|
|
}
|
|
}
|
|
}
|
|
|
|
@conversion
|
|
func __conversion() -> COpaquePointer {
|
|
header.reg_save_area = storage.base
|
|
header.overflow_arg_area = storage.base + _x86_64RegisterSaveWords
|
|
return COpaquePointer(addressof(&self.header))
|
|
}
|
|
|
|
var gpRegistersUsed = 0
|
|
var sseRegistersUsed = 0
|
|
var header = Header()
|
|
var storage: Word[]
|
|
}
|
|
|
|
func makeC_va_list() -> C_va_list {
|
|
if swift_runningOnX86_64() {
|
|
return X86_64_va_list()
|
|
}
|
|
else {
|
|
return BasicC_va_list()
|
|
}
|
|
}
|