// RUN: %target-swift-frontend -disable-debugger-shadow-copies -primary-file %s -emit-ir -g -o - | %FileCheck %s sil_stage canonical import Builtin import Swift struct MyStruct { @_hasStorage var x: Int64 { get set } @_hasStorage var y: Int64 { get set } init(x: Int64, y: Int64) } sil_scope 1 { loc "file.swift":1:6 parent @test_transform_const : $@convention(thin) () -> () } sil_scope 2 { loc "file.swift":5:6 parent @test_transform_add : $@convention(thin) (Builtin.Int64) -> () } sil_scope 3 { loc "file.swift":10:6 parent @test_transform_multi : $@convention(thin) (Builtin.Int64) -> () } sil_scope 4 { loc "file.swift":15:6 parent @test_transform_struct_extract : $@convention(thin) (Int64) -> () } sil_scope 5 { loc "file.swift":20:6 parent @test_transform_tuple_extract : $@convention(thin) (Int64) -> () } // CHECK-LABEL: define {{.*}} @test_transform_const sil @test_transform_const : $@convention(thin) () -> () { bb0: // The transform block produces a constant i64 42 that is used in #dbg_value. // CHECK: #dbg_value(i64 42, ![[VAR1:[0-9]+]] debug_value undef : $Builtin.Int64, let, name "x", type $Int64, expr op_fragment:#Int64._value, transform { bb0: %0 = integer_literal $Builtin.Int64, 42 return %0 : $Builtin.Int64 }, loc "file.swift":2:3, scope 1 %r = tuple () return %r : $(), loc "file.swift":3:3, scope 1 } // CHECK-LABEL: define {{.*}} @test_transform_add sil @test_transform_add : $@convention(thin) (Builtin.Int64) -> () { bb0(%arg : $Builtin.Int64): // The transform block adds 10 to the argument. The add instruction should be // salvaged into a DWARF expression and erased from the IR. // CHECK-NOT: add {{.*}} 10 // CHECK: #dbg_value(i64 %0, ![[VAR2:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 10, DW_OP_stack_value) debug_value %arg : $Builtin.Int64, let, name "y", type $Int64, expr op_fragment:#Int64._value, transform { bb0(%0 : $Builtin.Int64): %1 = integer_literal $Builtin.Int64, 10 %2 = builtin "add_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int64 return %2 : $Builtin.Int64 }, loc "file.swift":6:3, scope 2 %r = tuple () return %r : $(), loc "file.swift":7:3, scope 2 } // CHECK-LABEL: define {{.*}} @test_transform_multi sil @test_transform_multi : $@convention(thin) (Builtin.Int64) -> () { bb0(%arg : $Builtin.Int64): // Multiple arithmetic instructions that all get salvaged and erased. // `(x + 10) * 2 + 3`: three real LLVM instructions, all must be erased. // CHECK-NOT: add // CHECK-NOT: mul // CHECK: #dbg_value(i64 %0, ![[VAR3:[0-9]+]], !DIExpression(DW_OP_plus_uconst, 10, DW_OP_constu, 2, DW_OP_mul, DW_OP_plus_uconst, 3, DW_OP_stack_value) debug_value %arg : $Builtin.Int64, let, name "z", type $Int64, expr op_fragment:#Int64._value, transform { bb0(%0 : $Builtin.Int64): %1 = integer_literal $Builtin.Int64, 10 %2 = builtin "add_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int64 %3 = integer_literal $Builtin.Int64, 2 %4 = builtin "mul_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int64 %5 = integer_literal $Builtin.Int64, 3 %6 = builtin "add_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int64 return %6 : $Builtin.Int64 }, loc "file.swift":11:3, scope 3 %r = tuple () return %r : $(), loc "file.swift":12:3, scope 3 } // CHECK-LABEL: define {{.*}} @test_transform_struct_extract sil @test_transform_struct_extract : $@convention(thin) (Int64) -> () { bb0(%arg : $Int64): // struct + struct_extract of the same field should cancel out. // CHECK: #dbg_value(i64 %0, ![[VAR4:[0-9]+]] debug_value %arg : $Int64, let, name "x", transform { bb0(%0 : $Int64): %1 = struct $MyStruct (%0 : $Int64, undef : $Int64) %2 = struct_extract %1 : $MyStruct, #MyStruct.x return %2 : $Int64 }, loc "file.swift":16:3, scope 4 // struct + struct_extract of a different field should yield undef. // CHECK: #dbg_value(i64 undef, ![[VAR5:[0-9]+]] debug_value %arg : $Int64, let, name "y", transform { bb0(%0 : $Int64): %1 = struct $MyStruct (%0 : $Int64, undef : $Int64) %2 = struct_extract %1 : $MyStruct, #MyStruct.y return %2 : $Int64 }, loc "file.swift":18:3, scope 4 %r = tuple () return %r : $(), loc "file.swift":17:3, scope 4 } // CHECK-LABEL: define {{.*}} @test_transform_tuple_extract sil @test_transform_tuple_extract : $@convention(thin) (Int64) -> () { bb0(%arg : $Int64): // tuple + tuple_extract of the same element should cancel out. // CHECK: #dbg_value(i64 %0, ![[VAR6:[0-9]+]] debug_value %arg : $Int64, let, name "x", transform { bb0(%0 : $Int64): %1 = tuple (%0 : $Int64, undef : $Int64) %2 = tuple_extract %1 : $(Int64, Int64), 0 return %2 : $Int64 }, loc "file.swift":21:3, scope 5 // tuple + tuple_extract of the undef element should yield undef. // CHECK: #dbg_value(i64 undef, ![[VAR7:[0-9]+]] debug_value %arg : $Int64, let, name "y", transform { bb0(%0 : $Int64): %1 = tuple (%0 : $Int64, undef : $Int64) %2 = tuple_extract %1 : $(Int64, Int64), 1 return %2 : $Int64 }, loc "file.swift":23:3, scope 5 %r = tuple () return %r : $(), loc "file.swift":24:3, scope 5 } // CHECK-DAG: ![[VAR1]] = !DILocalVariable(name: "x" // CHECK-DAG: ![[VAR2]] = !DILocalVariable(name: "y" // CHECK-DAG: ![[VAR3]] = !DILocalVariable(name: "z" // CHECK-DAG: ![[VAR4]] = !DILocalVariable(name: "x" // CHECK-DAG: ![[VAR5]] = !DILocalVariable(name: "y" // CHECK-DAG: ![[VAR6]] = !DILocalVariable(name: "x" // CHECK-DAG: ![[VAR7]] = !DILocalVariable(name: "y"