Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Mar 28, 2020. It is now read-only.
/swift-clangPublic archive

Commit1cf6569

Browse files
committed
Merge remote-tracking branch 'origin/apple/stable/20190619' into stable
2 parents36a5e1a +9ebee0a commit1cf6569

File tree

4 files changed

+184
-11
lines changed

4 files changed

+184
-11
lines changed

‎lib/CodeGen/CGCall.cpp‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3868,6 +3868,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
38683868
Address swiftErrorTemp =Address::invalid();
38693869
Address swiftErrorArg =Address::invalid();
38703870

3871+
// When passing arguments using temporary allocas, we need to add the
3872+
// appropriate lifetime markers. This vector keeps track of all the lifetime
3873+
// markers that need to be ended right after the call.
3874+
SmallVector<CallLifetimeEnd,2> CallLifetimeEndAfterCall;
3875+
38713876
// Translate all of the arguments as necessary to match the IR lowering.
38723877
assert(CallInfo.arg_size() == CallArgs.size() &&
38733878
"Mismatch between function signature & arguments.");
@@ -3984,6 +3989,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
39843989
Address AI =CreateMemTempWithoutCast(
39853990
I->Ty, ArgInfo.getIndirectAlign(),"byval-temp");
39863991
IRCallArgs[FirstIRArg] = AI.getPointer();
3992+
3993+
// Emit lifetime markers for the temporary alloca.
3994+
uint64_t ByvalTempElementSize =
3995+
CGM.getDataLayout().getTypeAllocSize(AI.getElementType());
3996+
llvm::Value *LifetimeSize =
3997+
EmitLifetimeStart(ByvalTempElementSize, AI.getPointer());
3998+
3999+
// Add cleanup code to emit the end lifetime marker after the call.
4000+
if (LifetimeSize)// In case we disabled lifetime markers.
4001+
CallLifetimeEndAfterCall.emplace_back(AI, LifetimeSize);
4002+
4003+
// Generate the copy.
39874004
I->copyInto(*this, AI);
39884005
}else {
39894006
// Skip the extra memcpy call.
@@ -4551,6 +4568,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
45514568
}
45524569
}
45534570

4571+
// Explicitly call CallLifetimeEnd::Emit just to re-use the code even though
4572+
// we can't use the full cleanup mechanism.
4573+
for (CallLifetimeEnd &LifetimeEnd : CallLifetimeEndAfterCall)
4574+
LifetimeEnd.Emit(*this,/*Flags=*/{});
4575+
45544576
return Ret;
45554577
}
45564578

‎lib/Lex/DependencyDirectivesSourceMinimizer.cpp‎

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,6 @@ static void skipRawString(const char *&First, const char *const End) {
185185
}
186186
}
187187

188-
staticvoidskipString(constchar *&First,constchar *const End) {
189-
assert(*First =='\'' || *First =='"' || *First =='<');
190-
constchar Terminator = *First =='<' ?'>' : *First;
191-
for (++First; First != End && *First != Terminator; ++First)
192-
if (*First =='\\')
193-
if (++First == End)
194-
return;
195-
if (First != End)
196-
++First;// Finish off the string.
197-
}
198-
199188
// Returns the length of EOL, either 0 (no end-of-line), 1 (\n) or 2 (\r\n)
200189
staticunsignedisEOL(constchar *First,constchar *const End) {
201190
if (First == End)
@@ -206,6 +195,35 @@ static unsigned isEOL(const char *First, const char *const End) {
206195
return !!isVerticalWhitespace(First[0]);
207196
}
208197

198+
staticvoidskipString(constchar *&First,constchar *const End) {
199+
assert(*First =='\'' || *First =='"' || *First =='<');
200+
constchar Terminator = *First =='<' ?'>' : *First;
201+
for (++First; First != End && *First != Terminator; ++First) {
202+
// String and character literals don't extend past the end of the line.
203+
if (isVerticalWhitespace(*First))
204+
return;
205+
if (*First !='\\')
206+
continue;
207+
// Skip past backslash to the next character. This ensures that the
208+
// character right after it is skipped as well, which matters if it's
209+
// the terminator.
210+
if (++First == End)
211+
return;
212+
if (!isWhitespace(*First))
213+
continue;
214+
// Whitespace after the backslash might indicate a line continuation.
215+
constchar *FirstAfterBackslashPastSpace = First;
216+
skipOverSpaces(FirstAfterBackslashPastSpace, End);
217+
if (unsigned NLSize =isEOL(FirstAfterBackslashPastSpace, End)) {
218+
// Advance the character pointer to the next line for the next
219+
// iteration.
220+
First = FirstAfterBackslashPastSpace + NLSize -1;
221+
}
222+
}
223+
if (First != End)
224+
++First;// Finish off the string.
225+
}
226+
209227
// Returns the length of the skipped newline
210228
staticunsignedskipNewline(constchar *&First,constchar *End) {
211229
if (First == End)

‎test/CodeGen/aarch64-byval-temp.c‎

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// RUN: %clang_cc1 -emit-llvm -triple arm64-- -o - %s -O0 | FileCheck %s --check-prefix=CHECK-O0
2+
// RUN: %clang_cc1 -emit-llvm -disable-llvm-optzns -triple arm64-- -o - %s -O3 | FileCheck %s --check-prefix=CHECK-O3
3+
4+
structlarge {
5+
void*pointers[8];
6+
};
7+
8+
voidpass_large(structlarge);
9+
10+
// For arm64, we don't use byval to pass structs but instead we create
11+
// temporary allocas.
12+
//
13+
// Make sure we generate the appropriate lifetime markers for the temporary
14+
// allocas so that the optimizer can re-use stack slots if possible.
15+
voidexample() {
16+
structlargel= {0};
17+
pass_large(l);
18+
pass_large(l);
19+
}
20+
// CHECK-O0-LABEL: define void @example(
21+
// The alloca for the struct on the stack.
22+
// CHECK-O0: %[[l:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
23+
// The alloca for the temporary stack space that we use to pass the argument.
24+
// CHECK-O0-NEXT: %[[byvaltemp:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
25+
// Another one to pass the argument to the second function call.
26+
// CHECK-O0-NEXT: %[[byvaltemp1:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
27+
// First, memset `l` to 0.
28+
// CHECK-O0-NEXT: %[[bitcastl:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
29+
// CHECK-O0-NEXT: call void @llvm.memset.p0i8.i64(i8* align 8 %[[bitcastl]], i8 0, i64 64, i1 false)
30+
// Then, memcpy `l` to the temporary stack space.
31+
// CHECK-O0-NEXT: %[[src:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp]] to i8*
32+
// CHECK-O0-NEXT: %[[dst:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
33+
// CHECK-O0-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[src]], i8* align 8 %[[dst]], i64 64, i1 false)
34+
// Finally, call using a pointer to the temporary stack space.
35+
// CHECK-O0-NEXT: call void @pass_large(%struct.large* %[[byvaltemp]])
36+
// Now, do the same for the second call, using the second temporary alloca.
37+
// CHECK-O0-NEXT: %[[src:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp1]] to i8*
38+
// CHECK-O0-NEXT: %[[dst:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
39+
// CHECK-O0-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[src]], i8* align 8 %[[dst]], i64 64, i1 false)
40+
// CHECK-O0-NEXT: call void @pass_large(%struct.large* %[[byvaltemp1]])
41+
// CHECK-O0-NEXT: ret void
42+
//
43+
// At O3, we should have lifetime markers to help the optimizer re-use the temporary allocas.
44+
//
45+
// CHECK-O3-LABEL: define void @example(
46+
// The alloca for the struct on the stack.
47+
// CHECK-O3: %[[l:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
48+
// The alloca for the temporary stack space that we use to pass the argument.
49+
// CHECK-O3-NEXT: %[[byvaltemp:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
50+
// Another one to pass the argument to the second function call.
51+
// CHECK-O3-NEXT: %[[byvaltemp1:[0-9A-Za-z-]+]] = alloca %struct.large, align 8
52+
//
53+
// Mark the start of the lifetime for `l`
54+
// CHECK-O3-NEXT: %[[bitcastl:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
55+
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0i8(i64 64, i8* %[[bitcastl]])
56+
//
57+
// First, memset `l` to 0.
58+
// CHECK-O3-NEXT: %[[bitcastl:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
59+
// CHECK-O3-NEXT: call void @llvm.memset.p0i8.i64(i8* align 8 %[[bitcastl]], i8 0, i64 64, i1 false)
60+
//
61+
// Lifetime of the first temporary starts here and ends right after the call.
62+
// CHECK-O3-NEXT: %[[bitcastbyvaltemp:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp]] to i8*
63+
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0i8(i64 64, i8* %[[bitcastbyvaltemp]])
64+
//
65+
// Then, memcpy `l` to the temporary stack space.
66+
// CHECK-O3-NEXT: %[[src:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp]] to i8*
67+
// CHECK-O3-NEXT: %[[dst:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
68+
// CHECK-O3-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[src]], i8* align 8 %[[dst]], i64 64, i1 false)
69+
// Finally, call using a pointer to the temporary stack space.
70+
// CHECK-O3-NEXT: call void @pass_large(%struct.large* %[[byvaltemp]])
71+
//
72+
// The lifetime of the temporary used to pass a pointer to the struct ends here.
73+
// CHECK-O3-NEXT: %[[bitcastbyvaltemp:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp]] to i8*
74+
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0i8(i64 64, i8* %[[bitcastbyvaltemp]])
75+
//
76+
// Now, do the same for the second call, using the second temporary alloca.
77+
// CHECK-O3-NEXT: %[[bitcastbyvaltemp:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp1]] to i8*
78+
// CHECK-O3-NEXT: call void @llvm.lifetime.start.p0i8(i64 64, i8* %[[bitcastbyvaltemp]])
79+
// CHECK-O3-NEXT: %[[src:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp1]] to i8*
80+
// CHECK-O3-NEXT: %[[dst:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[l]] to i8*
81+
// CHECK-O3-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[src]], i8* align 8 %[[dst]], i64 64, i1 false)
82+
// CHECK-O3-NEXT: call void @pass_large(%struct.large* %[[byvaltemp1]])
83+
// CHECK-O3-NEXT: %[[bitcastbyvaltemp:[0-9A-Za-z-]+]] = bitcast %struct.large* %[[byvaltemp1]] to i8*
84+
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0i8(i64 64, i8* %[[bitcastbyvaltemp]])
85+
//
86+
// Mark the end of the lifetime of `l`.
87+
// CHECK-O3-NEXT: %[[bitcastl:[0-9A-Za-z-]+]] = bitcast %struct.large* %l to i8*
88+
// CHECK-O3-NEXT: call void @llvm.lifetime.end.p0i8(i64 64, i8* %[[bitcastl]])
89+
// CHECK-O3-NEXT: ret void

‎unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,50 @@ TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) {
594594
EXPECT_STREQ("#pragma once\n#include <test.h>\n", Out.data());
595595
}
596596

597+
TEST(MinimizeSourceToDependencyDirectivesTest,
598+
SkipLineStringCharLiteralsUntilNewline) {
599+
SmallVector<char,128> Out;
600+
601+
StringRef Source =R"(#if NEVER_ENABLED
602+
#define why(fmt, ...) #error don't try me
603+
#endif
604+
605+
void foo();
606+
)";
607+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
608+
EXPECT_STREQ(
609+
"#if NEVER_ENABLED\n#define why(fmt,...) #error don't try me\n#endif\n",
610+
Out.data());
611+
612+
Source =R"(#if NEVER_ENABLED
613+
#define why(fmt, ...) "quote dropped
614+
#endif
615+
616+
void foo();
617+
)";
618+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
619+
EXPECT_STREQ(
620+
"#if NEVER_ENABLED\n#define why(fmt,...)\"quote dropped\n#endif\n",
621+
Out.data());
622+
}
623+
624+
TEST(MinimizeSourceToDependencyDirectivesTest,
625+
SupportWhitespaceBeforeLineContinuationInStringSkipping) {
626+
SmallVector<char,128> Out;
627+
628+
StringRef Source ="#define X '\\\t\nx'\nvoid foo() {}";
629+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
630+
EXPECT_STREQ("#define X '\\\t\nx'\n", Out.data());
631+
632+
Source ="#define X\"\\\r\nx\"\nvoid foo() {}";
633+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
634+
EXPECT_STREQ("#define X\"\\\r\nx\"\n", Out.data());
635+
636+
Source ="#define X\"\\\r\nx\n#include <x>\n";
637+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
638+
EXPECT_STREQ("#define X\"\\\r\nx\n#include <x>\n", Out.data());
639+
}
640+
597641
TEST(MinimizeSourceToDependencyDirectivesTest, CxxModules) {
598642
SmallVector<char,128> Out;
599643
SmallVector<Token,4> Tokens;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp