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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits