[swift-dev] [RFC] SIL syntax for debug information Part 1: Variables
Adrian Prantl
aprantl at apple.com
Tue Dec 15 15:25:46 CST 2015
> On Dec 10, 2015, at 10:19 AM, John McCall <rjmccall at apple.com> wrote:
>
>> On Dec 10, 2015, at 8:31 AM, Joe Groff via swift-dev <swift-dev at swift.org> wrote:
>>> On Dec 9, 2015, at 4:15 PM, Adrian Prantl via swift-dev <swift-dev at 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?
-- adrian
More information about the swift-dev
mailing list