Skip to content

Commit 79c83c7

Browse files
committed
Teach IRGen to tell Clang to emit lazy definitions on demand.
Previously, we had hacks in place to eagerly emit everything in the global ExternalDefinitions list. These can now be removed, at least at the IRGen layer.
1 parent bd5a466 commit 79c83c7

File tree

10 files changed

+104
-85
lines changed

10 files changed

+104
-85
lines changed

include/swift/SIL/SILGlobalVariable.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,15 @@ class SILGlobalVariable
146146

147147
/// Return whether this variable corresponds to a Clang node.
148148
bool hasClangNode() const {
149-
return VDecl->hasClangNode();
149+
return (VDecl ? VDecl->hasClangNode() : false);
150150
}
151151

152152
/// Return the Clang node associated with this variable if it has one.
153153
ClangNode getClangNode() const {
154-
return VDecl->getClangNode();
154+
return (VDecl ? VDecl->getClangNode() : ClangNode());
155155
}
156156
const clang::Decl *getClangDecl() const {
157-
return VDecl->getClangDecl();
157+
return (VDecl ? VDecl->getClangDecl() : nullptr);
158158
}
159159

160160
//===--------------------------------------------------------------------===//

lib/ClangImporter/ClangImporter.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,6 @@ getNormalInvocationArguments(std::vector<std::string> &invocationArgStrs,
326326
// Don't emit LLVM IR.
327327
"-fsyntax-only",
328328

329-
"-femit-all-decls",
330329
SHIMS_INCLUDE_FLAG, searchPathOpts.RuntimeResourcePath,
331330
"-fretain-comments-from-system-headers",
332331
"-fmodules-validate-system-headers",

lib/IRGen/GenClangDecl.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "IRGenModule.h"
1414
#include "clang/AST/Decl.h"
1515
#include "clang/AST/DeclGroup.h"
16+
#include "clang/AST/GlobalDecl.h"
1617
#include "clang/AST/RecursiveASTVisitor.h"
1718
#include "clang/CodeGen/ModuleBuilder.h"
1819
#include "llvm/ADT/SmallPtrSet.h"
@@ -35,10 +36,11 @@ class ClangDeclRefFinder
3536
};
3637
} // end anonymous namespace
3738

38-
void IRGenModule::emitClangDecl(clang::Decl *decl) {
39+
void IRGenModule::emitClangDecl(const clang::Decl *decl) {
3940
auto valueDecl = dyn_cast<clang::ValueDecl>(decl);
4041
if (!valueDecl || valueDecl->isExternallyVisible()) {
41-
ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(decl));
42+
ClangCodeGen->HandleTopLevelDecl(
43+
clang::DeclGroupRef(const_cast<clang::Decl*>(decl)));
4244
return;
4345
}
4446

@@ -69,6 +71,16 @@ void IRGenModule::emitClangDecl(clang::Decl *decl) {
6971
}
7072
}
7173

74+
llvm::Constant *
75+
IRGenModule::getAddrOfClangGlobalDecl(clang::GlobalDecl global,
76+
ForDefinition_t forDefinition) {
77+
// Register the decl with the clang code generator.
78+
if (auto decl = global.getDecl())
79+
emitClangDecl(decl);
80+
81+
return ClangCodeGen->GetAddrOfGlobal(global, (bool) forDefinition);
82+
}
83+
7284
void IRGenModule::finalizeClangCodeGen() {
7385
ClangCodeGen->HandleTranslationUnit(
7486
*const_cast<clang::ASTContext *>(ClangASTContext));

lib/IRGen/GenDecl.cpp

Lines changed: 63 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#include "swift/SIL/FormalLinkage.h"
3131
#include "swift/SIL/SILDebugScope.h"
3232
#include "swift/SIL/SILModule.h"
33+
#include "clang/AST/ASTContext.h"
34+
#include "clang/AST/DeclCXX.h"
35+
#include "clang/AST/GlobalDecl.h"
3336
#include "llvm/IR/Module.h"
3437
#include "llvm/IR/TypeBuilder.h"
3538
#include "llvm/IR/Value.h"
@@ -838,11 +841,6 @@ void IRGenModule::finishEmitAfterTopLevel() {
838841
AccessPath);
839842
DebugInfo->emitImport(Imp);
840843
}
841-
842-
// Emit external definitions used by this module.
843-
for (auto def : Context.ExternalDefinitions) {
844-
emitExternalDefinition(def);
845-
}
846844
}
847845

848846
static void emitLazyTypeMetadata(IRGenModule &IGM, CanType type) {
@@ -1477,52 +1475,25 @@ void IRGenModule::emitGlobalDecl(Decl *D) {
14771475
llvm_unreachable("bad decl kind!");
14781476
}
14791477

1480-
void IRGenModule::emitExternalDefinition(Decl *D) {
1481-
switch (D->getKind()) {
1482-
case DeclKind::Extension:
1483-
case DeclKind::PatternBinding:
1484-
case DeclKind::EnumCase:
1485-
case DeclKind::EnumElement:
1486-
case DeclKind::TopLevelCode:
1487-
case DeclKind::TypeAlias:
1488-
case DeclKind::GenericTypeParam:
1489-
case DeclKind::AssociatedType:
1490-
case DeclKind::Import:
1491-
case DeclKind::Subscript:
1492-
case DeclKind::Destructor:
1493-
case DeclKind::InfixOperator:
1494-
case DeclKind::PrefixOperator:
1495-
case DeclKind::PostfixOperator:
1496-
case DeclKind::IfConfig:
1497-
case DeclKind::Param:
1498-
case DeclKind::Module:
1499-
llvm_unreachable("Not a valid external definition for IRgen");
1500-
1501-
case DeclKind::Var:
1502-
assert(D->getClangDecl() && "Not a valid external var for IRGen");
1503-
return emitClangDecl(const_cast<clang::Decl *>(D->getClangDecl()));
1504-
1505-
case DeclKind::Func:
1506-
if (auto *clangDecl = D->getClangDecl())
1507-
emitClangDecl(const_cast<clang::Decl *>(clangDecl));
1508-
break;
1509-
1510-
case DeclKind::Constructor:
1511-
// Do nothing.
1512-
break;
1513-
1514-
// No need to eagerly emit Swift metadata for external types.
1515-
case DeclKind::Struct:
1516-
case DeclKind::Enum:
1517-
case DeclKind::Class:
1518-
case DeclKind::Protocol:
1519-
break;
1520-
}
1521-
}
1522-
15231478
Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
15241479
const TypeInfo &ti,
15251480
ForDefinition_t forDefinition) {
1481+
if (auto clangDecl = var->getClangDecl()) {
1482+
auto addr = getAddrOfClangGlobalDecl(cast<clang::VarDecl>(clangDecl),
1483+
forDefinition);
1484+
1485+
// If we're not emitting this to define it, make sure we cast it to the
1486+
// right type.
1487+
if (!forDefinition) {
1488+
auto ptrTy = ti.getStorageType()->getPointerTo();
1489+
addr = llvm::ConstantExpr::getBitCast(addr, ptrTy);
1490+
}
1491+
1492+
auto alignment =
1493+
Alignment(getClangASTContext().getDeclAlign(clangDecl).getQuantity());
1494+
return Address(addr, alignment);
1495+
}
1496+
15261497
LinkEntity entity = LinkEntity::forSILGlobalVariable(var);
15271498
ResilienceExpansion expansion = getResilienceExpansionForLayout(var);
15281499

@@ -1605,20 +1576,38 @@ static bool isReadOnlyFunction(SILFunction *f) {
16051576
Eff == EffectsKind::ReadOnly;
16061577
}
16071578

1579+
static clang::GlobalDecl getClangGlobalDeclForFunction(const clang::Decl *decl) {
1580+
if (auto ctor = dyn_cast<clang::CXXConstructorDecl>(decl))
1581+
return clang::GlobalDecl(ctor, clang::Ctor_Complete);
1582+
if (auto dtor = dyn_cast<clang::CXXDestructorDecl>(decl))
1583+
return clang::GlobalDecl(dtor, clang::Dtor_Complete);
1584+
return clang::GlobalDecl(cast<clang::FunctionDecl>(decl));
1585+
}
1586+
16081587
/// Find the entry point for a SIL function.
16091588
llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
16101589
ForDefinition_t forDefinition) {
16111590
LinkEntity entity = LinkEntity::forSILFunction(f);
16121591

16131592
// Check whether we've created the function already.
16141593
// FIXME: We should integrate this into the LinkEntity cache more cleanly.
1615-
llvm::Function *fn = Module.getFunction(f->getName());
1594+
llvm::Function *fn = Module.getFunction(f->getName());
16161595
if (fn) {
16171596
if (forDefinition) updateLinkageForDefinition(*this, fn, entity);
16181597
return fn;
16191598
}
16201599

1621-
bool hasOrderNumber = f->isDefinition();
1600+
// If it's a Clang declaration, ask Clang to generate the IR declaration.
1601+
// This might generate new functions, so we should do it before computing
1602+
// the insert-before point.
1603+
llvm::Constant *clangAddr = nullptr;
1604+
if (auto clangDecl = f->getClangDecl()) {
1605+
auto globalDecl = getClangGlobalDeclForFunction(clangDecl);
1606+
clangAddr = getAddrOfClangGlobalDecl(globalDecl, forDefinition);
1607+
}
1608+
1609+
bool isDefinition = f->isDefinition();
1610+
bool hasOrderNumber = isDefinition;
16221611
unsigned orderNumber = ~0U;
16231612
llvm::Function *insertBefore = nullptr;
16241613

@@ -1630,18 +1619,35 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,
16301619
if (auto emittedFunctionIterator
16311620
= EmittedFunctionsByOrder.findLeastUpperBound(orderNumber))
16321621
insertBefore = *emittedFunctionIterator;
1622+
}
16331623

1634-
// Also, if we have a lazy definition for it, be sure to queue that up.
1635-
if (!forDefinition &&
1636-
!isPossiblyUsedExternally(f->getLinkage(),
1637-
getSILModule().isWholeModule()))
1638-
IRGen.addLazyFunction(f);
1624+
// If it's a Clang declaration, check whether Clang gave us a declaration.
1625+
if (clangAddr) {
1626+
fn = dyn_cast<llvm::Function>(clangAddr->stripPointerCasts());
1627+
1628+
// If we have a function, move it to the appropriate position.
1629+
if (fn) {
1630+
if (hasOrderNumber) {
1631+
auto &fnList = Module.getFunctionList();
1632+
fnList.remove(fn);
1633+
fnList.insert(llvm::Module::iterator(insertBefore), fn);
1634+
1635+
EmittedFunctionsByOrder.insert(orderNumber, fn);
1636+
}
1637+
return fn;
1638+
}
1639+
1640+
// Otherwise, if we have a lazy definition for it, be sure to queue that up.
1641+
} else if (isDefinition && !forDefinition &&
1642+
!isPossiblyUsedExternally(f->getLinkage(),
1643+
getSILModule().isWholeModule())) {
1644+
IRGen.addLazyFunction(f);
16391645
}
1640-
1646+
16411647
llvm::AttributeSet attrs;
16421648
llvm::FunctionType *fnType = getFunctionType(f->getLoweredFunctionType(),
16431649
attrs);
1644-
1650+
16451651
auto cc = expandCallingConv(*this, f->getRepresentation());
16461652
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
16471653

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace clang {
6464
template <class> class CanQual;
6565
class CodeGenerator;
6666
class Decl;
67+
class GlobalDecl;
6768
class Type;
6869
namespace CodeGen {
6970
class CGFunctionInfo;
@@ -643,6 +644,9 @@ class IRGenModule {
643644
llvm::function_ref<void(IRGenFunction &IGF)> generate);
644645

645646
private:
647+
llvm::Constant *getAddrOfClangGlobalDecl(clang::GlobalDecl global,
648+
ForDefinition_t forDefinition);
649+
646650
llvm::DenseMap<LinkEntity, llvm::Constant*> GlobalVars;
647651
llvm::DenseMap<LinkEntity, llvm::Constant*> GlobalGOTEquivalents;
648652
llvm::DenseMap<LinkEntity, llvm::Function*> GlobalFuncs;
@@ -804,7 +808,7 @@ private: \
804808
llvm::Constant *emitFixedTypeLayout(CanType t, const FixedTypeInfo &ti);
805809

806810
void emitNestedTypeDecls(DeclRange members);
807-
void emitClangDecl(clang::Decl *decl);
811+
void emitClangDecl(const clang::Decl *decl);
808812
void finalizeClangCodeGen();
809813
void finishEmitAfterTopLevel();
810814

@@ -950,7 +954,6 @@ private: \
950954
void emitTypeVerifier();
951955
private:
952956
void emitGlobalDecl(Decl *D);
953-
void emitExternalDefinition(Decl *D);
954957
};
955958

956959
/// Stores a pointer to an IRGenModule.

test/ClangModules/cvars_ir.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import cvars
66

77
// Check that the mangling is correct.
8-
// CHECK: @PI = external global [[FLOAT:%.*]]
8+
// CHECK: @PI = external global float, align 4
99

1010
func getPI() -> Float {
1111
return PI

test/IRGen/c_globals.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ public func testCaptureGlobal() {
3131
}) // CHECK: {{^}$}}
3232
}
3333

34+
// CHECK: attributes [[CLANG_FUNC_ATTR]] = { inlinehint nounwind {{.*}}"no-frame-pointer-elim"="true"{{.*}}
3435
// CHECK: attributes [[SWIFT_FUNC_ATTR]] = { "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "target-cpu"
35-
// CHECK: attributes [[CLANG_FUNC_ATTR]] = { inlinehint nounwind {{(ssp )?}}{{(uwtable )?}}"no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "target-cpu"

test/IRGen/newtype.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Newtype
1313

1414
// CHECK-LABEL: define %CSo8NSString* @_TF7newtype14getErrorDomainFT_VSC11ErrorDomain()
1515
public func getErrorDomain() -> ErrorDomain {
16-
// CHECK: load %CSo8NSString*, %CSo8NSString** getelementptr inbounds (%VSC11ErrorDomain, %VSC11ErrorDomain* @SNTErrOne
16+
// CHECK: load %CSo8NSString*, %CSo8NSString** getelementptr inbounds (%VSC11ErrorDomain, %VSC11ErrorDomain* {{.*}}@SNTErrOne
1717
return .one
1818
}
1919

@@ -85,18 +85,18 @@ public func compareABIs() {
8585

8686
// Make sure that the calling conventions align correctly, that is we don't
8787
// have double-indirection or anything else like that
88-
// CHECK: declare %struct.__CFString* @getMyABINewType() #0
89-
// CHECK: declare %struct.__CFString* @getMyABIOldType() #0
88+
// CHECK: declare %struct.__CFString* @getMyABINewType()
89+
// CHECK: declare %struct.__CFString* @getMyABIOldType()
9090
//
91-
// CHECK: declare void @takeMyABINewType(%struct.__CFString*) #0
92-
// CHECK: declare void @takeMyABIOldType(%struct.__CFString*) #0
91+
// CHECK: declare void @takeMyABINewType(%struct.__CFString*)
92+
// CHECK: declare void @takeMyABIOldType(%struct.__CFString*)
9393
//
94-
// CHECK: declare void @takeMyABINewTypeNonNull(%struct.__CFString*) #0
95-
// CHECK: declare void @takeMyABIOldTypeNonNull(%struct.__CFString*) #0
94+
// CHECK: declare void @takeMyABINewTypeNonNull(%struct.__CFString*)
95+
// CHECK: declare void @takeMyABIOldTypeNonNull(%struct.__CFString*)
9696
//
97-
// CHECK: declare %0* @getMyABINewTypeNS() #0
98-
// CHECK: declare %0* @getMyABIOldTypeNS() #0
97+
// CHECK: declare %0* @getMyABINewTypeNS()
98+
// CHECK: declare %0* @getMyABIOldTypeNS()
9999
//
100-
// CHECK: declare void @takeMyABINewTypeNonNullNS(%0*) #0
101-
// CHECK: declare void @takeMyABIOldTypeNonNullNS(%0*) #0
100+
// CHECK: declare void @takeMyABINewTypeNonNullNS(%0*)
101+
// CHECK: declare void @takeMyABIOldTypeNonNullNS(%0*)
102102
}

test/IRGen/objc_globals.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ import Foundation
1010
func blackHole<T>(_ t: T) { }
1111

1212
// CHECK-LABEL: @"OBJC_CLASS_$_NSNumber" = external global %objc_class
13+
// CHECK: @"OBJC_CLASS_$_NSString" = external global {{%.*}}, align
1314
// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_{{.*}}" = private global %struct._class_t* bitcast (%objc_class* @"OBJC_CLASS_$_NSNumber" to %struct._class_t*), section "__DATA, __objc_classrefs, regular, no_dead_strip"
14-
15-
// CHECK-LABEL: @"OBJC_CLASS_$_NSString" = external global %struct._class_t
16-
// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_{{.*}}" = private global %struct._class_t* @"OBJC_CLASS_$_NSString", section "__DATA, __objc_classrefs, regular, no_dead_strip"
15+
// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_{{.*}}" = private global %struct._class_t* bitcast (%objc_class* @"OBJC_CLASS_$_NSString" to %struct._class_t*), section "__DATA, __objc_classrefs, regular, no_dead_strip"
1716

1817
public func testLiterals() {
1918
blackHole(gadget.giveMeASelector())

test/IRGen/objc_structs.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,21 @@ func setFrame(_ g: Gizmo, frame: NSRect) {
3434

3535
// CHECK: define hidden void @_TF12objc_structs8makeRect{{.*}}([[NSRECT]]* noalias nocapture sret, double, double, double, double)
3636
func makeRect(_ a: Double, b: Double, c: Double, d: Double) -> NSRect {
37-
// CHECK: call void @NSMakeRect([[NSRECT]]* noalias nocapture sret {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
37+
// CHECK: call void @NSMakeRect(%struct.NSRect* noalias nocapture sret {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
3838
return NSMakeRect(a,b,c,d)
3939
}
4040
// CHECK: }
4141

4242
// CHECK: define hidden [[stringLayout:[^@]*]] @_TF12objc_structs14stringFromRect{{.*}}(%VSC6NSRect* noalias nocapture dereferenceable({{.*}})) {{.*}} {
4343
func stringFromRect(_ r: NSRect) -> String {
44-
// CHECK: call [[OPAQUE0:.*]]* @NSStringFromRect([[NSRECT]]* byval align 8 {{.*}})
44+
// CHECK: call [[OPAQUE0:.*]]* @NSStringFromRect(%struct.NSRect* byval align 8 {{.*}})
4545
return NSStringFromRect(r)
4646
}
4747
// CHECK: }
4848

4949
// CHECK: define hidden void @_TF12objc_structs9insetRect{{.*}}([[NSRECT]]* noalias nocapture sret, %VSC6NSRect* noalias nocapture dereferenceable({{.*}}), double, double)
5050
func insetRect(_ r: NSRect, x: Double, y: Double) -> NSRect {
51-
// CHECK: call void @NSInsetRect([[NSRECT]]* noalias nocapture sret {{.*}}, [[NSRECT]]* byval align 8 {{.*}}, double {{.*}}, double {{.*}})
51+
// CHECK: call void @NSInsetRect(%struct.NSRect* noalias nocapture sret {{.*}}, %struct.NSRect* byval align 8 {{.*}}, double {{.*}}, double {{.*}})
5252
return NSInsetRect(r, x, y)
5353
}
5454
// CHECK: }
@@ -62,7 +62,7 @@ func convertRectFromBase(_ v: NSView, r: NSRect) -> NSRect {
6262
// CHECK: }
6363

6464
// CHECK: define hidden void @_TF12objc_structs20useStructOfNSStringsFVSC17StructOfNSStringsS0_(%VSC17StructOfNSStrings* noalias nocapture sret, %VSC17StructOfNSStrings* noalias nocapture dereferenceable({{.*}}))
65-
// CHECK: call void @useStructOfNSStringsInObjC(%VSC17StructOfNSStrings* noalias nocapture sret {{%.*}}, %VSC17StructOfNSStrings* byval align 8 {{%.*}})
65+
// CHECK: call void @useStructOfNSStringsInObjC(%struct.StructOfNSStrings* noalias nocapture sret {{%.*}}, %struct.StructOfNSStrings* byval align 8 {{%.*}})
6666
func useStructOfNSStrings(_ s: StructOfNSStrings) -> StructOfNSStrings {
6767
return useStructOfNSStringsInObjC(s)
6868
}

0 commit comments

Comments
 (0)