2323#include " clang/Basic/Diagnostic.h"
2424#include " clang/CodeGen/CGFunctionInfo.h"
2525#include " llvm/ADT/STLExtras.h"
26+ #include " llvm/BinaryFormat/MachO.h"
2627#include " llvm/IR/DataLayout.h"
2728#include " llvm/IR/InlineAsm.h"
2829using namespace clang ;
@@ -3814,9 +3815,61 @@ CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) {
38143815 return Val;
38153816}
38163817
3818+ static unsigned getBaseMachOPlatformID (const llvm::Triple &TT) {
3819+ switch (TT.getOS ()) {
3820+ case llvm::Triple::Darwin:
3821+ case llvm::Triple::MacOSX:
3822+ return llvm::MachO::PLATFORM_MACOS;
3823+ case llvm::Triple::IOS:
3824+ return llvm::MachO::PLATFORM_IOS;
3825+ case llvm::Triple::TvOS:
3826+ return llvm::MachO::PLATFORM_TVOS;
3827+ case llvm::Triple::WatchOS:
3828+ return llvm::MachO::PLATFORM_WATCHOS;
3829+ default :
3830+ return /* Unknown platform*/ 0 ;
3831+ }
3832+ }
3833+
3834+ static llvm::Value *emitIsPlatformVersionAtLeast (CodeGenFunction &CGF,
3835+ const VersionTuple &Version) {
3836+ CodeGenModule &CGM = CGF.CGM ;
3837+ // Note: we intend to support multi-platform version checks, so reserve
3838+ // the room for a dual platform checking invocation that will be
3839+ // implemented in the future.
3840+ llvm::SmallVector<llvm::Value *, 8 > Args;
3841+
3842+ auto EmitArgs = [&](const VersionTuple &Version, const llvm::Triple &TT) {
3843+ Optional<unsigned > Min = Version.getMinor (), SMin = Version.getSubminor ();
3844+ Args.push_back (
3845+ llvm::ConstantInt::get (CGM.Int32Ty , getBaseMachOPlatformID (TT)));
3846+ Args.push_back (llvm::ConstantInt::get (CGM.Int32Ty , Version.getMajor ()));
3847+ Args.push_back (llvm::ConstantInt::get (CGM.Int32Ty , Min ? *Min : 0 ));
3848+ Args.push_back (llvm::ConstantInt::get (CGM.Int32Ty , SMin ? *SMin : 0 ));
3849+ };
3850+
3851+ assert (!Version.empty () && " unexpected empty version" );
3852+ EmitArgs (Version, CGM.getTarget ().getTriple ());
3853+
3854+ if (!CGM.IsPlatformVersionAtLeastFn ) {
3855+ llvm::FunctionType *FTy = llvm::FunctionType::get (
3856+ CGM.Int32Ty , {CGM.Int32Ty , CGM.Int32Ty , CGM.Int32Ty , CGM.Int32Ty },
3857+ false );
3858+ CGM.IsPlatformVersionAtLeastFn =
3859+ CGM.CreateRuntimeFunction (FTy, " __isPlatformVersionAtLeast" );
3860+ }
3861+
3862+ llvm::Value *Check =
3863+ CGF.EmitNounwindRuntimeCall (CGM.IsPlatformVersionAtLeastFn , Args);
3864+ return CGF.Builder .CreateICmpNE (Check,
3865+ llvm::Constant::getNullValue (CGM.Int32Ty ));
3866+ }
3867+
38173868llvm::Value *
3818- CodeGenFunction::EmitBuiltinAvailable (ArrayRef<llvm::Value *> Args) {
3819- assert (Args.size () == 3 && " Expected 3 argument here!" );
3869+ CodeGenFunction::EmitBuiltinAvailable (const VersionTuple &Version) {
3870+ // Darwin uses the new __isPlatformVersionAtLeast family of routines.
3871+ if (CGM.getTarget ().getTriple ().isOSDarwin ())
3872+ return emitIsPlatformVersionAtLeast (*this , Version);
38203873
38213874 if (!CGM.IsOSVersionAtLeastFn ) {
38223875 llvm::FunctionType *FTy =
@@ -3825,18 +3878,51 @@ CodeGenFunction::EmitBuiltinAvailable(ArrayRef<llvm::Value *> Args) {
38253878 CGM.CreateRuntimeFunction (FTy, " __isOSVersionAtLeast" );
38263879 }
38273880
3881+ Optional<unsigned > Min = Version.getMinor (), SMin = Version.getSubminor ();
3882+ llvm::Value *Args[] = {
3883+ llvm::ConstantInt::get (CGM.Int32Ty , Version.getMajor ()),
3884+ llvm::ConstantInt::get (CGM.Int32Ty , Min ? *Min : 0 ),
3885+ llvm::ConstantInt::get (CGM.Int32Ty , SMin ? *SMin : 0 ),
3886+ };
3887+
38283888 llvm::Value *CallRes =
38293889 EmitNounwindRuntimeCall (CGM.IsOSVersionAtLeastFn , Args);
38303890
38313891 return Builder.CreateICmpNE (CallRes, llvm::Constant::getNullValue (Int32Ty));
38323892}
38333893
3894+ static bool isFoundationNeededForDarwinAvailabilityCheck (
3895+ const llvm::Triple &TT, const VersionTuple &TargetVersion) {
3896+ VersionTuple FoundationDroppedInVersion;
3897+ switch (TT.getOS ()) {
3898+ case llvm::Triple::IOS:
3899+ case llvm::Triple::TvOS:
3900+ FoundationDroppedInVersion = VersionTuple (/* Major=*/ 13 );
3901+ break ;
3902+ case llvm::Triple::WatchOS:
3903+ FoundationDroppedInVersion = VersionTuple (/* Major=*/ 6 );
3904+ break ;
3905+ case llvm::Triple::Darwin:
3906+ case llvm::Triple::MacOSX:
3907+ FoundationDroppedInVersion = VersionTuple (/* Major=*/ 10 , /* Minor=*/ 15 );
3908+ break ;
3909+ default :
3910+ llvm_unreachable (" Unexpected OS" );
3911+ }
3912+ return TargetVersion < FoundationDroppedInVersion;
3913+ }
3914+
38343915void CodeGenModule::emitAtAvailableLinkGuard () {
3835- if (!IsOSVersionAtLeastFn )
3916+ if (!IsPlatformVersionAtLeastFn )
38363917 return ;
38373918 // @available requires CoreFoundation only on Darwin.
38383919 if (!Target.getTriple ().isOSDarwin ())
38393920 return ;
3921+ // @available doesn't need Foundation on macOS 10.15+, iOS/tvOS 13+, or
3922+ // watchOS 6+.
3923+ if (!isFoundationNeededForDarwinAvailabilityCheck (
3924+ Target.getTriple (), Target.getPlatformMinVersion ()))
3925+ return ;
38403926 // Add -framework CoreFoundation to the linker commands. We still want to
38413927 // emit the core foundation reference down below because otherwise if
38423928 // CoreFoundation is not used in the code, the linker won't link the
0 commit comments