mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
At -Onone, we may opt to extend the liverange of a value by inserting
fake uses of the value in blocks which postdominate its def. This keeps
values available throughout the entirety of a function when stepping
through it in a debugger.
This patch makes it so that we also insert a fake use at the start of a
value's lifetime. This forces early materialization of the value, i.e it
becomes available for inspection in a debugger as soon as it's defined.
This is useful when a value has no uses except fake uses. In such cases,
ISel may (correctly!) decide to materialize the value at the end of its
scope. This is really unintuitive and unhelpful for users, because you
need to be done stepping through the value's scope before you can
inspect it.
For the same reasons, forcing early materialization is also useful when
a value *does* have uses. Consider:
let d = ...
print("Here is the value of d: \(d)")
Without early materialization, if you set a breakpoint on the line
containing the print, you would not be able to inspect "d". That's
because "d" would be materialized right before string interpolation
happens, which is *after* the breakpoint PC.
rdar://38465084
64 lines
2.1 KiB
Swift
64 lines
2.1 KiB
Swift
// RUN: %target-swift-frontend %s -g -emit-ir -o - | %FileCheck %s
|
|
|
|
// REQUIRES: CPU=x86_64
|
|
//
|
|
// We require x86_64 to make the test easier to read. Without this,
|
|
// writing check lines that ensure our asm gadgets match up with the
|
|
// right values is painfully hard to do.
|
|
|
|
func use<T>(_ x: T) {}
|
|
|
|
func getInt32() -> Int32 { return -1 }
|
|
|
|
// CHECK-LABEL: define {{.*}}rangeExtension
|
|
public func rangeExtension(_ b: Bool) {
|
|
let i = getInt32()
|
|
// CHECK: [[I:%.*]] = call swiftcc i32 @"{{.*}}getInt32
|
|
// CHECK-NEXT: [[I_ZEXT:%.*]] = zext i32 [[I]] to i64
|
|
// CHECK-NEXT: call void asm sideeffect "", "r"(i64 [[I_ZEXT]])
|
|
// CHECK-NEXT: llvm.dbg.value(metadata i32 [[I]], metadata [[MD_I:!.*]], metadata
|
|
|
|
use(i)
|
|
|
|
// CHECK: br i1
|
|
|
|
if b {
|
|
// CHECK: llvm.dbg.value(metadata i32 [[I]], metadata [[MD_I]]
|
|
|
|
let j = getInt32()
|
|
// CHECK: [[J:%.*]] = call swiftcc i32 @"{{.*}}getInt32
|
|
// CHECK-NEXT: [[J_ZEXT:%.*]] = zext i32 [[J]] to i64
|
|
// CHECK-NEXT: call void asm sideeffect "", "r"(i64 [[J_ZEXT]])
|
|
// CHECK: llvm.dbg.value(metadata i32 [[J]], metadata [[MD_J:!.*]], metadata
|
|
|
|
use(j)
|
|
// CHECK: call swiftcc void @"{{.*}}use
|
|
|
|
// CHECK: [[I_ZEXT:%.*]] = zext i32 [[I]] to i64
|
|
// CHECK-NEXT: call void asm sideeffect "", "r"(i64 [[I_ZEXT]])
|
|
// CHECK-NEXT: [[J_ZEXT:%.*]] = zext i32 [[J]] to i64
|
|
// CHECK-NEXT: call void asm sideeffect "", "r"(i64 [[J_ZEXT]])
|
|
|
|
// CHECK: br label
|
|
}
|
|
|
|
// CHECK-NOT: llvm.dbg.value(metadata i32 [[J]]
|
|
// CHECK: llvm.dbg.value(metadata i32 [[I]]
|
|
|
|
let z = getInt32()
|
|
// CHECK: [[Z:%.*]] = call swiftcc i32 @"{{.*}}getInt32
|
|
// CHECK: llvm.dbg.value(metadata i32 [[Z]], metadata [[MD_Z:!.*]], metadata
|
|
|
|
use(z)
|
|
// CHECK: call swiftcc void @"{{.*}}use
|
|
|
|
// CHECK: [[I_ZEXT:%.*]] = zext i32 [[I]] to i64
|
|
// CHECK-NEXT: call void asm sideeffect "", "r"(i64 [[I_ZEXT]])
|
|
// CHECK-NEXT: [[Z_ZEXT:%.*]] = zext i32 [[Z]] to i64
|
|
// CHECK-NEXT: call void asm sideeffect "", "r"(i64 [[Z_ZEXT]])
|
|
}
|
|
|
|
// CHECK-DAG: [[MD_I]] = !DILocalVariable(name: "i"
|
|
// CHECK-DAG: [[MD_J]] = !DILocalVariable(name: "j"
|
|
// CHECK-DAG: [[MD_Z]] = !DILocalVariable(name: "z"
|