Skip to content

Commit 45de490

Browse files
committed
Make changes to CodeGen that are needed to support feature-based
availability rdar://137999979
1 parent 29610f7 commit 45de490

File tree

10 files changed

+438
-3
lines changed

10 files changed

+438
-3
lines changed

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,15 @@ class ScalarExprEmitter
583583
}
584584

585585
Value *VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
586+
if (E->hasDomainName()) {
587+
auto DomainName = E->getDomainName();
588+
ASTContext::AvailabilityDomainInfo Info =
589+
CGF.getContext().getFeatureAvailInfo(DomainName);
590+
assert((Info.Kind == FeatureAvailKind::Dynamic && Info.Call) &&
591+
"ObjCAvailabilityCheckExpr should have been constant evaluated");
592+
return CGF.EmitScalarExpr(Info.Call);
593+
}
594+
586595
VersionTuple Version = E->getVersionAsWritten();
587596

588597
// If we're checking for a platform older than our minimum deployment

clang/lib/CodeGen/CGObjCMac.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,6 +3119,8 @@ static void PushProtocolProperties(
31193119
SmallVectorImpl<const ObjCPropertyDecl *> &Properties,
31203120
const ObjCProtocolDecl *Proto, bool IsClassProperty) {
31213121
for (const auto *PD : Proto->properties()) {
3122+
if (Proto->getASTContext().hasUnavailableFeature(PD))
3123+
continue;
31223124
if (IsClassProperty != PD->isClassProperty())
31233125
continue;
31243126
if (!PropertySet.insert(PD->getIdentifier()).second)
@@ -3160,6 +3162,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(
31603162
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
31613163
for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
31623164
for (auto *PD : ClassExt->properties()) {
3165+
if (CGM.getContext().hasUnavailableFeature(PD))
3166+
continue;
31633167
if (IsClassProperty != PD->isClassProperty())
31643168
continue;
31653169
if (PD->isDirectProperty())
@@ -3169,6 +3173,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(
31693173
}
31703174

31713175
for (const auto *PD : OCD->properties()) {
3176+
if (CGM.getContext().hasUnavailableFeature(PD))
3177+
continue;
31723178
if (IsClassProperty != PD->isClassProperty())
31733179
continue;
31743180
// Don't emit duplicate metadata for properties that were already in a
@@ -5222,6 +5228,9 @@ void IvarLayoutBuilder::visitAggregate(Iterator begin, Iterator end,
52225228
for (; begin != end; ++begin) {
52235229
auto field = *begin;
52245230

5231+
if (CGM.getContext().hasUnavailableFeature(field))
5232+
continue;
5233+
52255234
// Skip over bitfields.
52265235
if (field->isBitField()) {
52275236
continue;
@@ -6644,6 +6653,9 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
66446653
void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
66456654
const ObjCMethodDecl *MD,
66466655
bool forProtocol) {
6656+
if (CGM.getContext().hasUnavailableFeature(MD))
6657+
return;
6658+
66476659
auto method = builder.beginStruct(ObjCTypes.MethodTy);
66486660
method.add(GetMethodVarName(MD->getSelector()));
66496661
method.add(GetMethodVarType(MD));
@@ -6841,6 +6853,9 @@ CGObjCNonFragileABIMac::EmitIvarList(const ObjCImplementationDecl *ID) {
68416853
if (!IVD->getDeclName())
68426854
continue;
68436855

6856+
if (CGM.getContext().hasUnavailableFeature(IVD))
6857+
continue;
6858+
68446859
auto ivar = ivars.beginStruct(ObjCTypes.IvarnfABITy);
68456860
ivar.add(EmitIvarOffsetVar(ID->getClassInterface(), IVD,
68466861
ComputeIvarBaseOffset(CGM, ID, IVD)));

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
900900
// the condition and the dead arm of the if/else.
901901
bool CondConstant;
902902
if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant,
903-
S.isConstexpr())) {
903+
(S.isConstexpr() || S.isObjCAvailabilityCheckWithDomainName()))) {
904904
// Figure out which block (then or else) is executed.
905905
const Stmt *Executed = S.getThen();
906906
const Stmt *Skipped = Else;
@@ -909,7 +909,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
909909

910910
// If the skipped block has no labels in it, just emit the executed block.
911911
// This avoids emitting dead code and simplifies the CFG substantially.
912-
if (S.isConstexpr() || !ContainsLabel(Skipped)) {
912+
if ((S.isConstexpr() || S.isObjCAvailabilityCheckWithDomainName()) || !ContainsLabel(Skipped)) {
913913
if (CondConstant)
914914
incrementProfileCounter(&S);
915915
if (Executed) {

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5342,6 +5342,9 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
53425342
return;
53435343
}
53445344

5345+
if (Context.hasUnavailableFeature(D))
5346+
return;
5347+
53455348
// The tentative definition is the only definition.
53465349
EmitGlobalVarDefinition(D);
53475350
}
@@ -6864,6 +6867,9 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
68646867
void CodeGenModule::EmitObjCPropertyImplementations(const
68656868
ObjCImplementationDecl *D) {
68666869
for (const auto *PID : D->property_impls()) {
6870+
if (Context.hasUnavailableFeature(PID->getPropertyDecl()))
6871+
continue;
6872+
68676873
// Dynamic is just for type-checking.
68686874
if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) {
68696875
ObjCPropertyDecl *PD = PID->getPropertyDecl();
@@ -6888,9 +6894,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const
68886894
static bool needsDestructMethod(ObjCImplementationDecl *impl) {
68896895
const ObjCInterfaceDecl *iface = impl->getClassInterface();
68906896
for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
6891-
ivar; ivar = ivar->getNextIvar())
6897+
ivar; ivar = ivar->getNextIvar()) {
6898+
if (impl->getASTContext().hasUnavailableFeature(ivar))
6899+
continue;
68926900
if (ivar->getType().isDestructedType())
68936901
return true;
6902+
}
68946903

68956904
return false;
68966905
}
@@ -7022,6 +7031,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
70227031
if (auto *FD = dyn_cast<FunctionDecl>(D); FD && FD->isImmediateFunction())
70237032
return;
70247033

7034+
if (Context.hasUnavailableFeature(D))
7035+
return;
7036+
70257037
switch (D->getKind()) {
70267038
case Decl::CXXConversion:
70277039
case Decl::CXXMethod:
@@ -7152,6 +7164,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
71527164
}
71537165
case Decl::ObjCMethod: {
71547166
auto *OMD = cast<ObjCMethodDecl>(D);
7167+
if (Context.hasUnavailableFeature(OMD->getClassInterface()))
7168+
break;
71557169
// If this is not a prototype, emit the body.
71567170
if (OMD->getBody())
71577171
CodeGenFunction(*this).GenerateObjCMethod(OMD);
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck --check-prefixes=CHECK,DOMAIN %s
3+
4+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -emit-pch -o %t %s
5+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -ffeature-availability=feature1:on -ffeature-availability=feature2:off -include-pch %t -emit-llvm -o - %s | FileCheck %s
6+
7+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -emit-pch -o %t -DUSE_DOMAIN %s
8+
// RUN: %clang_cc1 -triple arm64-apple-macosx -fblocks -include-pch %t -emit-llvm -o - -DUSE_DOMAIN %s | FileCheck --check-prefixes=CHECK,DOMAIN %s
9+
10+
// CHECK: %[[STRUCT_S0:.*]] = type { i32 }
11+
// CHECK: @g0 = external global i32, align 4
12+
// CHECK-NOT: @g1
13+
// CHECK-NOT: @g2
14+
15+
#ifndef HEADER
16+
#define HEADER
17+
18+
#include <feature-availability.h>
19+
20+
#define AVAIL 0
21+
22+
#ifdef USE_DOMAIN
23+
// DOMAIN: @g3 = extern_weak global i32, align 4
24+
25+
static struct __AvailabilityDomain feature1 __attribute__((availability_domain(feature1))) = {__AVAILABILITY_DOMAIN_ENABLED, 0};
26+
static struct __AvailabilityDomain feature2 __attribute__((availability_domain(feature2))) = {__AVAILABILITY_DOMAIN_DISABLED, 0};
27+
#endif
28+
29+
__attribute__((availability(domain:feature1, AVAIL))) int func0(void);
30+
__attribute__((availability(domain:feature2, AVAIL))) int func1(void);
31+
int func2(void);
32+
33+
__attribute__((availability(domain:feature1, AVAIL))) extern int g0;
34+
__attribute__((availability(domain:feature2, AVAIL))) int g1 = 100;
35+
__attribute__((availability(domain:feature2, AVAIL))) int g2;
36+
37+
struct __attribute__((availability(domain:feature1, AVAIL))) S0 {
38+
int d0;
39+
};
40+
41+
// CHECK-LABEL: define void @test0()
42+
// CHECK-NOT: br
43+
// CHECK: call i32 @func0()
44+
// CHECK: store i32 123, ptr @g0, align 4
45+
// CHECK-NOT: func1()
46+
// CHECK-NOT: func2()
47+
void test0(void) {
48+
if (__builtin_available(domain:feature1)) {
49+
func0();
50+
g0 = 123;
51+
}
52+
53+
if (__builtin_available(domain:feature2)) {
54+
func1();
55+
g1 = 123;
56+
}
57+
58+
if (__builtin_available(domain:feature1))
59+
if (__builtin_available(domain:feature2)) {
60+
func2();
61+
}
62+
}
63+
64+
// CHECK-LABEL: define void @test1()
65+
__attribute__((availability(domain:feature1, AVAIL)))
66+
void test1(void) {
67+
}
68+
69+
// CHECK-NOT: @test2(
70+
__attribute__((availability(domain:feature2, AVAIL)))
71+
void test2(void) {
72+
}
73+
74+
// CHECK-LABEL: define void @test3(
75+
// CHECK: %[[D0:.*]] = getelementptr inbounds nuw %[[STRUCT_S0]], ptr %{{.*}}, i32 0, i32 0
76+
// CHECK: store i32 134, ptr %[[D0]], align 4
77+
__attribute__((availability(domain:feature1, AVAIL)))
78+
void test3(struct S0 *s0) {
79+
s0->d0 = 134;
80+
}
81+
82+
#ifdef USE_DOMAIN
83+
// DOMAIN-LABEL: define void @test4()
84+
// DOMAIN: %[[CALL:.*]] = call i32 @pred1()
85+
// DOMAIN-NEXT: %[[TOBOOL:.*]] = icmp ne i32 %[[CALL]], 0
86+
// DOMAIN-NEXT: br i1 %[[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
87+
//
88+
// DOMAIN: [[IF_THEN]]:
89+
// DOMAIN-NEXT: %[[CALL1:.*]] = call i32 @func3()
90+
// DOMAIN-NEXT: store i32 1, ptr @g3, align 4
91+
// DOMAIN-NEXT: br label %[[IF_END]]
92+
//
93+
// DOMAIN: [[IF_END]]:
94+
// DOMAIN-NEXT: ret void
95+
96+
int pred1(void);
97+
static struct __AvailabilityDomain feature3 __attribute__((availability_domain(feature3))) = {__AVAILABILITY_DOMAIN_DYNAMIC, pred1};
98+
__attribute__((availability(domain:feature3, AVAIL))) int func3(void);
99+
__attribute__((availability(domain:feature3, AVAIL))) extern int g3;
100+
101+
void test4(void) {
102+
if (__builtin_available(domain:feature3)) {
103+
func3();
104+
g3 = 1;
105+
}
106+
}
107+
108+
// DOMAIN: declare extern_weak i32 @func3()
109+
110+
#endif
111+
112+
// CHECK-LABEL: define void @test5()
113+
// CHECK: br label %[[L1:.*]]
114+
// CHECK: [[L1]]:
115+
// CHECK-NEXT: call i32 @func0()
116+
// CHECK-NEXT: ret void
117+
118+
void test5(void) {
119+
if (__builtin_available(domain:feature1)) {
120+
goto L1;
121+
L1:
122+
func0();
123+
} else {
124+
goto L2;
125+
L2:
126+
func2();
127+
}
128+
}
129+
130+
#endif /* HEADER */

0 commit comments

Comments
 (0)