Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 25 additions & 59 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ class IRGenSILFunction :

/// All alloc_ref instructions which allocate the object on the stack.
llvm::SmallPtrSet<SILInstruction *, 8> StackAllocs;

/// With closure captures it is actually possible to have two function
/// arguments that both have the same name. Until this is fixed, we need to
/// also hash the ArgNo here.
Expand Down Expand Up @@ -759,8 +760,7 @@ class IRGenSILFunction :

void visitSILBasicBlock(SILBasicBlock *BB);

void emitFunctionArgDebugInfo(SILBasicBlock *BB);

void emitErrorResultVar(SILResultInfo ErrorInfo, DebugValueInst *DbgValue);
void emitDebugInfoForAllocStack(AllocStackInst *i, const TypeInfo &type,
llvm::Value *addr);
void visitAllocStackInst(AllocStackInst *i);
Expand Down Expand Up @@ -1470,52 +1470,12 @@ void IRGenSILFunction::estimateStackSize() {
}
}

/// Determine the number of source-level Swift of a function or closure.
static unsigned countArgs(DeclContext *DC) {
unsigned N = 0;
if (auto *Fn = dyn_cast<AbstractFunctionDecl>(DC)) {
for (auto *PL : Fn->getParameterLists())
N += PL->size();

} else if (auto *Closure = dyn_cast<AbstractClosureExpr>(DC))
N += Closure->getParameters()->size();
else
llvm_unreachable("unhandled declcontext type");
return N;
}

void IRGenSILFunction::emitFunctionArgDebugInfo(SILBasicBlock *BB) {
// Emit the artificial error result argument.
auto FnTy = CurSILFn->getLoweredFunctionType();
if (FnTy->hasErrorResult() && CurSILFn->getDeclContext()) {
auto ErrorInfo = FnTy->getErrorResult();
auto ErrorResultSlot = getErrorResultSlot(ErrorInfo.getSILType());
DebugTypeInfo DTI(ErrorInfo.getType(),
ErrorResultSlot->getType(),
IGM.getPointerSize(),
IGM.getPointerAlignment(),
nullptr);
StringRef Name("$error");
// We just need any number that is guaranteed to be larger than every
// other argument. It is only used for sorting.
unsigned ArgNo =
countArgs(CurSILFn->getDeclContext()) + 1 + BB->getBBArgs().size();
auto Storage = emitShadowCopy(ErrorResultSlot.getAddress(), getDebugScope(),
Name, ArgNo);
IGM.DebugInfo->emitVariableDeclaration(
Builder, Storage, DTI, getDebugScope(), nullptr, Name, ArgNo,
IndirectValue, ArtificialValue);
}
}


void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
// Insert into the lowered basic block.
llvm::BasicBlock *llBB = getLoweredBB(BB).bb;
Builder.SetInsertPoint(llBB);

bool InEntryBlock = BB->pred_empty();
bool ArgsEmitted = false;

// Set this block as the dominance point. This implicitly communicates
// with the dominance resolver configured in emitSILFunction.
Expand Down Expand Up @@ -1585,22 +1545,6 @@ void IRGenSILFunction::visitSILBasicBlock(SILBasicBlock *BB) {
// Use an artificial (line 0) location.
IGM.DebugInfo->setCurrentLoc(Builder, DS);

// Function argument handling.
if (InEntryBlock && !ArgsEmitted) {
if (!I.getLoc().isInPrologue() && I.getLoc().getSourceLoc().isValid()) {
// This is the first non-prologue instruction in the entry
// block. The function prologue is where the stack frame is
// set up and storage for local variables and function
// arguments is initialized. We need to emit the debug info
// for the function arguments after the function prologue,
// after the initialization.
if (!DS)
DS = CurSILFn->getDebugScope();
PrologueLocation AutoRestore(IGM.DebugInfo, Builder);
emitFunctionArgDebugInfo(BB);
ArgsEmitted = true;
}
}
if (isa<TermInst>(&I))
emitDebugVariableRangeExtension(BB);
}
Expand Down Expand Up @@ -3188,13 +3132,35 @@ void IRGenSILFunction::visitStoreInst(swift::StoreInst *i) {
}
}

/// Emit the artificial error result argument.
void IRGenSILFunction::emitErrorResultVar(SILResultInfo ErrorInfo,
DebugValueInst *DbgValue) {
auto ErrorResultSlot = getErrorResultSlot(ErrorInfo.getSILType());
SILDebugVariable Var = DbgValue->getVarInfo();
auto Storage = emitShadowCopy(ErrorResultSlot.getAddress(), getDebugScope(),
Var.Name, Var.ArgNo);
DebugTypeInfo DTI(ErrorInfo.getType(), ErrorResultSlot->getType(),
IGM.getPointerSize(), IGM.getPointerAlignment(), nullptr);
IGM.DebugInfo->emitVariableDeclaration(Builder, Storage, DTI, getDebugScope(),
nullptr, Var.Name, Var.ArgNo,
IndirectValue, ArtificialValue);
}

void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
if (!IGM.DebugInfo)
return;

auto SILVal = i->getOperand();
if (isa<SILUndef>(SILVal))
if (isa<SILUndef>(SILVal)) {
// We cannot track the location of inlined error arguments because it has no
// representation in SIL.
if (!i->getDebugScope()->InlinedCallSite &&
i->getVarInfo().Name == "$error") {
auto funcTy = CurSILFn->getLoweredFunctionType();
emitErrorResultVar(funcTy->getErrorResult(), i);
}
return;
}

StringRef Name = getVarName(i);
DebugTypeInfo DbgTy;
Expand Down
9 changes: 4 additions & 5 deletions lib/SILGen/SILGenConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
assert(!selfTy.getClassOrBoundGenericClass()
&& "can't emit a class ctor here");

// Self is a curried argument and thus comes last.
unsigned N = ctor->getParameterList(1)->size() + 1;
// Allocate the local variable for 'self'.
emitLocalVariableWithCleanup(selfDecl, false, N)->finishInitialization(*this);
emitLocalVariableWithCleanup(selfDecl, false)->finishInitialization(*this);

// Mark self as being uninitialized so that DI knows where it is and how to
// check for it.
Expand All @@ -204,7 +202,8 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
}

// Emit the prolog.
emitProlog(ctor->getParameterList(1), ctor->getResultType(), ctor);
emitProlog(ctor->getParameterList(1), ctor->getResultType(), ctor,
ctor->hasThrows());
emitConstructorMetatypeArg(*this, ctor);

// Create a basic block to jump to for the implicit 'self' return.
Expand Down Expand Up @@ -565,7 +564,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
// Emit the prolog for the non-self arguments.
// FIXME: Handle self along with the other body patterns.
emitProlog(ctor->getParameterList(1),
TupleType::getEmpty(F.getASTContext()), ctor);
TupleType::getEmpty(F.getASTContext()), ctor, ctor->hasThrows());

SILType selfTy = getLoweredLoadableType(selfDecl->getType());
SILValue selfArg = new (SGM.M) SILArgument(F.begin(), selfTy, selfDecl);
Expand Down
7 changes: 4 additions & 3 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
MagicFunctionName = SILGenModule::getMagicFunctionName(fd);

Type resultTy = fd->getResultType();
emitProlog(fd, fd->getParameterLists(), resultTy);
emitProlog(fd, fd->getParameterLists(), resultTy, fd->hasThrows());
prepareEpilog(resultTy, fd->hasThrows(), CleanupLocation(fd));

emitProfilerIncrement(fd->getBody());
Expand All @@ -480,7 +480,8 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {
MagicFunctionName = SILGenModule::getMagicFunctionName(ace);

emitProlog(ace, ace->getParameters(), ace->getResultType());
emitProlog(ace, ace->getParameters(), ace->getResultType(),
ace->isBodyThrowing());
prepareEpilog(ace->getResultType(), ace->isBodyThrowing(),
CleanupLocation(ace));
if (auto *ce = dyn_cast<ClosureExpr>(ace)) {
Expand Down Expand Up @@ -858,7 +859,7 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value) {
// is not going to be ever used anyway.
overrideLocationForMagicIdentifiers = SourceLoc();

emitProlog({ }, value->getType(), function.getDecl()->getDeclContext());
emitProlog({}, value->getType(), function.getDecl()->getDeclContext(), false);
prepareEpilog(value->getType(), false, CleanupLocation::get(Loc));
emitReturnExpr(Loc, value);
emitEpilog(Loc);
Expand Down
12 changes: 8 additions & 4 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,14 +709,18 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
//===--------------------------------------------------------------------===//
// Memory management
//===--------------------------------------------------------------------===//


/// Emit debug info for the artificial error inout argument.
void emitErrorArgument(SILLocation Loc, unsigned ArgNo);

/// emitProlog - Generates prolog code to allocate and clean up mutable
/// storage for closure captures and local arguments.
void emitProlog(AnyFunctionRef TheClosure,
ArrayRef<ParameterList*> paramPatterns, Type resultType);
ArrayRef<ParameterList *> paramPatterns, Type resultType,
bool throws);
/// returns the number of variables in paramPatterns.
unsigned emitProlog(ArrayRef<ParameterList*> paramPatterns,
Type resultType, DeclContext *DeclCtx);
unsigned emitProlog(ArrayRef<ParameterList *> paramPatterns, Type resultType,
DeclContext *DeclCtx, bool throws);

/// Create SILArguments in the entry block that bind all the values
/// of the given pattern suitably for being forwarded.
Expand Down
30 changes: 24 additions & 6 deletions lib/SILGen/SILGenProlog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,9 +410,9 @@ static void emitCaptureArguments(SILGenFunction &gen, CapturedValue capture,

void SILGenFunction::emitProlog(AnyFunctionRef TheClosure,
ArrayRef<ParameterList*> paramPatterns,
Type resultType) {
unsigned ArgNo =
emitProlog(paramPatterns, resultType, TheClosure.getAsDeclContext());
Type resultType, bool throws) {
unsigned ArgNo = emitProlog(paramPatterns, resultType,
TheClosure.getAsDeclContext(), throws);

// Emit the capture argument variables. These are placed last because they
// become the first curry level of the SIL function.
Expand Down Expand Up @@ -457,10 +457,13 @@ static void emitIndirectResultParameters(SILGenFunction &gen, Type resultType,
auto arg =
new (gen.SGM.M) SILArgument(gen.F.begin(), resultTI.getLoweredType(), var);
(void) arg;


}

unsigned SILGenFunction::emitProlog(ArrayRef<ParameterList*> paramLists,
Type resultType, DeclContext *DC) {
unsigned SILGenFunction::emitProlog(ArrayRef<ParameterList *> paramLists,
Type resultType, DeclContext *DC,
bool throws) {
// Create the indirect result parameters.
emitIndirectResultParameters(*this, resultType, DC);

Expand All @@ -473,6 +476,21 @@ unsigned SILGenFunction::emitProlog(ArrayRef<ParameterList*> paramLists,
for (auto &param : *paramList)
emitter.emitParam(param);
}
return emitter.getNumArgs();

// Record the ArgNo of the artificial $error inout argument.
unsigned ArgNo = emitter.getNumArgs();
if (throws) {
RegularLocation Loc{SourceLoc()};
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC))
Loc = AFD->getThrowsLoc();
else if (auto *ACE = dyn_cast<AbstractClosureExpr>(DC))
Loc = ACE->getLoc();
auto NativeErrorTy = SILType::getExceptionType(getASTContext());
ManagedValue Undef = emitUndef(Loc, NativeErrorTy);
B.createDebugValue(Loc, Undef.getValue(),
{"$error", /*Constant*/ false, ++ArgNo});
}

return ArgNo;
}

2 changes: 1 addition & 1 deletion test/DebugInfo/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func simple(_ placeholder: Int64) throws -> () {
// CHECK: define {{.*}}void @_TF6Errors6simpleFzVs5Int64T_(i64, %swift.refcounted*, %swift.error**)
// CHECK: call void @llvm.dbg.declare
// CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[ERROR:[0-9]+]], metadata ![[DEREF:[0-9]+]])
// CHECK: ![[ERROR]] = !DILocalVariable(name: "$error", arg: 3,
// CHECK: ![[ERROR]] = !DILocalVariable(name: "$error", arg: 2,
// CHECK-SAME: type: ![[ERRTY:.*]], flags: DIFlagArtificial)
// CHECK: ![[ERRTY]] = !DICompositeType({{.*}}identifier: "_TtPs5Error_"
// CHECK: ![[DEREF]] = !DIExpression(DW_OP_deref)
Expand Down
6 changes: 4 additions & 2 deletions test/DebugInfo/generic_enum_closure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ struct CErrorOr<T>
// CHECK-NOT: define
// This is a SIL-level debug_value_addr instruction.
// CHECK: call void @llvm.dbg.value({{.*}}, metadata ![[SELF:.*]], metadata !{{[0-9]+}})
// CHECK-DAG: ![[T1:.*]] = !DICompositeType({{.*}}identifier: "_TtGV20generic_enum_closure8CErrorOrQq_S0__"
// CHECK-DAG: ![[SELF]] = !DILocalVariable(name: "self", arg:{{.*}} type: ![[T1]]
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope
// CHECK-SAME: type: ![[T1:.*]])
// CHECK: ![[T1]] = !DICompositeType(
// CHECK-SAME: identifier: "_TtGV20generic_enum_closure8CErrorOrQq_S0__"
value = .none
}
func isError() -> Bool {
Expand Down
5 changes: 3 additions & 2 deletions test/DebugInfo/self.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ public func f() {
// CHECK: define {{.*}} @_TFV4self11stuffStructCfT_S0_(
// CHECK-NEXT: entry:
// CHECK-NEXT: %[[ALLOCA:.*]] = alloca %V4self11stuffStruct, align {{(4|8)}}
// CHECK: call void @llvm.dbg.declare(metadata %V4self11stuffStruct* %[[ALLOCA]], metadata ![[SELF:.*]], metadata !{{[0-9]+}}), !db
// CHECK: call void @llvm.dbg.declare(metadata %V4self11stuffStruct* %[[ALLOCA]],
// CHECK-SAME: metadata ![[SELF:.*]], metadata !{{[0-9]+}}), !dbg
// CHECK: ![[STUFFSTRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "stuffStruct",{{.*}}identifier
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", arg: 1,
// CHECK: ![[SELF]] = !DILocalVariable(name: "self", scope
// CHECK-SAME: type: ![[STUFFSTRUCT]]

7 changes: 5 additions & 2 deletions test/SILGen/errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,9 @@ func feedCat() throws -> Int {
}
}
// CHECK-LABEL: sil hidden @_TF6errors7feedCatFzT_Si : $@convention(thin) () -> (Int, @error Error)
// CHECK: %0 = function_ref @_TF6errors13preferredFoodFzT_OS_7CatFood : $@convention(thin) () -> (CatFood, @error Error)
// CHECK: try_apply %0() : $@convention(thin) () -> (CatFood, @error Error), normal bb1, error bb5
// CHECK: debug_value undef : $Error, var, name "$error", argno 1
// CHECK: %1 = function_ref @_TF6errors13preferredFoodFzT_OS_7CatFood : $@convention(thin) () -> (CatFood, @error Error)
// CHECK: try_apply %1() : $@convention(thin) () -> (CatFood, @error Error), normal bb1, error bb5
// CHECK: bb1([[VAL:%.*]] : $CatFood):
// CHECK: switch_enum [[VAL]] : $CatFood, case #CatFood.Canned!enumelt: bb2, case #CatFood.Dry!enumelt: bb3
// CHECK: bb5([[ERROR:%.*]] : $Error)
Expand All @@ -366,6 +367,7 @@ func getHungryCat(_ food: CatFood) throws -> Cat {
// errors.getHungryCat throws (errors.CatFood) -> errors.Cat
// CHECK-LABEL: sil hidden @_TF6errors12getHungryCatFzOS_7CatFoodCS_3Cat : $@convention(thin) (CatFood) -> (@owned Cat, @error Error)
// CHECK: bb0(%0 : $CatFood):
// CHECK: debug_value undef : $Error, var, name "$error", argno 2
// CHECK: switch_enum %0 : $CatFood, case #CatFood.Canned!enumelt: bb1, case #CatFood.Dry!enumelt: bb3
// CHECK: bb1:
// CHECK: [[FN:%.*]] = function_ref @_TF6errors10make_a_catFzT_CS_3Cat : $@convention(thin) () -> (@owned Cat, @error Error)
Expand All @@ -385,6 +387,7 @@ func test_variadic(_ cat: Cat) throws {
try take_many_cats(make_a_cat(), cat, make_a_cat(), make_a_cat())
}
// CHECK-LABEL: sil hidden @_TF6errors13test_variadicFzCS_3CatT_
// CHECK: debug_value undef : $Error, var, name "$error", argno 2
// CHECK: [[TAKE_FN:%.*]] = function_ref @_TF6errors14take_many_catsFztGSaCS_3Cat__T_ : $@convention(thin) (@owned Array<Cat>) -> @error Error
// CHECK: [[N:%.*]] = integer_literal $Builtin.Word, 4
// CHECK: [[T0:%.*]] = function_ref @_TFs27_allocateUninitializedArray
Expand Down
6 changes: 4 additions & 2 deletions test/SILGen/foreign_errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,15 @@ func testArgs() throws {
try ErrorProne.consume(nil)
}
// CHECK: sil hidden @_TF14foreign_errors8testArgsFzT_T_ : $@convention(thin) () -> @error Error
// CHECK: class_method [volatile] %0 : $@thick ErrorProne.Type, #ErrorProne.consume!1.foreign : (ErrorProne.Type) -> (Any!) throws -> () , $@convention(objc_method) (Optional<AnyObject>, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> ObjCBool
// CHECK: debug_value undef : $Error, var, name "$error", argno 1
// CHECK: class_method [volatile] %1 : $@thick ErrorProne.Type, #ErrorProne.consume!1.foreign : (ErrorProne.Type) -> (Any!) throws -> () , $@convention(objc_method) (Optional<AnyObject>, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> ObjCBool

func testBridgedResult() throws {
let array = try ErrorProne.collection(withCount: 0)
}
// CHECK: sil hidden @_TF14foreign_errors17testBridgedResultFzT_T_ : $@convention(thin) () -> @error Error {
// CHECK: class_method [volatile] %0 : $@thick ErrorProne.Type, #ErrorProne.collection!1.foreign : (ErrorProne.Type) -> (Int) throws -> [Any] , $@convention(objc_method) (Int, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> @autoreleased Optional<NSArray>
// CHECK: debug_value undef : $Error, var, name "$error", argno 1
// CHECK: class_method [volatile] %1 : $@thick ErrorProne.Type, #ErrorProne.collection!1.foreign : (ErrorProne.Type) -> (Int) throws -> [Any] , $@convention(objc_method) (Int, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @objc_metatype ErrorProne.Type) -> @autoreleased Optional<NSArray>

// rdar://20861374
// Clear out the self box before delegating.
Expand Down
7 changes: 4 additions & 3 deletions test/SILOptimizer/throw_inline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ public func foo() throws -> Int32 {
}

// CHECK-LABEL: _TF12throw_inline3foo
// CHECK: %0 = integer_literal $Builtin.Int32, 999
// CHECK: %1 = struct $Int32 (%0 : $Builtin.Int32)
// CHECK: return %1 : $Int32
// CHECK: debug_value undef : $Error, var, name "$error", argno 1
// CHECK: %1 = integer_literal $Builtin.Int32, 999
// CHECK: %2 = struct $Int32 (%1 : $Builtin.Int32)
// CHECK: return %2 : $Int32
func bar() throws -> Int32 {
return try foo()
}
Expand Down