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

Reply via email to