erik.pilkington updated this revision to Diff 89067. erik.pilkington added a comment.
This new patch just generates a call to the function `_IsOSVersionAtLeast` and branches on the result. `_IsOSVersionAtLeast` is going through review here: https://reviews.llvm.org/D30136. I decided to parse the SystemVersion.plist file, I think mapping from kernel versions to marketing versions works for macOS, but not for iOS, as iOS tends to cling on to darwin versions for longer. For example, darwin 14.0.0 was used from iOS 7.0 until iOS 8.4.1, (based on the table here: https://www.theiphonewiki.com/wiki/Kernel) which is not fine grain enough for use with `@available`. Thanks for taking a look! Erik https://reviews.llvm.org/D27827 Files: lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CGObjC.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/CodeGenModule.h test/CodeGenObjC/availability-check.m
Index: test/CodeGenObjC/availability-check.m =================================================================== --- test/CodeGenObjC/availability-check.m +++ test/CodeGenObjC/availability-check.m @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -xc -triple x86_64-apple-macosx10.11 -emit-llvm -o - %s | FileCheck %s + +void use_at_available() { + // CHECK: call i32 @_IsOSVersionAtLeast(i32 10, i32 12, i32 0) + // CHECK-NEXT: icmp ne + if (__builtin_available(macos 10.12, *)) + ; + // This check should be folded: our deployment target is 10.11. + // CHECK-NOT: call i32 @_IsOSVersionAtLeast + if (__builtin_available(macos 10.11, *)) + ; +} + +// CHECK: declare i32 @_IsOSVersionAtLeast(i32, i32, i32) Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -546,6 +546,10 @@ return *ObjCData; } + // Version checking function, used to implement ObjC's @available: + // i32 @_IsOSVersionAtLeast(i32, i32, i32) + llvm::Constant *ObjCIsOSVersionAtLeastFn = nullptr; + InstrProfStats &getPGOStats() { return PGOStats; } llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2476,6 +2476,8 @@ void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S); + llvm::Value *EmitObjCIsOSVersionAtLeast(ArrayRef<llvm::Value *> Args); + void EmitCoroutineBody(const CoroutineBodyStmt &S); RValue EmitCoroutineIntrinsic(const CallExpr *E, unsigned int IID); Index: lib/CodeGen/CGObjC.cpp =================================================================== --- lib/CodeGen/CGObjC.cpp +++ lib/CodeGen/CGObjC.cpp @@ -3399,5 +3399,21 @@ return Val; } +llvm::Value * +CodeGenFunction::EmitObjCIsOSVersionAtLeast(ArrayRef<llvm::Value *> Args) { + assert(Args.size() == 3 && "Expected 3 argument here!"); + + if (!CGM.ObjCIsOSVersionAtLeastFn) { + llvm::FunctionType *FTy = + llvm::FunctionType::get(Int32Ty, {Int32Ty, Int32Ty, Int32Ty}, false); + CGM.ObjCIsOSVersionAtLeastFn = + CGM.CreateRuntimeFunction(FTy, "_IsOSVersionAtLeast"); + } + + llvm::Value *CallRes = + EmitNounwindRuntimeCall(CGM.ObjCIsOSVersionAtLeastFn, Args); + + return Builder.CreateICmpNE(CallRes, llvm::Constant::getNullValue(Int32Ty)); +} CGObjCRuntime::~CGObjCRuntime() {} Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -300,6 +300,24 @@ return V; } + Value *VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + VersionTuple Version = E->getVersion(); + + // If we're checking for a platform older than our minimum deployment + // target, we can fold the check away. + if (Version <= CGF.CGM.getTarget().getPlatformMinVersion()) + return llvm::ConstantInt::get(Builder.getInt1Ty(), 1); + + Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor(); + llvm::Value *Args[] = { + llvm::ConstantInt::get(CGF.CGM.Int32Ty, Version.getMajor()), + llvm::ConstantInt::get(CGF.CGM.Int32Ty, Min ? *Min : 0), + llvm::ConstantInt::get(CGF.CGM.Int32Ty, SMin ? *SMin : 0), + }; + + return CGF.EmitObjCIsOSVersionAtLeast(Args); + } + Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitConvertVectorExpr(ConvertVectorExpr *E);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits