Skip to content

Commit cef6ef9

Browse files
committed
SIL: add a debug_step instruction
This instruction can be inserted by Onone optimizations as a replacement for deleted instructions to ensure that it's possible to single step on its location.
1 parent e92f27c commit cef6ef9

File tree

22 files changed

+110
-3
lines changed

22 files changed

+110
-3
lines changed

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ public struct Builder {
134134
return notifyNew(SILBuilder_createDestroyValue(bridged, operand.bridged).getAs(DestroyValueInst.self))
135135
}
136136

137+
@discardableResult
138+
public func createDebugStep() -> DebugStepInst {
139+
return notifyNew(SILBuilder_createDebugStep(bridged).getAs(DebugStepInst.self))
140+
}
141+
137142
@discardableResult
138143
public func createApply(
139144
function: Value,

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ final public class FixLifetimeInst : Instruction, UnaryInstruction {}
291291

292292
final public class DebugValueInst : Instruction, UnaryInstruction {}
293293

294+
final public class DebugStepInst : Instruction {}
295+
294296
final public class UnconditionalCheckedCastAddrInst : Instruction {
295297
public override var mayTrap: Bool { true }
296298
}

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public func registerSILClasses() {
5050
register(MarkUninitializedInst.self)
5151
register(FixLifetimeInst.self)
5252
register(DebugValueInst.self)
53+
register(DebugStepInst.self)
5354
register(UnconditionalCheckedCastAddrInst.self)
5455
register(SetDeallocatingInst.self)
5556
register(EndApplyInst.self)

docs/SIL.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3952,6 +3952,20 @@ SIL DIExpression can have elements with various types, like AST nodes or strings
39523952

39533953
The ``[trace]`` flag is available for compiler unit testing. It is not produced during normal compilation. It is used combination with internal logging and optimization controls to select specific values to trace or to transform. For example, liveness analysis combines all "traced" values into a single live range with multiple definitions. This exposes corner cases that cannot be represented by passing valid SIL through the pipeline.
39543954

3955+
debug_step
3956+
``````````
3957+
3958+
::
3959+
3960+
sil-instruction ::= debug_step
3961+
3962+
debug_step
3963+
3964+
This instruction is inserted by Onone optimizations as a replacement for deleted instructions to
3965+
ensure that it's possible to set a breakpoint on its location.
3966+
3967+
It is code-generated to a NOP instruction.
3968+
39553969
Testing
39563970
~~~~~~~
39573971

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ BridgedInstruction SILBuilder_createCopyAddr(BridgedBuilder builder,
465465
SwiftInt takeSource, SwiftInt initializeDest);
466466
BridgedInstruction SILBuilder_createDestroyValue(BridgedBuilder builder,
467467
BridgedValue op);
468+
BridgedInstruction SILBuilder_createDebugStep(BridgedBuilder builder);
468469
BridgedInstruction SILBuilder_createApply(BridgedBuilder builder,
469470
BridgedValue function, swift::SubstitutionMap subMap,
470471
BridgedValueArray arguments, bool isNonThrowing, bool isNonAsync,

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,10 @@ class SILBuilder {
985985
bool wasMoved = false,
986986
bool trace = false);
987987

988+
DebugStepInst *createDebugStep(SILLocation Loc) {
989+
return insert(new (getModule()) DebugStepInst(getSILDebugLocation(Loc)));
990+
}
991+
988992
/// Create a debug_value according to the type of \p src
989993
SILInstruction *emitDebugDescription(SILLocation Loc, SILValue src,
990994
SILDebugVariable Var) {

include/swift/SIL/SILCloner.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,11 @@ SILCloner<ImplClass>::visitDebugValueInst(DebugValueInst *Inst) {
13151315
remapDebugVarInfo(DebugVarCarryingInst(NewInst));
13161316
recordClonedInstruction(Inst, NewInst);
13171317
}
1318+
template<typename ImplClass>
1319+
void
1320+
SILCloner<ImplClass>::visitDebugStepInst(DebugStepInst *Inst) {
1321+
recordClonedInstruction(Inst, getBuilder().createDebugStep(Inst->getLoc()));
1322+
}
13181323

13191324
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \
13201325
template <typename ImplClass> \

include/swift/SIL/SILInstruction.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4929,6 +4929,19 @@ class MarkFunctionEscapeInst final
49294929
}
49304930
};
49314931

4932+
/// This instruction is inserted by Onone optimizations as a replacement for deleted
4933+
/// instructions to ensure that it's possible to set a breakpoint on its location.
4934+
class DebugStepInst final
4935+
: public InstructionBase<SILInstructionKind::DebugStepInst, NonValueInstruction> {
4936+
friend SILBuilder;
4937+
4938+
DebugStepInst(SILDebugLocation debugLoc) : InstructionBase(debugLoc) {}
4939+
4940+
public:
4941+
ArrayRef<Operand> getAllOperands() const { return {}; }
4942+
MutableArrayRef<Operand> getAllOperands() { return {}; }
4943+
};
4944+
49324945
/// Define the start or update to a symbolic variable value (for loadable
49334946
/// types).
49344947
class DebugValueInst final

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,8 @@ NON_VALUE_INST(MarkFunctionEscapeInst, mark_function_escape,
789789
SILInstruction, None, DoesNotRelease)
790790
NON_VALUE_INST(DebugValueInst, debug_value,
791791
SILInstruction, None, DoesNotRelease)
792+
NON_VALUE_INST(DebugStepInst, debug_step,
793+
SILInstruction, MayHaveSideEffects, DoesNotRelease)
792794
NON_VALUE_INST(TestSpecificationInst, test_specification,
793795
SILInstruction, None, DoesNotRelease)
794796
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \

lib/IRGen/IRGenSIL.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,7 @@ class IRGenSILFunction :
11941194
llvm_unreachable("unimplemented");
11951195
}
11961196
void visitDebugValueInst(DebugValueInst *i);
1197+
void visitDebugStepInst(DebugStepInst *i);
11971198
void visitRetainValueInst(RetainValueInst *i);
11981199
void visitRetainValueAddrInst(RetainValueAddrInst *i);
11991200
void visitCopyValueInst(CopyValueInst *i);
@@ -5113,6 +5114,17 @@ void IRGenSILFunction::visitDebugValueInst(DebugValueInst *i) {
51135114
AddrDbgInstrKind(i->getWasMoved()));
51145115
}
51155116

5117+
void IRGenSILFunction::visitDebugStepInst(DebugStepInst *i) {
5118+
// Unfortunately there is no LLVM-equivalent of a debug_step instruction.
5119+
// Also LLVM doesn't provide a plain NOP instruction.
5120+
// Therefore we have to solve this with inline assembly.
5121+
// Strictly speaking, this is not architecture independent. But there are
5122+
// probably few assembly languages which don't use "nop" for nop instructions.
5123+
auto *AsmFnTy = llvm::FunctionType::get(IGM.VoidTy, {}, false);
5124+
auto *InlineAsm = llvm::InlineAsm::get(AsmFnTy, "nop", "", true);
5125+
Builder.CreateAsmCall(InlineAsm, {});
5126+
}
5127+
51165128
void IRGenSILFunction::visitFixLifetimeInst(swift::FixLifetimeInst *i) {
51175129
if (i->getOperand()->getType().isAddress()) {
51185130
// Just pass in the address to fix lifetime if we have one. We will not do

0 commit comments

Comments
 (0)