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