Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 1cf6569

Browse files
committed
Merge remote-tracking branch 'origin/apple/stable/20190619' into stable
2 parents 36a5e1a + 9ebee0a commit 1cf6569

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-
static void skipString(const char *&First, const char *const End) {
189-
assert(*First == '\'' || *First == '"' || *First == '<');
190-
const char 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
static unsigned isEOL(const char *First, const char *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+
static void skipString(const char *&First, const char *const End) {
199+
assert(*First == '\'' || *First == '"' || *First == '<');
200+
const char 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+
const char *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
static unsigned skipNewline(const char *&First, const char *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+
struct large {
5+
void* pointers[8];
6+
};
7+
8+
void pass_large(struct large);
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+
void example() {
16+
struct large l = {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)