Skip to content

Commit ee22004

Browse files
committed
[IRGen] Walk inlineable Clang functions and emit their dependencies.
This handles things like NSSwapHostLongLongToBig and MKMapRectMake that are static inline functions that themselves call other static inline functions. <rdar://problem/17227237> Swift SVN r21080
1 parent 65cd1ac commit ee22004

File tree

10 files changed

+124
-20
lines changed

10 files changed

+124
-20
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ ClangImporter::create(ASTContext &ctx,
214214
// target.
215215
std::vector<std::string> invocationArgStrs = {
216216
"-x", "objective-c", "-std=gnu11", "-fobjc-arc", "-fmodules", "-fblocks",
217-
"-fsyntax-only", "-w",
217+
"-fsyntax-only", "-w", "-femit-all-decls",
218218
"-triple", irGenOpts.Triple, "-target-cpu", irGenOpts.TargetCPU,
219219
"-target-abi", irGenOpts.TargetABI,
220220
SHIMS_INCLUDE_FLAG, searchPathOpts.RuntimeResourcePath,

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,17 +2021,7 @@ namespace {
20212021
// Keep track of inline function bodies so that we can generate
20222022
// IR from them using Clang's IR generator.
20232023
if ((decl->isInlined() || decl->hasAttr<clang::AlwaysInlineAttr>())
2024-
&& decl->getBody()) {
2025-
// FIXME: Total hack to force instantiation of inline
2026-
// functions into the module rather than going through
2027-
// Clang's CodeGenModule::Release(), which will emit
2028-
// deferred decls that have been referenced, since
2029-
// Release() does many things including emitting stuff
2030-
// that along with what Swift emits results in broken
2031-
// modules.
2032-
auto *attr = clang::UsedAttr::CreateImplicit(decl->getASTContext());
2033-
const_cast<clang::FunctionDecl *>(decl)->addAttr(attr);
2034-
2024+
&& decl->hasBody()) {
20352025
Impl.registerExternalDecl(result);
20362026
}
20372027

lib/IRGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_swift_library(swiftIRGen
22
DebugTypeInfo.cpp
33
GenCast.cpp
4+
GenClangDecl.cpp
45
GenClangType.cpp
56
GenClass.cpp
67
GenControl.cpp

lib/IRGen/GenClangDecl.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===--- GenClangDecl.cpp - Swift IRGen for imported Clang declarations ---===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "IRGenModule.h"
14+
#include "clang/AST/Decl.h"
15+
#include "clang/AST/DeclGroup.h"
16+
#include "clang/AST/DataRecursiveASTVisitor.h"
17+
#include "clang/CodeGen/ModuleBuilder.h"
18+
#include "llvm/ADT/SmallPtrSet.h"
19+
20+
using namespace swift;
21+
using namespace irgen;
22+
23+
namespace {
24+
class ClangDeclRefFinder
25+
: public clang::DataRecursiveASTVisitor<ClangDeclRefFinder> {
26+
std::function<void(const clang::DeclRefExpr *)> callback;
27+
public:
28+
template <typename Fn>
29+
explicit ClangDeclRefFinder(Fn fn) : callback(fn) {}
30+
31+
bool VisitDeclRefExpr(clang::DeclRefExpr *DRE) {
32+
callback(DRE);
33+
return true;
34+
}
35+
};
36+
} // end anonymous namespace
37+
38+
void IRGenModule::emitLocalDecls(clang::Decl *decl) {
39+
auto valueDecl = dyn_cast<clang::ValueDecl>(decl);
40+
if (!valueDecl || valueDecl->isExternallyVisible()) {
41+
ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(decl));
42+
return;
43+
}
44+
45+
if (!GlobalClangDecls.insert(decl).second)
46+
return;
47+
SmallVector<const clang::Decl *, 8> stack;
48+
stack.push_back(decl);
49+
50+
ClangDeclRefFinder refFinder([&](const clang::DeclRefExpr *DRE) {
51+
const clang::ValueDecl *D = DRE->getDecl();
52+
if (!D->hasLinkage() || D->isExternallyVisible())
53+
return;
54+
if (!GlobalClangDecls.insert(D->getCanonicalDecl()).second)
55+
return;
56+
stack.push_back(D);
57+
});
58+
59+
while (!stack.empty()) {
60+
auto *next = const_cast<clang::Decl *>(stack.pop_back_val());
61+
if (auto fn = dyn_cast<clang::FunctionDecl>(next)) {
62+
const clang::FunctionDecl *definition;
63+
if (fn->hasBody(definition))
64+
refFinder.TraverseDecl(const_cast<clang::FunctionDecl *>(definition));
65+
}
66+
ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(next));
67+
}
68+
}
69+

lib/IRGen/GenFunc.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3112,9 +3112,3 @@ void IRGenModule::emitLocalDecls(DestructorDecl *dd) {
31123112
if (dd->getBody())
31133113
emitLocalDecls(dd->getBody());
31143114
}
3115-
3116-
// Emit IR for an imported inline Clang function body.
3117-
void IRGenModule::emitLocalDecls(clang::Decl *decl) {
3118-
ClangCodeGen->HandleTopLevelDecl(clang::DeclGroupRef(decl));
3119-
}
3120-

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/Basic/SuccessorMap.h"
2323
#include "llvm/ADT/BitVector.h"
2424
#include "llvm/ADT/DenseMap.h"
25+
#include "llvm/ADT/DenseSet.h"
2526
#include "llvm/ADT/SmallPtrSet.h"
2627
#include "llvm/ADT/SmallVector.h"
2728
#include "llvm/ADT/StringMap.h"
@@ -299,6 +300,7 @@ class IRGenModule {
299300
private:
300301
llvm::DenseMap<LinkEntity, llvm::Constant*> GlobalVars;
301302
llvm::DenseMap<LinkEntity, llvm::Function*> GlobalFuncs;
303+
llvm::DenseSet<const clang::Decl *> GlobalClangDecls;
302304
llvm::StringMap<llvm::Constant*> GlobalStrings;
303305
llvm::StringMap<llvm::Constant*> GlobalUTF16Strings;
304306
llvm::StringMap<llvm::Constant*> ObjCSelectorRefs;

test/IRGen/Inputs/usr/include/Gizmo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ typedef long NSInteger;
4242

4343
static inline int innerZero(void) { return 0; }
4444
static inline int zero(void) { return innerZero(); }
45+
static inline int wrappedZero(void) { return zero(); }
46+
47+
extern int getInt(void);
48+
static inline int wrappedGetInt(void) { return getInt(); }
4549

4650
@interface NSView : NSObject
4751
- (struct NSRect) convertRectFromBase: (struct NSRect) r;

test/IRGen/clang_inline.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,21 @@ import gizmo
44

55
// CHECK: define i64 @_TFC12clang_inline16CallStaticInline10ReturnZerofS0_FT_Si(%C12clang_inline16CallStaticInline*) {
66
// CHECK: define internal i32 @zero() #0 {
7-
// FIXME: We should be generating the IR for the body of innerZero as well.
8-
// CHECK: declare i32 @innerZero() #2
97
class CallStaticInline {
108
func ReturnZero() -> Int { return Int(zero()) }
119
}
10+
11+
// CHECK: define i64 @_TFC12clang_inline17CallStaticInline210ReturnZerofS0_FT_Si(%C12clang_inline17CallStaticInline2*) {
12+
// CHECK: define internal i32 @wrappedZero() #0 {
13+
class CallStaticInline2 {
14+
func ReturnZero() -> Int { return Int(wrappedZero()) }
15+
}
16+
17+
// CHECK: define i32 @_TF12clang_inline10testExternFT_VSs5Int32() {
18+
// CHECK: define internal i32 @wrappedGetInt() #0 {
19+
func testExtern() -> CInt {
20+
return wrappedGetInt()
21+
}
22+
23+
// CHECK: define internal i32 @innerZero() #2 {
24+
// CHECK: declare i32 @getInt() #3

test/IRGen/clang_inline_reverse.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Same test as clang_inline.swift, but with the order swapped.
2+
3+
// RUN: rm -rf %t/clang-module-cache
4+
// RUN: %swift -target x86_64-apple-macosx10.9 -module-cache-path %t/clang-module-cache -sdk %S/Inputs %s -emit-ir -module-name clang_inline | FileCheck %s
5+
import gizmo
6+
7+
// CHECK: define i64 @_TFC12clang_inline16CallStaticInline10ReturnZerofS0_FT_Si(%C12clang_inline16CallStaticInline*) {
8+
// CHECK: define internal i32 @wrappedZero() #0 {
9+
class CallStaticInline {
10+
func ReturnZero() -> Int { return Int(wrappedZero()) }
11+
}
12+
13+
// CHECK: define i64 @_TFC12clang_inline17CallStaticInline210ReturnZerofS0_FT_Si(%C12clang_inline17CallStaticInline2*) {
14+
// CHECK: define internal i32 @zero() #0 {
15+
class CallStaticInline2 {
16+
func ReturnZero() -> Int { return Int(zero()) }
17+
}
18+
19+
// CHECK: define internal i32 @innerZero() #2 {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-run-simple-swift | FileCheck %s
2+
3+
import Foundation
4+
import MapKit
5+
6+
let rect = MKMapRectMake(1.0, 2.0, 3.0, 4.0)
7+
// CHECK: {{^}}1.0 2.0 3.0 4.0{{$}}
8+
println("\(rect.origin.x) \(rect.origin.y) \(rect.size.width) \(rect.size.height)")
9+
10+
let value: CUnsignedInt = 0xFF00FF00
11+
// CHECK: {{^}}ff00ff00 ff00ff{{$}}
12+
println("\(String(value, radix: 16)) \(String(NSSwapInt(value), radix: 16))")

0 commit comments

Comments
 (0)