//===--- SwiftTargetInfo.cpp ----------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the SwiftTargetInfo abstract base class. This class // provides an interface to target-dependent attributes of interest to Swift. // //===----------------------------------------------------------------------===// #include "SwiftTargetInfo.h" #include "IRGenModule.h" #include "llvm/TargetParser/Triple.h" #include "llvm/IR/DataLayout.h" #include "swift/ABI/System.h" #include "swift/AST/ASTContext.h" #include "swift/AST/IRGenOptions.h" #include "swift/Basic/Platform.h" using namespace swift; using namespace irgen; /// Initialize a bit vector to be equal to the given bit-mask. static void setToMask(SpareBitVector &bits, unsigned size, uint64_t mask) { bits.clear(); bits.add(size, mask); } /// Configures target-specific information for arm64 platforms. static void configureARM64(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { if (triple.isAndroid()) { setToMask(target.PointerSpareBits, 64, SWIFT_ABI_ANDROID_ARM64_SWIFT_SPARE_BITS_MASK); setToMask(target.ObjCPointerReservedBits, 64, SWIFT_ABI_ANDROID_ARM64_OBJC_RESERVED_BITS_MASK); } else { setToMask(target.PointerSpareBits, 64, SWIFT_ABI_ARM64_SWIFT_SPARE_BITS_MASK); setToMask(target.ObjCPointerReservedBits, 64, SWIFT_ABI_ARM64_OBJC_RESERVED_BITS_MASK); } setToMask(target.IsObjCPointerBit, 64, SWIFT_ABI_ARM64_IS_OBJC_BIT); // Non-embedded Darwin reserves the low 4GB of address space. if (triple.isOSDarwin() && !IGM.getSwiftModule()->getASTContext().LangOpts.hasFeature( Feature::Embedded)) { target.LeastValidPointerValue = SWIFT_ABI_DARWIN_ARM64_LEAST_VALID_POINTER; } // arm64 has no special objc_msgSend variants, not even stret. target.ObjCUseStret = false; // arm64 requires marker assembly for objc_retainAutoreleasedReturnValue. target.ObjCRetainAutoreleasedReturnValueMarker = "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue"; // arm64 requires ISA-masking. target.ObjCUseISAMask = true; // arm64 tops out at 56 effective bits of address space and reserves the high // half for the kernel. target.SwiftRetainIgnoresNegativeValues = true; // ARM64 Darwin has swiftSwiftDirectRuntime, but not in Embedded mode. JIT // mode can't load the static library, so disable it there as well. if (triple.isOSDarwin() && !IGM.getSwiftModule()->getASTContext().LangOpts.hasFeature( Feature::Embedded) && !IGM.getOptions().UseJIT) target.HasSwiftSwiftDirectRuntimeLibrary = true; target.UsableSwiftAsyncContextAddrIntrinsic = true; } /// Configures target-specific information for arm64_32 platforms. static void configureARM64_32(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 32, SWIFT_ABI_ARM_SWIFT_SPARE_BITS_MASK); // arm64_32 has no special objc_msgSend variants, not even stret. target.ObjCUseStret = false; // arm64_32 requires marker assembly for objc_retainAutoreleasedReturnValue. target.ObjCRetainAutoreleasedReturnValueMarker = "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue"; setToMask(target.IsObjCPointerBit, 32, SWIFT_ABI_ARM_IS_OBJC_BIT); target.ObjCHasOpaqueISAs = true; } /// Configures target-specific information for x86-64 platforms. static void configureX86_64(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 64, SWIFT_ABI_X86_64_SWIFT_SPARE_BITS_MASK); setToMask(target.IsObjCPointerBit, 64, SWIFT_ABI_X86_64_IS_OBJC_BIT); if (triple.isSimulatorEnvironment()) { setToMask(target.ObjCPointerReservedBits, 64, SWIFT_ABI_X86_64_SIMULATOR_OBJC_RESERVED_BITS_MASK); } else { setToMask(target.ObjCPointerReservedBits, 64, SWIFT_ABI_X86_64_OBJC_RESERVED_BITS_MASK); } if (triple.isOSDarwin() && !IGM.getSwiftModule()->getASTContext().LangOpts.hasFeature( Feature::Embedded)) { target.LeastValidPointerValue = SWIFT_ABI_DARWIN_X86_64_LEAST_VALID_POINTER; } // x86-64 has every objc_msgSend variant known to humankind. target.ObjCUseFPRet = true; target.ObjCUseFP2Ret = true; // x86-64 requires ISA-masking. target.ObjCUseISAMask = true; // x86-64 only has 48 effective bits of address space and reserves the high // half for the kernel. target.SwiftRetainIgnoresNegativeValues = true; target.UsableSwiftAsyncContextAddrIntrinsic = true; } /// Configures target-specific information for 32-bit x86 platforms. static void configureX86(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 32, SWIFT_ABI_I386_SWIFT_SPARE_BITS_MASK); // x86 uses objc_msgSend_fpret but not objc_msgSend_fp2ret. target.ObjCUseFPRet = true; setToMask(target.IsObjCPointerBit, 32, SWIFT_ABI_I386_IS_OBJC_BIT); } /// Configures target-specific information for 32-bit arm platforms. static void configureARM(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 32, SWIFT_ABI_ARM_SWIFT_SPARE_BITS_MASK); // ARM requires marker assembly for objc_retainAutoreleasedReturnValue. target.ObjCRetainAutoreleasedReturnValueMarker = "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue"; // armv7k has opaque ISAs which must go through the ObjC runtime. if (triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7k) target.ObjCHasOpaqueISAs = true; setToMask(target.IsObjCPointerBit, 32, SWIFT_ABI_ARM_IS_OBJC_BIT); } /// Configures target-specific information for powerpc platforms. static void configurePowerPC(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 32, SWIFT_ABI_POWERPC_SWIFT_SPARE_BITS_MASK); } /// Configures target-specific information for powerpc64 platforms. static void configurePowerPC64(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 64, SWIFT_ABI_POWERPC64_SWIFT_SPARE_BITS_MASK); } /// Configures target-specific information for SystemZ platforms. static void configureSystemZ(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { setToMask(target.PointerSpareBits, 64, SWIFT_ABI_S390X_SWIFT_SPARE_BITS_MASK); setToMask(target.ObjCPointerReservedBits, 64, SWIFT_ABI_S390X_OBJC_RESERVED_BITS_MASK); setToMask(target.IsObjCPointerBit, 64, SWIFT_ABI_S390X_IS_OBJC_BIT); target.SwiftRetainIgnoresNegativeValues = true; } /// Configures target-specific information for wasm32 platforms. static void configureWasm32(IRGenModule &IGM, const llvm::Triple &triple, SwiftTargetInfo &target) { target.LeastValidPointerValue = SWIFT_ABI_WASM32_LEAST_VALID_POINTER; } /// Configure a default target. SwiftTargetInfo::SwiftTargetInfo( llvm::Triple::ObjectFormatType outputObjectFormat, unsigned numPointerBits) : OutputObjectFormat(outputObjectFormat), HeapObjectAlignment(numPointerBits / 8), LeastValidPointerValue(SWIFT_ABI_DEFAULT_LEAST_VALID_POINTER) { setToMask(PointerSpareBits, numPointerBits, SWIFT_ABI_DEFAULT_SWIFT_SPARE_BITS_MASK); setToMask(ObjCPointerReservedBits, numPointerBits, SWIFT_ABI_DEFAULT_OBJC_RESERVED_BITS_MASK); setToMask(FunctionPointerSpareBits, numPointerBits, SWIFT_ABI_DEFAULT_FUNCTION_SPARE_BITS_MASK); if (numPointerBits == 64) { ReferencePoisonDebugValue = SWIFT_ABI_DEFAULT_REFERENCE_POISON_DEBUG_VALUE_64; } else { ReferencePoisonDebugValue = SWIFT_ABI_DEFAULT_REFERENCE_POISON_DEBUG_VALUE_32; } } SwiftTargetInfo SwiftTargetInfo::get(IRGenModule &IGM) { const llvm::Triple &triple = IGM.Context.LangOpts.Target; auto pointerSize = IGM.DataLayout.getPointerSizeInBits(); // Prepare generic target information. SwiftTargetInfo target(triple.getObjectFormat(), pointerSize); // On Apple platforms, we implement "once" using dispatch_once, // which exposes a barrier-free inline path with -1 as the "done" value. if (triple.isOSDarwin()) target.OnceDonePredicateValue = -1L; // Other platforms use std::call_once() and we don't // assume that they have a barrier-free inline fast path. switch (triple.getArch()) { case llvm::Triple::x86_64: configureX86_64(IGM, triple, target); break; case llvm::Triple::x86: configureX86(IGM, triple, target); break; case llvm::Triple::arm: case llvm::Triple::thumb: configureARM(IGM, triple, target); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: if (triple.getArchName() == "arm64_32") configureARM64_32(IGM, triple, target); else configureARM64(IGM, triple, target); break; case llvm::Triple::ppc: configurePowerPC(IGM, triple, target); break; case llvm::Triple::ppc64: case llvm::Triple::ppc64le: configurePowerPC64(IGM, triple, target); break; case llvm::Triple::systemz: configureSystemZ(IGM, triple, target); break; case llvm::Triple::wasm32: configureWasm32(IGM, triple, target); break; default: // FIXME: Complain here? Default target info is unlikely to be correct. break; } if (IGM.getOptions().CustomLeastValidPointerValue != 0) target.LeastValidPointerValue = IGM.getOptions().CustomLeastValidPointerValue; return target; } bool SwiftTargetInfo::hasObjCTaggedPointers() const { return ObjCPointerReservedBits.any(); }