diff --git a/lib/IRGen/IRABIDetailsProvider.cpp b/lib/IRGen/IRABIDetailsProvider.cpp index 92e48ce3b14aa..66b4addbeb0a1 100644 --- a/lib/IRGen/IRABIDetailsProvider.cpp +++ b/lib/IRGen/IRABIDetailsProvider.cpp @@ -38,6 +38,7 @@ #include "clang/CodeGen/ModuleBuilder.h" #include "clang/CodeGen/SwiftCallingConv.h" #include "llvm/IR/DerivedTypes.h" +#include using namespace swift; using namespace irgen; @@ -59,14 +60,25 @@ getPrimitiveTypeFromLLVMType(ASTContext &ctx, const llvm::Type *type) { default: return std::nullopt; } - } else if (type->isFloatTy()) { + } + if (type->isFloatTy()) { return ctx.getFloatType(); - } else if (type->isDoubleTy()) { + } + if (type->isDoubleTy()) { return ctx.getDoubleType(); - } else if (type->isPointerTy()) { + } + if (type->isPointerTy()) { return ctx.getOpaquePointerType(); } - // FIXME: Handle vector type. + if (const auto *vecTy = dyn_cast(type)) { + auto elemTy = getPrimitiveTypeFromLLVMType(ctx, vecTy->getElementType()); + if (!elemTy) + return std::nullopt; + auto elemCount = vecTy->getElementCount(); + if (!elemCount.isFixed()) + return std::nullopt; + return BuiltinVectorType::get(ctx, *elemTy, elemCount.getFixedValue()); + } return std::nullopt; } diff --git a/lib/PrintAsClang/PrimitiveTypeMapping.cpp b/lib/PrintAsClang/PrimitiveTypeMapping.cpp index dd951f7334d97..69089ab7b4ee2 100644 --- a/lib/PrintAsClang/PrimitiveTypeMapping.cpp +++ b/lib/PrintAsClang/PrimitiveTypeMapping.cpp @@ -14,8 +14,13 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Module.h" +#include "swift/AST/Type.h" +#include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" #include "swift/ClangImporter/ClangImporter.h" +#include +#include +#include using namespace swift; @@ -101,13 +106,19 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) { #define MAP_SIMD_TYPE(BASENAME, _, __) \ StringRef simd2##BASENAME = "swift_" #BASENAME "2"; \ mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "2")}] = { \ - simd2##BASENAME, simd2##BASENAME, simd2##BASENAME, false}; \ + simd2##BASENAME, simd2##BASENAME, simd2##BASENAME, false, true}; \ + mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier("simd_" #BASENAME "2")}] = { \ + simd2##BASENAME, simd2##BASENAME, simd2##BASENAME, false, true}; \ StringRef simd3##BASENAME = "swift_" #BASENAME "3"; \ mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "3")}] = { \ - simd3##BASENAME, simd3##BASENAME, simd3##BASENAME, false}; \ + simd3##BASENAME, simd3##BASENAME, simd3##BASENAME, false, true}; \ + mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier("simd_" #BASENAME "3")}] = { \ + simd3##BASENAME, simd3##BASENAME, simd3##BASENAME, false, true}; \ StringRef simd4##BASENAME = "swift_" #BASENAME "4"; \ mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "4")}] = { \ - simd4##BASENAME, simd4##BASENAME, simd4##BASENAME, false}; + simd4##BASENAME, simd4##BASENAME, simd4##BASENAME, false, true}; \ + mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier("simd_" #BASENAME "4")}] = { \ + simd4##BASENAME, simd4##BASENAME, simd4##BASENAME, false, true}; #include "swift/ClangImporter/SIMDMappedTypes.def" static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4, "must add or remove special name mappings if max number of " @@ -130,7 +141,8 @@ PrimitiveTypeMapping::getMappedTypeInfoOrNull(const TypeDecl *typeDecl) { std::optional PrimitiveTypeMapping::getKnownObjCTypeInfo(const TypeDecl *typeDecl) { if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl)) - return ClangTypeInfo{typeInfo->objcName, typeInfo->canBeNullable}; + return ClangTypeInfo{typeInfo->objcName, typeInfo->canBeNullable, + typeInfo->simd}; return std::nullopt; } @@ -138,7 +150,8 @@ std::optional PrimitiveTypeMapping::getKnownCTypeInfo(const TypeDecl *typeDecl) { if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl)) { if (typeInfo->cName) - return ClangTypeInfo{*typeInfo->cName, typeInfo->canBeNullable}; + return ClangTypeInfo{*typeInfo->cName, typeInfo->canBeNullable, + typeInfo->simd}; } return std::nullopt; } @@ -147,7 +160,32 @@ std::optional PrimitiveTypeMapping::getKnownCxxTypeInfo(const TypeDecl *typeDecl) { if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl)) { if (typeInfo->cxxName) - return ClangTypeInfo{*typeInfo->cxxName, typeInfo->canBeNullable}; + return ClangTypeInfo{*typeInfo->cxxName, typeInfo->canBeNullable, + typeInfo->simd}; } return std::nullopt; } + +std::optional +PrimitiveTypeMapping::getKnownSIMDTypeInfo(Type t, ASTContext &ctx) { + auto vecTy = t->getAs(); + if (!vecTy) + return std::nullopt; + + auto elemTy = vecTy->getElementType(); + auto numElems = vecTy->getNumElements(); + + if (mappedTypeNames.empty()) + initialize(ctx); + + Identifier moduleName = ctx.Id_simd; + std::string elemTyName = elemTy.getString(); + // While the element type starts with an upper case, vector types start with + // lower case. + elemTyName[0] = std::tolower(elemTyName[0]); + Identifier name = ctx.getIdentifier(elemTyName + std::to_string(numElems)); + auto iter = mappedTypeNames.find({moduleName, name}); + if (iter == mappedTypeNames.end()) + return std::nullopt; + return ClangTypeInfo{*iter->second.cName, false, true}; +} diff --git a/lib/PrintAsClang/PrimitiveTypeMapping.h b/lib/PrintAsClang/PrimitiveTypeMapping.h index 91f397bd42124..e09448a04f2ee 100644 --- a/lib/PrintAsClang/PrimitiveTypeMapping.h +++ b/lib/PrintAsClang/PrimitiveTypeMapping.h @@ -21,18 +21,21 @@ namespace swift { class ASTContext; class TypeDecl; +class Type; /// Provides a mapping from Swift's primitive types to C / Objective-C / C++ /// primitive types. /// /// Certain types have mappings that differ in different language modes. -/// For example, Swift's `Int` maps to `NSInteger` for Objective-C declarations, -/// but to something like `intptr_t` or `swift::Int` for C and C++ declarations. +/// For example, Swift's `Int` maps to `NSInteger` for Objective-C +/// declarations, but to something like `intptr_t` or `swift::Int` for C and +/// C++ declarations. class PrimitiveTypeMapping { public: struct ClangTypeInfo { StringRef name; bool canBeNullable; + bool simd; }; /// Returns the Objective-C type name and nullability for the given Swift @@ -47,6 +50,8 @@ class PrimitiveTypeMapping { /// primitive type declaration, or \c None if no such type name exists. std::optional getKnownCxxTypeInfo(const TypeDecl *typeDecl); + std::optional getKnownSIMDTypeInfo(Type t, ASTContext &ctx); + private: void initialize(ASTContext &ctx); @@ -58,6 +63,7 @@ class PrimitiveTypeMapping { // The C++ name of the Swift type. std::optional cxxName; bool canBeNullable; + bool simd = false; }; FullClangTypeInfo *getMappedTypeInfoOrNull(const TypeDecl *typeDecl); diff --git a/lib/PrintAsClang/PrintClangFunction.cpp b/lib/PrintAsClang/PrintClangFunction.cpp index 1bd546494efbf..d0e0e2f65ac83 100644 --- a/lib/PrintAsClang/PrintClangFunction.cpp +++ b/lib/PrintAsClang/PrintClangFunction.cpp @@ -52,48 +52,62 @@ getKnownTypeInfo(const TypeDecl *typeDecl, PrimitiveTypeMapping &typeMapping, : typeMapping.getKnownCTypeInfo(typeDecl); } -bool isKnownType(Type t, PrimitiveTypeMapping &typeMapping, - OutputLanguageMode languageMode) { +enum class KnownTypeKind { Known, KnownSIMD, Unknown }; + +KnownTypeKind isKnownType(Type t, PrimitiveTypeMapping &typeMapping, + OutputLanguageMode languageMode, ASTContext &ctx) { if (auto *typeAliasType = dyn_cast(t.getPointer())) { auto aliasInfo = getKnownTypeInfo(typeAliasType->getDecl(), typeMapping, languageMode); if (aliasInfo != std::nullopt) - return true; + return aliasInfo->simd ? KnownTypeKind::KnownSIMD : KnownTypeKind::Known; return isKnownType(typeAliasType->getSinglyDesugaredType(), typeMapping, - languageMode); + languageMode, ctx); } const TypeDecl *typeDecl; auto *tPtr = t->isOptional() ? t->getOptionalObjectType()->getDesugaredType() : t->getDesugaredType(); if (auto *bgt = dyn_cast(tPtr)) { - return bgt->isUnsafePointer() || bgt->isUnsafeMutablePointer(); + return (bgt->isUnsafePointer() || bgt->isUnsafeMutablePointer()) + ? KnownTypeKind::Known + : KnownTypeKind::Unknown; } if (auto *structType = dyn_cast(tPtr)) { auto nullableInfo = getKnownTypeInfo(structType->getDecl(), typeMapping, languageMode); if (nullableInfo && nullableInfo->canBeNullable) - return true; + return nullableInfo->simd ? KnownTypeKind::KnownSIMD + : KnownTypeKind::Known; } if (auto *classType = dyn_cast(tPtr)) { - return classType->getClassOrBoundGenericClass()->hasClangNode() && - isa( - classType->getClassOrBoundGenericClass()->getClangDecl()); + return (classType->getClassOrBoundGenericClass()->hasClangNode() && + isa( + classType->getClassOrBoundGenericClass()->getClangDecl())) + ? KnownTypeKind::Known + : KnownTypeKind::Unknown; } + if (t->getAs()) + return typeMapping.getKnownSIMDTypeInfo(t, ctx) ? KnownTypeKind::KnownSIMD + : KnownTypeKind::Unknown; if (auto *structDecl = t->getStructOrBoundGenericStruct()) typeDecl = structDecl; else - return false; - return getKnownTypeInfo(typeDecl, typeMapping, languageMode) != std::nullopt; + return KnownTypeKind::Unknown; + return getKnownTypeInfo(typeDecl, typeMapping, languageMode) != std::nullopt + ? KnownTypeKind::Known + : KnownTypeKind::Unknown; } -bool isKnownCxxType(Type t, PrimitiveTypeMapping &typeMapping) { - return isKnownType(t, typeMapping, OutputLanguageMode::Cxx); +KnownTypeKind isKnownCxxType(Type t, PrimitiveTypeMapping &typeMapping, + ASTContext &ctx) { + return isKnownType(t, typeMapping, OutputLanguageMode::Cxx, ctx); } -bool isKnownCType(Type t, PrimitiveTypeMapping &typeMapping) { - return isKnownType(t, typeMapping, OutputLanguageMode::ObjC); +KnownTypeKind isKnownCType(Type t, PrimitiveTypeMapping &typeMapping, + ASTContext &ctx) { + return isKnownType(t, typeMapping, OutputLanguageMode::ObjC, ctx); } struct CFunctionSignatureTypePrinterModifierDelegate { @@ -151,7 +165,7 @@ class ClangTypeHandler { static void printGenericReturnScaffold(raw_ostream &os, StringRef templateParamName, llvm::function_ref bodyOfReturn) { - printReturnScaffold(nullptr, os, templateParamName, templateParamName, + printReturnScaffold(false, os, templateParamName, templateParamName, bodyOfReturn); } @@ -165,13 +179,19 @@ class ClangTypeHandler { llvm::raw_string_ostream unqualTypeNameOS(typeName); unqualTypeNameOS << typeDecl->getName(); } - printReturnScaffold(typeDecl, os, fullQualifiedType, typeName, + printReturnScaffold(isTrivial(typeDecl), os, fullQualifiedType, typeName, bodyOfReturn); } + static void + printSIMDReturnScaffold(StringRef simdTypeName, raw_ostream &os, + llvm::function_ref bodyOfReturn) { + printReturnScaffold(true, os, simdTypeName, simdTypeName, bodyOfReturn); + } + private: static void - printReturnScaffold(const clang::TagDecl *typeDecl, raw_ostream &os, + printReturnScaffold(bool isTrivial, raw_ostream &os, StringRef fullQualifiedType, StringRef typeName, llvm::function_ref bodyOfReturn) { os << "alignas(alignof(" << fullQualifiedType << ")) char storage[sizeof(" @@ -180,7 +200,7 @@ class ClangTypeHandler { << fullQualifiedType << " *>(storage);\n"; bodyOfReturn("storage"); os << ";\n"; - if (isTrivial(typeDecl)) { + if (isTrivial) { // Trivial object can be just copied and not destroyed. os << "return *storageObjectPtr;\n"; return; @@ -463,7 +483,8 @@ class CFunctionSignatureTypePrinter llvm::SaveAndRestore typeUseNormal( typeUseKind, FunctionSignatureTypeUse::TypeReference); // FIXME: We can definitely support pointers to known Clang types. - if (!isKnownCType(args.front(), typeMapping)) + if (isKnownCType(args.front(), typeMapping, BGT->getASTContext()) == + KnownTypeKind::Unknown) return ClangRepresentation(ClangRepresentation::unsupported); auto partRepr = visitPart(args.front(), OTK_None, /*isInOutParam=*/false); if (partRepr.isUnsupported()) @@ -572,9 +593,11 @@ DeclAndTypeClangFunctionPrinter::printClangFunctionReturnType( static void addABIRecordToTypeEncoding(llvm::raw_ostream &typeEncodingOS, clang::CharUnits offset, clang::CharUnits end, Type t, - PrimitiveTypeMapping &typeMapping) { - auto info = - typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal()); + PrimitiveTypeMapping &typeMapping, + ASTContext &ctx) { + auto info = typeMapping.getKnownSIMDTypeInfo(t, ctx); + if (!info) + info = typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal()); assert(info); typeEncodingOS << '_'; for (char c : info->name) { @@ -605,7 +628,8 @@ static std::string encodeTypeInfo(const T &abiTypeInfo, ClangSyntaxPrinter(moduleContext->getASTContext(), typeEncodingOS).printBaseName(moduleContext); abiTypeInfo.enumerateRecordMembers( [&](clang::CharUnits offset, clang::CharUnits end, Type t) { - addABIRecordToTypeEncoding(typeEncodingOS, offset, end, t, typeMapping); + addABIRecordToTypeEncoding(typeEncodingOS, offset, end, t, typeMapping, + moduleContext->getASTContext()); }); return std::move(typeEncodingOS.str()); } @@ -652,7 +676,8 @@ static bool printDirectReturnOrParamCType( clang::CharUnits end, Type t) { lastOffset = offset; ++Count; - addABIRecordToTypeEncoding(typeEncodingOS, offset, end, t, typeMapping); + addABIRecordToTypeEncoding(typeEncodingOS, offset, end, t, typeMapping, + emittedModule->getASTContext()); })) return false; if (isResultType && Count == 0) { @@ -664,7 +689,8 @@ static bool printDirectReturnOrParamCType( assert(Count > 0 && "missing return values"); // FIXME: is this "prettyfying" logic sound for multiple return values? - if (isKnownCType(valueType, typeMapping) || + if (isKnownCType(valueType, typeMapping, emittedModule->getASTContext()) == + KnownTypeKind::Known || (Count == 1 && lastOffset.isZero() && !valueType->hasTypeParameter() && (valueType->isAnyClassReferenceType() || isOptionalObjCExistential(valueType) || @@ -683,7 +709,10 @@ static bool printDirectReturnOrParamCType( abiTypeInfo.enumerateRecordMembers([&](clang::CharUnits offset, clang::CharUnits end, Type t) { auto info = - typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal()); + typeMapping.getKnownSIMDTypeInfo(t, emittedModule->getASTContext()); + if (!info) + info = + typeMapping.getKnownCTypeInfo(t->getNominalOrBoundGenericNominal()); os << " " << info->name; if (info->canBeNullable) os << " _Nullable"; @@ -962,8 +991,8 @@ ClangRepresentation DeclAndTypeClangFunctionPrinter::printFunctionSignature( ->isAnyClassReferenceType()); if (isConst) functionSignatureOS << "const "; - if (isKnownCType(param.getParamDecl().getInterfaceType(), - typeMapping) || + if (isKnownCType(param.getParamDecl().getInterfaceType(), typeMapping, + FD->getASTContext()) != KnownTypeKind::Unknown || (!param.getParamDecl().getInterfaceType()->hasTypeParameter() && param.getParamDecl() .getInterfaceType() @@ -1079,7 +1108,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse( Type type, StringRef name, const ModuleDecl *moduleContext, bool isInOut, bool isIndirect, std::string directTypeEncoding, bool forceSelf) { auto namePrinter = [&]() { ClangSyntaxPrinter(moduleContext->getASTContext(), os).printIdentifier(name); }; - if (!isKnownCxxType(type, typeMapping) && + auto knownTypeKind = + isKnownCxxType(type, typeMapping, moduleContext->getASTContext()); + if (knownTypeKind != KnownTypeKind::Known && !hasKnownOptionalNullableCxxMapping(type)) { if (type->is()) { os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() @@ -1114,21 +1145,21 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse( os << "::" << cxx_synthesis::getCxxImplNamespaceName() << "::swift_interop_passDirect_" << directTypeEncoding << '('; } - if (decl->hasClangNode()) { - if (!directTypeEncoding.empty()) - os << "reinterpret_cast("; - os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() - << "::getOpaquePointer("; - namePrinter(); + if (decl->hasClangNode() || knownTypeKind == KnownTypeKind::KnownSIMD) { + if (!directTypeEncoding.empty()) + os << "reinterpret_cast("; + os << "swift::" << cxx_synthesis::getCxxImplNamespaceName() + << "::getOpaquePointer("; + namePrinter(); + os << ')'; + if (!directTypeEncoding.empty()) os << ')'; - if (!directTypeEncoding.empty()) - os << ')'; } else { - ClangValueTypePrinter(os, cPrologueOS, interopContext) - .printParameterCxxToCUseScaffold( - moduleContext, - [&]() { printTypeImplTypeSpecifier(type, moduleContext); }, - namePrinter, forceSelf); + ClangValueTypePrinter(os, cPrologueOS, interopContext) + .printParameterCxxToCUseScaffold( + moduleContext, + [&]() { printTypeImplTypeSpecifier(type, moduleContext); }, + namePrinter, forceSelf); } if (!directTypeEncoding.empty()) os << ')'; @@ -1463,7 +1494,9 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( // Values types are returned either direcly in their C representation, or // indirectly by a pointer. - if (!isKnownCxxType(resultTy, typeMapping) && + auto knownTypeKind = + isKnownCxxType(resultTy, typeMapping, moduleContext->getASTContext()); + if (knownTypeKind != KnownTypeKind::Known && !hasKnownOptionalNullableCxxMapping(resultTy)) { if (const auto *gtpt = resultTy->getAs()) { printGenericReturnSequence(os, gtpt, printCallToCFunc); @@ -1500,6 +1533,16 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody( printCallToCFunc(/*firstParam=*/resultPointerName); } }; + if (knownTypeKind == KnownTypeKind::KnownSIMD) { + if (auto *typeAliasType = + dyn_cast(resultTy.getPointer())) { + auto info = getKnownTypeInfo(typeAliasType->getDecl(), typeMapping, + OutputLanguageMode::Cxx); + ClangTypeHandler::printSIMDReturnScaffold(info->name, os, + valueTypeReturnThunker); + return; + } + } if (decl->hasClangNode()) { ClangTypeHandler handler(decl->getClangDecl()); assert(handler.isRepresentable()); diff --git a/test/Interop/CxxToSwiftToCxx/simd-bridge-cxx-struct-back-to-cxx.swift b/test/Interop/CxxToSwiftToCxx/simd-bridge-cxx-struct-back-to-cxx.swift index e32bc9ef122e7..fa568c72f0f1b 100644 --- a/test/Interop/CxxToSwiftToCxx/simd-bridge-cxx-struct-back-to-cxx.swift +++ b/test/Interop/CxxToSwiftToCxx/simd-bridge-cxx-struct-back-to-cxx.swift @@ -43,5 +43,14 @@ public func passStruct(_ x : Struct) { } // CHECK: class SWIFT_SYMBOL("s:8UseCxxTy6StructV") Struct final { -// CHECK-NOT: init( -// CHECK: // Unavailable in C++: Swift global function 'passStruct(_:)' + +// CHECK: SWIFT_INLINE_THUNK void passStruct(const Struct& x) noexcept SWIFT_SYMBOL("s:8UseCxxTy10passStructyyAA0E0VF") { +// CHECK-NEXT: UseCxxTy::_impl::$s8UseCxxTy10passStructyyAA0E0VF(UseCxxTy::_impl::swift_interop_passDirect_UseCxxTy_swift_float4_0_16_swift_float4_16_32_swift_float4_32_48_swift_float4_48_64(UseCxxTy::_impl::_impl_Struct::getOpaquePointer(x))); +// CHECK-NEXT:} + +// CHECK: SWIFT_INLINE_THUNK Struct Struct::init() { +// CHECK-NEXT: return UseCxxTy::_impl::_impl_Struct::returnNewValue([&](char * _Nonnull result) SWIFT_INLINE_THUNK_ATTRIBUTES { +// CHECK-NEXT: UseCxxTy::_impl::swift_interop_returnDirect_UseCxxTy_swift_float4_0_16_swift_float4_16_32_swift_float4_32_48_swift_float4_48_64(result, UseCxxTy::_impl::$s8UseCxxTy6StructVACycfC()); +// CHECK-NEXT: }); +// CHECK-NEXT: } + diff --git a/test/Interop/SwiftToCxx/stdlib/swift-simd-in-cxx-execution.cpp b/test/Interop/SwiftToCxx/stdlib/swift-simd-in-cxx-execution.cpp new file mode 100644 index 0000000000000..060f7a92838fa --- /dev/null +++ b/test/Interop/SwiftToCxx/stdlib/swift-simd-in-cxx-execution.cpp @@ -0,0 +1,32 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %S/swift-simd-in-cxx.swift -module-name SIMD -clang-header-expose-decls=all-public -typecheck -verify -emit-clang-header-path %t/simd.h + +// RUN: %target-interop-build-clangxx -c %s -I %t -o %t/swift-simd-execution.o +// RUN: %target-interop-build-swift %S/swift-simd-in-cxx.swift -o %t/swift-simd-execution -Xlinker %t/swift-simd-execution.o -module-name SIMD -Xfrontend -entry-point-function-name -Xfrontend swiftMain + +// RUN: %target-codesign %t/swift-simd-execution +// RUN: %target-run %t/swift-simd-execution | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: rdar157848231 + +#include "simd.h" +#include +#include + +int main() { + swift_float3 vec{1.0, 2.0, 3.0}; + SIMD::swiftThingSIMD(vec); + // CHECK: SIMD3(1.0, 2.0, 3.0) + SIMD::swiftThingSIMD2(vec); + // CHECK: SIMD3(1.0, 2.0, 3.0) + swift_float3 vec2 = SIMD::swiftThingSIMD3(); + std::cout << vec2.x << " " << vec2.y << " " << vec2.z << "\n"; + // CHECK: 4 5 6 + vec2 = SIMD::swiftThingSIMD4(); + std::cout << vec2.x << " " << vec2.y << " " << vec2.z << "\n"; + // CHECK: 4 5 6 + return 0; +} + diff --git a/test/Interop/SwiftToCxx/stdlib/swift-simd-in-cxx.swift b/test/Interop/SwiftToCxx/stdlib/swift-simd-in-cxx.swift new file mode 100644 index 0000000000000..c54be05629bd0 --- /dev/null +++ b/test/Interop/SwiftToCxx/stdlib/swift-simd-in-cxx.swift @@ -0,0 +1,61 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %s -module-name UseSIMD -cxx-interoperability-mode=default -clang-header-expose-decls=all-public -typecheck -verify -emit-clang-header-path %t/UseSIMD.h +// RUN: %FileCheck %s < %t/UseSIMD.h + +// RUN: %target-interop-build-clangxx -std=gnu++20 -fobjc-arc -c -x objective-c++-header %t/UseSIMD.h -o %t/o.o + +// REQUIRES: objc_interop +// REQUIRES: rdar157848231 + +import simd + +public func swiftThingScalar(a: Float) {} + +public func swiftThingSIMD(a: float3) { + print(a) +} + +public func swiftThingSIMD2(a: simd_float3) { + print(a) +} + +public func swiftThingSIMD3() -> float3 { + float3(4, 5, 6) +} + +public func swiftThingSIMD4() -> simd_float3 { + simd_float3(4, 5, 6) +} + +// CHECK: SWIFT_EXTERN void $s7UseSIMD010swiftThingB01ays5SIMD3VySfG_tF(struct swift_interop_passStub_UseSIMD_swift_float4_0_16 a) SWIFT_NOEXCEPT SWIFT_CALL; // swiftThingSIMD(a:) +// CHECK: SWIFT_EXTERN void $s7UseSIMD15swiftThingSIMD21ays5SIMD3VySfG_tF(struct swift_interop_passStub_UseSIMD_swift_float4_0_16 a) SWIFT_NOEXCEPT SWIFT_CALL; // swiftThingSIMD2(a:) +// CHECK: SWIFT_EXTERN struct swift_interop_returnStub_UseSIMD_swift_float4_0_16 $s7UseSIMD15swiftThingSIMD3s0E0VySfGyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // swiftThingSIMD3() +// CHECK: SWIFT_EXTERN struct swift_interop_returnStub_UseSIMD_swift_float4_0_16 $s7UseSIMD15swiftThingSIMD4s5SIMD3VySfGyF(void) SWIFT_NOEXCEPT SWIFT_CALL; // swiftThingSIMD4() +// CHECK: SWIFT_EXTERN void $s7UseSIMD16swiftThingScalar1aySf_tF(float a) SWIFT_NOEXCEPT SWIFT_CALL; // swiftThingScalar(a:) + +// CHECK: SWIFT_INLINE_THUNK void swiftThingSIMD(swift_float3 a) noexcept SWIFT_SYMBOL("s:7UseSIMD010swiftThingB01ays5SIMD3VySfG_tF") { +// CHECK-NEXT: UseSIMD::_impl::$s7UseSIMD010swiftThingB01ays5SIMD3VySfG_tF(UseSIMD::_impl::swift_interop_passDirect_UseSIMD_swift_float4_0_16(reinterpret_cast(swift::_impl::getOpaquePointer(a)))); +// CHECK-NEXT: } + +// CHECK: WIFT_INLINE_THUNK void swiftThingSIMD2(swift_float3 a) noexcept SWIFT_SYMBOL("s:7UseSIMD15swiftThingSIMD21ays5SIMD3VySfG_tF") { +// CHECK-NEXT: UseSIMD::_impl::$s7UseSIMD15swiftThingSIMD21ays5SIMD3VySfG_tF(UseSIMD::_impl::swift_interop_passDirect_UseSIMD_swift_float4_0_16(reinterpret_cast(swift::_impl::getOpaquePointer(a)))); +// CHECK-NEXT: } + +// CHECK: SWIFT_INLINE_THUNK swift_float3 swiftThingSIMD3() noexcept SWIFT_SYMBOL("s:7UseSIMD15swiftThingSIMD3s0E0VySfGyF") SWIFT_WARN_UNUSED_RESULT { +// CHECK-NEXT: alignas(alignof(swift_float3)) char storage[sizeof(swift_float3)]; +// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast(storage); +// CHECK-NEXT: UseSIMD::_impl::swift_interop_returnDirect_UseSIMD_swift_float4_0_16(storage, UseSIMD::_impl::$s7UseSIMD15swiftThingSIMD3s0E0VySfGyF()); +// CHECK-NEXT: return *storageObjectPtr; +// CHECK-NEXT: } + +// CHECK: SWIFT_INLINE_THUNK swift_float3 swiftThingSIMD4() noexcept SWIFT_SYMBOL("s:7UseSIMD15swiftThingSIMD4s5SIMD3VySfGyF") SWIFT_WARN_UNUSED_RESULT { +// CHECK-NEXT: alignas(alignof(swift_float3)) char storage[sizeof(swift_float3)]; +// CHECK-NEXT: auto * _Nonnull storageObjectPtr = reinterpret_cast(storage); +// CHECK-NEXT: UseSIMD::_impl::swift_interop_returnDirect_UseSIMD_swift_float4_0_16(storage, UseSIMD::_impl::$s7UseSIMD15swiftThingSIMD4s5SIMD3VySfGyF()); +// CHECK-NEXT: return *storageObjectPtr; +// CHECK-NEXT: } + +// CHECK: SWIFT_INLINE_THUNK void swiftThingScalar(float a) noexcept SWIFT_SYMBOL("s:7UseSIMD16swiftThingScalar1aySf_tF") { +// CHECK-NEXT: UseSIMD::_impl::$s7UseSIMD16swiftThingScalar1aySf_tF(a); +// CHECK-NEXT: }