[RFC] SIL syntax for debug information Part 1: Variables


(Adrian Prantl) #1

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
  return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
  debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
  return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
  debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
  return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

  sil-instruction ::= 'alloc_stack' sil-type dbg-var
  sil-instruction ::= 'alloc_stack' sil-type dbg-var
  sil-instruction ::= debug_value sil-operand dbg-var
  sil-instruction ::= debug_value_addr sil-operand dbg-var
  dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
  var-attr ::= ‘name:’ string-literal
  var-attr ::= ’type:’ string-literal
  var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
   Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
   Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
   Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

-- adrian


(Joe Groff) #2

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.
- Since these are core parts of the instruction, I would say they need no decoration at all; they should just be part of the instruction syntax:

debug_value %0 : $Int, name "x", type $Int, argno 1

-Joe

···

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
  Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
  Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
  Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.


(Adrian Prantl) #3

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

Good point. Is it safe to assume that all types representable in textual SIL? I’m slightly worried that a SIL pass might introduce a type (e.g., a generic function specialization) for which we don’t have any Swift syntax. Thinking about it though — even if there is no syntax, we would probably want to create one, so the type can be used in the debugger and REPL.

- Since these are core parts of the instruction, I would say they need no decoration at all; they should just be part of the instruction syntax:

debug_value %0 : $Int, name "x", type $Int, argno 1

sil-instruction ::= 'alloc_stack' sil-type (‘,' debugvar-attr)*
sil-instruction ::= 'alloc_stack' sil-type (‘,’ debugvar-attr)*
sil-instruction ::= debug_value sil-operand (‘,' debugvar-attr)*
sil-instruction ::= debug_value_addr sil-operand (‘,' debugvar-attr)*
debugvar-attr ::= ‘name’ string-literal
debugvar-attr ::= ’type’ type // only needed where AST type ≠ SIL type
debugvar-attr ::= ‘argno’ integer-literal

Works for me. Thanks for the feedback,
Adrian

···

On Dec 10, 2015, at 8:31 AM, Joe Groff <jgroff@apple.com> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:


(John McCall) #4

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

John.

···

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.


(Adrian Prantl) #5

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
  func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
  debug_value_addr %1 : $*T, let, name "x", argno 1
  copy_addr [take] %1 to [initialization] %0 : $*T
  %4 = tuple ()
  return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.
Another option is to explicitly call out the DeclContext by adding a sil-decl-ref attribute, like this:

debug_value_addr %1 : $*T, let, name "x", argno 1, declctx #id!1

But it looks like sil-decl-refs also aren’t expressive enough to distinguish between foo() / foo(x:Int) / foo<T>(x:T).

Am I missing something obvious?
-- adrian

···

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:


(Joe Groff) #6

Don't SILFunctions already reference a context ValueDecl for debug purposes?

-Joe

···

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.
Another option is to explicitly call out the DeclContext by adding a sil-decl-ref attribute, like this:

debug_value_addr %1 : $*T, let, name "x", argno 1, declctx #id!1

But it looks like sil-decl-refs also aren’t expressive enough to distinguish between foo() / foo(x:Int) / foo<T>(x:T).

Am I missing something obvious?


(John McCall) #7

Well, right now the in-memory representation uses a single DeclContext for the entire SILFunction. If that choice makes sense — and I’m willing to accept that it does — then it seems to me that the assembly representation should be consistent with that choice. That is, you should find a way to write the DeclContext for the entire function in the parsed representation instead of writing it out for individual instructions.

Now, for the specific case of archetypes and mangling, the answer is probably that you don’t really need a DeclContext, you need a GenericParamList.

John.

···

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.


(Adrian Prantl) #8

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.
Another option is to explicitly call out the DeclContext by adding a sil-decl-ref attribute, like this:

debug_value_addr %1 : $*T, let, name "x", argno 1, declctx #id!1

But it looks like sil-decl-refs also aren’t expressive enough to distinguish between foo() / foo(x:Int) / foo<T>(x:T).

Am I missing something obvious?

Don't SILFunctions already reference a context ValueDecl for debug purposes?

If you’re refering to SILFunction::getDeclContext() this field is only populated by the regular SILGen path. ParseSIL does not (yet) do this. I ran into the above problem while trying to set the DeclContext of SILFunctions that are created by ParseSIL.cpp.

-- adrian

···

On Dec 15, 2015, at 2:27 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

-Joe


(Adrian Prantl) #9

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.

Well, right now the in-memory representation uses a single DeclContext for the entire SILFunction. If that choice makes sense — and I’m willing to accept that it does — then it seems to me that the assembly representation should be consistent with that choice. That is, you should find a way to write the DeclContext for the entire function in the parsed representation instead of writing it out for individual instructions.

The only complication is that a debug_value that was inlined from another function will need to refer to that function as its DeclContext. Once we have a syntax for locations and inline information (this is next up on my list) we could determine an inlined instruction’s context via the location (which will point to the original function) and don’t need to store it in the instruction.
So, yes, attaching the DeclContext to a function would be totally adequate :slight_smile:

Now, for the specific case of archetypes and mangling, the answer is probably that you don’t really need a DeclContext, you need a GenericParamList.

That would be great, as the GenericParamList is already stored in the SILFunction. Alas, for debug info (only) the mangling for an archetype is

  qualified-archetype ::= 'Qq' index context

and contains the DeclContext.

It looks like both for locations DeclContexts it would be useful if there was a way to uniquely refer to an earlier ValueDecl in the same SIL file. I’m unsure what the best solution for this would be syntax-wise.

thanks,
adrian

···

On Dec 15, 2015, at 2:35 PM, John McCall <rjmccall@apple.com> wrote:

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:


(Joe Groff) #10

We could add some syntax to the sil function syntax to reference the debug DeclContext. I wouldn't try to demangle the name to guess what it's supposed to be.

-Joe

···

On Dec 15, 2015, at 2:34 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 15, 2015, at 2:27 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.
Another option is to explicitly call out the DeclContext by adding a sil-decl-ref attribute, like this:

debug_value_addr %1 : $*T, let, name "x", argno 1, declctx #id!1

But it looks like sil-decl-refs also aren’t expressive enough to distinguish between foo() / foo(x:Int) / foo<T>(x:T).

Am I missing something obvious?

Don't SILFunctions already reference a context ValueDecl for debug purposes?

If you’re refering to SILFunction::getDeclContext() this field is only populated by the regular SILGen path. ParseSIL does not (yet) do this. I ran into the above problem while trying to set the DeclContext of SILFunctions that are created by ParseSIL.cpp.


(John McCall) #11

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.

Well, right now the in-memory representation uses a single DeclContext for the entire SILFunction. If that choice makes sense — and I’m willing to accept that it does — then it seems to me that the assembly representation should be consistent with that choice. That is, you should find a way to write the DeclContext for the entire function in the parsed representation instead of writing it out for individual instructions.

The only complication is that a debug_value that was inlined from another function will need to refer to that function as its DeclContext. Once we have a syntax for locations and inline information (this is next up on my list) we could determine an inlined instruction’s context via the location (which will point to the original function) and don’t need to store it in the instruction.
So, yes, attaching the DeclContext to a function would be totally adequate :slight_smile:

Now, for the specific case of archetypes and mangling, the answer is probably that you don’t really need a DeclContext, you need a GenericParamList.

That would be great, as the GenericParamList is already stored in the SILFunction. Alas, for debug info (only) the mangling for an archetype is

qualified-archetype ::= 'Qq' index context

and contains the DeclContext.

Well, as a reminder, you made this mangling up for debug-info’s purposes, so it’s up to you. :slight_smile:

It looks like both for locations DeclContexts it would be useful if there was a way to uniquely refer to an earlier ValueDecl in the same SIL file. I’m unsure what the best solution for this would be syntax-wise.

John.

···

On Dec 15, 2015, at 3:01 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 15, 2015, at 2:35 PM, John McCall <rjmccall@apple.com> wrote:

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:


(Adrian Prantl) #12

Here are a couple of horrible ideas how this could be done:

1. Extend sil-decl-ref to allow specifying a type:
   Grammar:
       sil-function ::= 'sil' sil-linkage? sil-function-name ':' sil-type
                        ‘declcontext’ sil-decl-ref
                        '{' sil-basic-block+ '}'
   Example:

   // Decl
   func foo<T>(i : Int) -> T

   // SIL function + DeclContextRef
   sil @_TF4test3foo... : $@convention(thin) <T> (@out T, @in T) -> () declcontext test.foo$<T>(Int) -> (T) {

2. Extend ValueDecls in .sil files with a unique id
   Example:

   // Decl + ID
   func foo() #1

   // SIL function + DeclContextRef
   sil @_TF4test3foo... : $... declcontext #1 {

3. Extend ValueDecls with a unique id that happens to be its mangled/silgen name
   Example:

   // Decl + ID
   @_silgen_name("@_TF4test3foo...”) func foo()
   // SIL function + DeclContextRef
   sil @_TF4test3foo... : $... declcontext @_TF4test3foo... {

I personally lean towards something along the lines of option 1. What do you think?

-- adrian

···

On Dec 15, 2015, at 2:37 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 15, 2015, at 2:34 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 15, 2015, at 2:27 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.
Another option is to explicitly call out the DeclContext by adding a sil-decl-ref attribute, like this:

debug_value_addr %1 : $*T, let, name "x", argno 1, declctx #id!1

But it looks like sil-decl-refs also aren’t expressive enough to distinguish between foo() / foo(x:Int) / foo<T>(x:T).

Am I missing something obvious?

Don't SILFunctions already reference a context ValueDecl for debug purposes?

If you’re refering to SILFunction::getDeclContext() this field is only populated by the regular SILGen path. ParseSIL does not (yet) do this. I ran into the above problem while trying to set the DeclContext of SILFunctions that are created by ParseSIL.cpp.

We could add some syntax to the sil function syntax to reference the debug DeclContext. I wouldn't try to demangle the name to guess what it's supposed to be.


(Joe Groff) #13

Yeah, option 1 seems reasonable to me. I might give it attribute-like spelling, though, to help bracket it and keep it separate from the real name and declaration:

sil [debug_decl_context test.foo : <T> (T) -> ()] @_Tfoo : $... {
}

-Joe

···

On Dec 15, 2015, at 4:30 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 15, 2015, at 2:37 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 15, 2015, at 2:34 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 15, 2015, at 2:27 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 15, 2015, at 1:25 PM, Adrian Prantl <aprantl@apple.com> wrote:

On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall@apple.com> wrote:

On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev@swift.org> wrote:

In order to write textual SIL -> SIL testcases that exercise the handling of debug information by SIL passes, we need to make a couple of additions to the textual SIL language. In memory, the debug information attached to SIL instructions references information from the AST. If we want to create debug info from parsing a textual .sil file, these bits need to be made explicit.

Let me illustrate this with an example. The function

func foo(x : Int) -> Int {
return bar(x)
}

is compiled to SIL as

// main.foo (Swift.Int) -> Swift.Int
sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
// %0 // users: %1, %2, %4
bb0(%0 : $Int):
debug_value %0 : $Int // let x, argno: 1 // id: %1 line:1:10:in_prologue
return %4 : $Int // id: %5 line:2:3:return
}

Note that there is a bunch of information available in comments that will be lost once we parse that textual SIL again. I’d like to add syntax to SIL for the information in the comments. This proposal deals with lifting the debug variable information (the first comment) into actual SIL syntax. A similar proposal for locations will be coming soon.
With the proposed syntax, this could like like:

sil hidden @_TF4main3fooFSiSi : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
debug_value %0 : $Int, !dbg_var(name: "x", type: "_TTSi", argno: 1)
return %4 : $Int
}

More formally, debug variable info may be attached to debug_value, debug_value_addr, alloc_box, and alloc_stack instructions.

sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= 'alloc_stack' sil-type dbg-var
sil-instruction ::= debug_value sil-operand dbg-var
sil-instruction ::= debug_value_addr sil-operand dbg-var
dbg-var ::= ‘!dbg_var’ ‘(‘ var-attr (',' var-attr)*) ‘)'
var-attr ::= ‘name:’ string-literal
var-attr ::= ’type:’ string-literal
var-attr ::= ‘argno:’ integer-literal

This syntax for `dbg-var` is borrowed straight from LLVM IR and thus invokes a familiar feeling. Since the primary use-case of it will be in test cases, the verbose dictionary-like syntax is really helpful.

Syntax alternatives I’ve considered and rejected include:
1. debug_value %0 : $Int, “x”, “_TtSi”, 1
Why: Hard to read, potentially ambiguous because some fields are optional.

2. debug_value [name “x”] [type “_TtSi”] [argno 1] %0 : $Int
Why: Attributes in square brackets don’t typically have arguments and come before the entity they are modifying.

3. debug_value @var(name: “x”, type: “_TtSi”, argno: 1) %0 : $Int
Why: The ‘@‘ sigil is used not just for attributes but also for global symbols and thus creates an ambiguity.

Thanks for working on this, Adrian! My thoughts:

- I don't see a reason to mangle the type name at SIL time. You should reference the formal AST type directly in the instruction, and print and parse it using the normal (Swift) type parser.

In addition to all the other good reasons to do this, this means that archetypes in the type will be (1) sensibly bound in the context and (2) actually substituted by inlining and generic specialization.

By deferring the type mangling to IRGen time I’m hitting an interesting problem:

Let’s say we have the function
func id<T>(x : T) -> T { return x }

which is translated to SIL as

func id<T>(x: T) -> T // FuncDecl

// declcontext.id <A> (A) -> A
sil hidden @_TF11declcontext2idurFxx : $@convention(thin) <T> (@out T, @in T) -> () {
bb0(%0 : $*T, %1 : $*T):
debug_value_addr %1 : $*T, let, name "x", argno 1
copy_addr [take] %1 to [initialization] %0 : $*T
%4 = tuple ()
return %4 : $()
}

When emitting debug info for “x” we need to determine the mangled name of “T”. Since T is an archetype, the Mangler needs its DeclContext. In a compilation from source the DeclContext is readily available and the FuncDecl itself.
However, when parsing this from SIL it is unclear how to match up the SILFunction with the FuncDecl to establish the DeclContext for the Mangler. It would be possible to demangle the SILFunction’s name and then look up the FuncDecl by name in the SwiftModule and then filter the lookup results by type. But this filtering would not work after function signature optimizations.
Another option is to explicitly call out the DeclContext by adding a sil-decl-ref attribute, like this:

debug_value_addr %1 : $*T, let, name "x", argno 1, declctx #id!1

But it looks like sil-decl-refs also aren’t expressive enough to distinguish between foo() / foo(x:Int) / foo<T>(x:T).

Am I missing something obvious?

Don't SILFunctions already reference a context ValueDecl for debug purposes?

If you’re refering to SILFunction::getDeclContext() this field is only populated by the regular SILGen path. ParseSIL does not (yet) do this. I ran into the above problem while trying to set the DeclContext of SILFunctions that are created by ParseSIL.cpp.

We could add some syntax to the sil function syntax to reference the debug DeclContext. I wouldn't try to demangle the name to guess what it's supposed to be.

Here are a couple of horrible ideas how this could be done:

1. Extend sil-decl-ref to allow specifying a type:
  Grammar:
      sil-function ::= 'sil' sil-linkage? sil-function-name ':' sil-type
                       ‘declcontext’ sil-decl-ref
                       '{' sil-basic-block+ '}'
  Example:

  // Decl
  func foo<T>(i : Int) -> T

  // SIL function + DeclContextRef
  sil @_TF4test3foo... : $@convention(thin) <T> (@out T, @in T) -> () declcontext test.foo$<T>(Int) -> (T) {

2. Extend ValueDecls in .sil files with a unique id
  Example:

  // Decl + ID
  func foo() #1

  // SIL function + DeclContextRef
  sil @_TF4test3foo... : $... declcontext #1 {

3. Extend ValueDecls with a unique id that happens to be its mangled/silgen name
  Example:

  // Decl + ID
  @_silgen_name("@_TF4test3foo...”) func foo()
  // SIL function + DeclContextRef
  sil @_TF4test3foo... : $... declcontext @_TF4test3foo... {

I personally lean towards something along the lines of option 1. What do you think?

-- adrian