Skip to content

Commit 09ba317

Browse files
authored
---
yaml --- r: 314869 b: refs/heads/master c: e51086b h: refs/heads/master i: 314867: a049a9f
1 parent 60169ac commit 09ba317

25 files changed

+444
-149
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 847dd2f28f3b26971324aa2c48595463437d7c32
2+
refs/heads/master: e51086bcc1e88f47eb132ca91aebd76508417bdd
33
refs/heads/master-next: 66a7e661ff8e88e2d4efab3e430197a7a941e352
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/lib/AST/ASTVerifier.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,14 +2362,6 @@ class Verifier : public ASTWalker {
23622362
}
23632363
}
23642364

2365-
if (VD->isFinal() != VD->getAttrs().hasAttribute<FinalAttr>()) {
2366-
Out << "decl should be final iff it has FinalAttr, but isFinal() = "
2367-
<< VD->isFinal() << " and hasAttribute<FinalAttr>() = "
2368-
<< VD->getAttrs().hasAttribute<FinalAttr>() << "\n";
2369-
VD->dump(Out);
2370-
abort();
2371-
}
2372-
23732365
verifyCheckedBase(VD);
23742366
}
23752367

trunk/lib/SIL/LinearLifetimeChecker.cpp

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@ namespace {
4242
using BrPropUserAndBlockPair = std::pair<BranchPropagatedUser, SILBasicBlock *>;
4343

4444
struct State {
45-
/// The value that we are checking.
46-
SILValue value;
45+
/// If we are checking for a specific value, this is that value. This is only
46+
/// used for diagnostic purposes. The algorithm if this is set works on the
47+
/// parent block of the value.
48+
Optional<SILValue> value;
49+
50+
/// The block where the live range begins. If the field value is not None,
51+
/// then this is value->getParentBlock();
52+
SILBasicBlock *beginBlock;
4753

4854
/// The result error object that use to signal either that no errors were
4955
/// found or if errors are found the specific type of error that was found.
@@ -75,8 +81,15 @@ struct State {
7581
State(SILValue value, SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
7682
ErrorBehaviorKind errorBehavior,
7783
SmallVectorImpl<SILBasicBlock *> *leakingBlocks)
78-
: value(value), error(errorBehavior), visitedBlocks(visitedBlocks),
79-
leakingBlocks(leakingBlocks) {}
84+
: value(value), beginBlock(value->getParentBlock()), error(errorBehavior),
85+
visitedBlocks(visitedBlocks), leakingBlocks(leakingBlocks) {}
86+
87+
State(SILBasicBlock *beginBlock,
88+
SmallPtrSetImpl<SILBasicBlock *> &visitedBlocks,
89+
ErrorBehaviorKind errorBehavior,
90+
SmallVectorImpl<SILBasicBlock *> *leakingBlocks)
91+
: value(), beginBlock(beginBlock), error(errorBehavior),
92+
visitedBlocks(visitedBlocks), leakingBlocks(leakingBlocks) {}
8093

8194
void initializeAllNonConsumingUses(
8295
ArrayRef<BranchPropagatedUser> nonConsumingUsers);
@@ -183,7 +196,7 @@ void State::initializeAllConsumingUses(
183196
// If this user is in the same block as the value, do not visit
184197
// predecessors. We must be extra tolerant here since we allow for
185198
// unreachable code.
186-
if (userBlock == value->getParentBlock())
199+
if (userBlock == beginBlock)
187200
continue;
188201

189202
// Then for each predecessor of this block...
@@ -203,10 +216,15 @@ void State::initializeConsumingUse(BranchPropagatedUser consumingUser,
203216
return;
204217

205218
error.handleOverConsume([&] {
206-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
207-
<< "Found over consume?!\n"
208-
<< "Value: " << *value << "User: " << *consumingUser
209-
<< "Block: bb" << userBlock->getDebugID() << "\n\n";
219+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName() << "'\n"
220+
<< "Found over consume?!\n";
221+
if (auto v = value) {
222+
llvm::errs() << "Value: " << *value;
223+
} else {
224+
llvm::errs() << "Value: N/A\n";
225+
}
226+
llvm::errs() << "User: " << *consumingUser << "Block: bb"
227+
<< userBlock->getDebugID() << "\n\n";
210228
});
211229
}
212230

@@ -228,10 +246,16 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
228246
// the cond branch user is in a previous block. So just bail early.
229247
if (consumingUser.isCondBranchUser()) {
230248
error.handleUseAfterFree([&]() {
231-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
249+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
250+
<< "'\n"
232251
<< "Found use after free?!\n"
233-
<< "Value: " << *value
234-
<< "Consuming User: " << *consumingUser
252+
<< "Value: ";
253+
if (auto v = value) {
254+
llvm::errs() << *v;
255+
} else {
256+
llvm::errs() << "N/A. \n";
257+
}
258+
llvm::errs() << "Consuming User: " << *consumingUser
235259
<< "Non Consuming User: " << *iter->second << "Block: bb"
236260
<< userBlock->getDebugID() << "\n\n";
237261
});
@@ -255,10 +279,16 @@ void State::checkForSameBlockUseAfterFree(BranchPropagatedUser consumingUser,
255279
return nonConsumingUser == &i;
256280
}) != userBlock->end()) {
257281
error.handleUseAfterFree([&] {
258-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
282+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
283+
<< "'\n"
259284
<< "Found use after free?!\n"
260-
<< "Value: " << *value
261-
<< "Consuming User: " << *consumingUser
285+
<< "Value: ";
286+
if (auto v = value) {
287+
llvm::errs() << *v;
288+
} else {
289+
llvm::errs() << "N/A. \n";
290+
}
291+
llvm::errs() << "Consuming User: " << *consumingUser
262292
<< "Non Consuming User: " << *iter->second << "Block: bb"
263293
<< userBlock->getDebugID() << "\n\n";
264294
});
@@ -287,10 +317,17 @@ void State::checkPredsForDoubleConsume(BranchPropagatedUser consumingUser,
287317
}
288318

289319
error.handleOverConsume([&] {
290-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
320+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName() << "'\n"
291321
<< "Found over consume?!\n"
292-
<< "Value: " << *value << "User: " << *consumingUser
293-
<< "Block: bb" << userBlock->getDebugID() << "\n\n";
322+
<< "Value: ";
323+
if (auto v = value) {
324+
llvm::errs() << *v;
325+
} else {
326+
llvm::errs() << "N/A. \n";
327+
}
328+
329+
llvm::errs() << "User: " << *consumingUser << "Block: bb"
330+
<< userBlock->getDebugID() << "\n\n";
294331
});
295332
}
296333

@@ -310,10 +347,16 @@ void State::checkPredsForDoubleConsume(SILBasicBlock *userBlock) {
310347
}
311348

312349
error.handleOverConsume([&] {
313-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
350+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName() << "'\n"
314351
<< "Found over consume?!\n"
315-
<< "Value: " << *value << "Block: bb"
316-
<< userBlock->getDebugID() << "\n\n";
352+
<< "Value: ";
353+
if (auto v = value) {
354+
llvm::errs() << *v;
355+
} else {
356+
llvm::errs() << "N/A. \n";
357+
}
358+
359+
llvm::errs() << "Block: bb" << userBlock->getDebugID() << "\n\n";
317360
});
318361
}
319362

@@ -370,7 +413,7 @@ void State::performDataflow(DeadEndBlocks &deBlocks) {
370413
// further to do since we do not want to visit the predecessors of our
371414
// dominating block. On the other hand, we do want to add its successors to
372415
// the successorBlocksThatMustBeVisited set.
373-
if (block == value->getParentBlock())
416+
if (block == beginBlock)
374417
continue;
375418

376419
// Then for each predecessor of this block:
@@ -405,11 +448,16 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
405448

406449
// If we are supposed to error on leaks, do so now.
407450
error.handleLeak([&] {
408-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
451+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
452+
<< "'\n"
409453
<< "Error! Found a leak due to a consuming post-dominance "
410-
"failure!\n"
411-
<< " Value: " << *value
412-
<< " Post Dominating Failure Blocks:\n";
454+
"failure!\n";
455+
if (auto v = value) {
456+
llvm::errs() << "Value: " << *value;
457+
} else {
458+
llvm::errs() << "Value: N/A\n";
459+
}
460+
llvm::errs() << " Post Dominating Failure Blocks:\n";
413461
for (auto *succBlock : successorBlocksThatMustBeVisited) {
414462
llvm::errs() << " bb" << succBlock->getDebugID();
415463
}
@@ -434,10 +482,18 @@ void State::checkDataflowEndState(DeadEndBlocks &deBlocks) {
434482
}
435483

436484
error.handleUseAfterFree([&] {
437-
llvm::errs() << "Function: '" << value->getFunction()->getName() << "'\n"
485+
llvm::errs() << "Function: '" << beginBlock->getParent()->getName()
486+
<< "'\n"
438487
<< "Found use after free due to unvisited non lifetime "
439488
"ending uses?!\n"
440-
<< "Value: " << *value << " Remaining Users:\n";
489+
<< "Value: ";
490+
if (auto v = value) {
491+
llvm::errs() << *v;
492+
} else {
493+
llvm::errs() << "N/A. \n";
494+
}
495+
496+
llvm::errs() << " Remaining Users:\n";
441497
for (auto &pair : blocksWithNonConsumingUses) {
442498
llvm::errs() << "User:" << *pair.second << "Block: bb"
443499
<< pair.first->getDebugID() << "\n";

trunk/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ void ExistentialSpecializerCloner::cloneArguments(
159159
GenericTypeParamType *GenericParam = iter->second;
160160
SILType GenericSILType =
161161
NewF.getLoweredType(NewF.mapTypeIntoContext(GenericParam));
162+
GenericSILType = GenericSILType.getCategoryType(
163+
ArgDesc.Arg->getType().getCategory());
162164
auto *NewArg = ClonedEntryBB->createFunctionArgument(GenericSILType);
163165
NewArg->setOwnershipKind(ValueOwnershipKind(
164166
NewF, GenericSILType, ArgDesc.Arg->getArgumentConvention()));
@@ -173,6 +175,7 @@ void ExistentialSpecializerCloner::cloneArguments(
173175
Ctx.AllocateCopy(NewConformances);
174176
auto ExistentialRepr =
175177
ArgDesc.Arg->getType().getPreferredExistentialRepresentation(M);
178+
auto &EAD = ExistentialArgDescriptor[ArgDesc.Index];
176179
switch (ExistentialRepr) {
177180
case ExistentialRepresentation::Opaque: {
178181
/// Create this sequence for init_existential_addr.:
@@ -190,7 +193,7 @@ void ExistentialSpecializerCloner::cloneArguments(
190193
InsertLoc, ASI, NewArg->getType().getASTType(), NewArg->getType(),
191194
Conformances);
192195

193-
bool origConsumed = ExistentialArgDescriptor[ArgDesc.Index].isConsumed;
196+
bool origConsumed = EAD.isConsumed;
194197
// If the existential is not consumed in the function body, then the one
195198
// we introduce here needs cleanup.
196199
if (!origConsumed)
@@ -204,16 +207,32 @@ void ExistentialSpecializerCloner::cloneArguments(
204207
break;
205208
}
206209
case ExistentialRepresentation::Class: {
210+
SILValue NewArgValue = NewArg;
211+
if (!NewArg->getType().isObject()) {
212+
NewArgValue = NewFBuilder.createLoad(InsertLoc, NewArg,
213+
LoadOwnershipQualifier::Unqualified);
214+
}
215+
207216
// FIXME_ownership: init_existential_ref always takes ownership of the
208217
// incoming reference. If the argument convention is borrowed
209218
// (!isConsumed), then we should create a copy_value here and add this new
210219
// existential to the CleanupValues vector.
211220

212221
/// Simple case: Create an init_existential.
213222
/// %5 = init_existential_ref %0 : $T : $T, $P
214-
auto *InitRef = NewFBuilder.createInitExistentialRef(
215-
InsertLoc, ArgDesc.Arg->getType(), NewArg->getType().getASTType(),
216-
NewArg, Conformances);
223+
SILValue InitRef = NewFBuilder.createInitExistentialRef(
224+
InsertLoc, ArgDesc.Arg->getType().getObjectType(),
225+
NewArg->getType().getASTType(),
226+
NewArgValue, Conformances);
227+
228+
if (!NewArg->getType().isObject()) {
229+
auto alloc = NewFBuilder.createAllocStack(InsertLoc,
230+
InitRef->getType());
231+
NewFBuilder.createStore(InsertLoc, InitRef, alloc,
232+
StoreOwnershipQualifier::Unqualified);
233+
InitRef = alloc;
234+
AllocStackInsts.push_back(alloc);
235+
}
217236

218237
entryArgs.push_back(InitRef);
219238
break;
@@ -369,7 +388,8 @@ void ExistentialTransform::populateThunkBody() {
369388
/// Create a basic block and the function arguments.
370389
auto *ThunkBody = F->createBasicBlock();
371390
for (auto &ArgDesc : ArgumentDescList) {
372-
ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl);
391+
auto argumentType = ArgDesc.Arg->getType();
392+
ThunkBody->createFunctionArgument(argumentType, ArgDesc.Decl);
373393
}
374394

375395
/// Builder to add new instructions in the Thunk.
@@ -394,7 +414,11 @@ void ExistentialTransform::populateThunkBody() {
394414
SmallVector<SILValue, 8> ApplyArgs;
395415
// Maintain a list of arg values to be destroyed. These are consumed by the
396416
// convention and require a copy.
397-
SmallVector<CopyAddrInst *, 8> TempCopyAddrInsts;
417+
struct Temp {
418+
SILValue DeallocStackEntry;
419+
SILValue DestroyValue;
420+
};
421+
SmallVector<Temp, 8> Temps;
398422
SmallDenseMap<GenericTypeParamType *, Type> GenericToOpenedTypeMap;
399423
for (auto &ArgDesc : ArgumentDescList) {
400424
auto iter = ArgToGenericTypeMap.find(ArgDesc.Index);
@@ -422,22 +446,32 @@ void ExistentialTransform::populateThunkBody() {
422446
// must pass in a copy.
423447
auto *ASI =
424448
Builder.createAllocStack(Loc, OpenedSILType);
425-
auto *CAI =
426-
Builder.createCopyAddr(Loc, archetypeValue, ASI, IsNotTake,
427-
IsInitialization_t::IsInitialization);
428-
TempCopyAddrInsts.push_back(CAI);
449+
Builder.createCopyAddr(Loc, archetypeValue, ASI, IsNotTake,
450+
IsInitialization_t::IsInitialization);
451+
Temps.push_back({ASI, OrigOperand});
429452
calleeArg = ASI;
430453
}
431454
ApplyArgs.push_back(calleeArg);
432455
break;
433456
}
434457
case ExistentialRepresentation::Class: {
435-
/// If the operand is not object type, we would need an explicit load.
458+
// If the operand is not object type, we need an explicit load.
459+
SILValue OrigValue = OrigOperand;
460+
if (!OrigOperand->getType().isObject()) {
461+
OrigValue = Builder.createLoad(Loc, OrigValue,
462+
LoadOwnershipQualifier::Unqualified);
463+
}
436464
// OpenExistentialRef forwards ownership, so it does the right thing
437465
// regardless of whether the argument is borrowed or consumed.
438-
assert(OrigOperand->getType().isObject());
439466
archetypeValue =
440-
Builder.createOpenExistentialRef(Loc, OrigOperand, OpenedSILType);
467+
Builder.createOpenExistentialRef(Loc, OrigValue, OpenedSILType);
468+
if (!OrigOperand->getType().isObject()) {
469+
SILValue ASI = Builder.createAllocStack(Loc, OpenedSILType);
470+
Builder.createStore(Loc, archetypeValue, ASI,
471+
StoreOwnershipQualifier::Unqualified);
472+
Temps.push_back({ASI, SILValue()});
473+
archetypeValue = ASI;
474+
}
441475
ApplyArgs.push_back(archetypeValue);
442476
break;
443477
}
@@ -511,7 +545,7 @@ void ExistentialTransform::populateThunkBody() {
511545
ReturnValue = Builder.createApply(Loc, FRI, SubMap, ApplyArgs);
512546
}
513547
auto cleanupLoc = RegularLocation::getAutoGeneratedLocation();
514-
for (CopyAddrInst *CAI : reversed(TempCopyAddrInsts)) {
548+
for (auto &Temp : reversed(Temps)) {
515549
// The original argument was copied into a temporary and consumed by the
516550
// callee as such:
517551
// bb (%consumedExistential : $*Protocol)
@@ -523,10 +557,10 @@ void ExistentialTransform::populateThunkBody() {
523557
// Destroy the original arument and deallocation the temporary:
524558
// destroy_addr %consumedExistential : $*Protocol
525559
// dealloc_stack %temp : $*T
526-
auto *consumedExistential = cast<SILFunctionArgument>(
527-
cast<OpenExistentialAddrInst>(CAI->getSrc())->getOperand());
528-
Builder.createDestroyAddr(cleanupLoc, consumedExistential);
529-
Builder.createDeallocStack(cleanupLoc, CAI->getDest());
560+
if (Temp.DestroyValue)
561+
Builder.createDestroyAddr(cleanupLoc, Temp.DestroyValue);
562+
if (Temp.DeallocStackEntry)
563+
Builder.createDeallocStack(cleanupLoc, Temp.DeallocStackEntry);
530564
}
531565
/// Set up the return results.
532566
if (NewF->isNoReturnFunction()) {

0 commit comments

Comments
 (0)