Debug info in optimized code - how far can we go?
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Prica, Nikola
Todorovic, Djordje
Software release products are compiled with optimization level –O2 and higher. Such products might produce a core-file that is used for investigating cause of problem that produced it. First thing from which we start debug analysis is call-trace from a crash. In such traces most of the parameters are reported as optimized out due to variety of reasons. Some of parameters are really optimized out, but some of their locations could be calculated. Expert software developers are able to find what values parameters had at function entry point by using the technique that requires searching those values in disassembly of caller frame at place of that particular function call. Automation of such technique is described by DWARF 5 specifications and it is already implemented in GCC and GDB since 2011. The goal of this paper is to present ideas, implementation and problems that we encountered while we were working on this feature in LLVM. We will also show the improvement by presenting recovered parameters in some of the call-traces. This feature should improve debugging of optimized code built with LLVM by recovering optimized-out function parameters.
 Yeah. So, hi everyone. Thanks for coming. My name is George Zodorović. This is Nikola Brica. We are coming from RTK company from Serbia. So, we have been working as a team on various projects in field of compilers, debuggers, profilers, and so on. We are going to be talking today how far can we go with debugging for an optimized code in LVM, especially with unimprovement by looking at function parameters entry values at call point, at call site point. So, since we know that debugging optimized code is very challenging, in these days, we work very hard in order to improve that. So, yeah. So, RTK is software company specialized in system software and embedded systems. So, as I said, we are part of the group working on compilers and tools from open source area, such as GCC, BNU, TILS, LVM, LuaJIT, and so on. So, the group has been working on LVM since 2010, and we are working on debug related issues in LVM for the last two years. So, yeah. Here are points we're going to talk about today. Firstly, we will start with some general story about debugging software release products. So, also, we'll describe a technique that can be used within debugger for finding some actual values of function parameters, even they are described as optimized out. So, after that, we will point to some parts of our implementation. In LVM, we took to support this feature, and at the end, we'll show you some numbers that actually confirmed that we are improving something in debug location coverage. So, yeah. Let's start. So, software release products are compiled with some kind of optimizations. So, for compilers like GCC and LVM Clang, it is usually O2 or O3 level. So, such a product might produce a core DOM file on an embedded system, and it could be starting point of our analysis of the problem. So, first thing we usually do after loading a core file into debugger on our local machines, is analysis of the call trace from the crash. So, through the optimization pipeline, we lose a lot of debug information. So, in those call traces, we see a lot of optimize out parameters values. So, actually, we also notice in those debug sessions that even if a variable is alive at some point, it could be clobbered even earlier and reported as optimized out. So, yeah. So, developers with more experience with the buggers are aware that some of those values could be found at parent's frame or frame above. So, yeah. Looking at this example here, we see that parameter X is reported as optimized out. But if we jump into frame two, we are able to print the actual value at call site point. So, yeah. If we can do that, why not optimize all these process within debugger? But in order to do that, we need additional information by compiler side. So, in this example here, we see all the process optimized on both sides, debugger and compiler. We also see these entry values printed out. So, actually, those optimized out values turned into actual values. So, yeah. A little bit of motivation here to listen to the rest of presentation carefully by implementing this feature in LVM Clang. We noticed that the number of fully covered function parameters increase even up to 15 percent, which is very good number. So, yeah. There are several dwarf symbols introduced in order to support the feature. So, does everyone know dwarf? I hope no, yeah. For those who are not familiar, actually dwarf is standard for describing debug information on Unix-like operating systems. So, compilers generate that, so the bugger's consume it. So, yeah. To mention that it was initially introduced by Jakub Elenec, and it was implemented in GCC and GDB since 2011. So, basically, those two tags represent call site and call site parameters. So, those attributes describe them. So, there is also a dwarf operand that can be used within dwarf expression for describing actual value for parameters. So, let's jump into real example. So, we see here a real call site printed into debug info section. So, it says that it lives at this address in memory, this call PC. Actually, it is address of a call instruction in memory. This call origin actually represents a reference to debug information about call function. This call site parameter is a child of this particular call site, and it says that it lives at register five, and at call point, it had value seven. So, yeah. It's another example. So, if the parameter has untouched unchanged value through the course of the function, we can use this entry value, actually entry value for describing actual value for that parameter at the places where it has no location information at all. So, let's imagine that a parameter has its code from address X to address Z. But from X to epsilon address, it has location information. But for the rest of its scope, we generate additional entry value for describing the rest of the scope. So, yeah. So, this too. Mkola will continue with implementation details. So, hello everyone. I will present you entities that we introduce on IR and machine IR level in order to follow information about call site to the compilation process. I will also introduce you with some of the concerns that we have about our certain parts of implementation. So, how many of you is familiar with debug info metadata in LLVM? So, basically, I will explain it briefly. Basically, it is inspired by dwarf tags and it is used to represent source entities such as file functions, lines, lines, lexical blocks, variables, etc. So, since debug info metadata is inspired by dwarf and we have that resemblance. And George showed that call site information in dwarf is represented by tags, tag call site, and tag call site parameter. We decided to introduce DI call site and DI call site param metadata. So, here we can see for call instruction that it has attached metadata node call site, which reference to call site metadata. And we can see that call site has following arguments such as scope file, it has reference to array of DI call site param, it has line, and it has reference to cold subprogram. And for the I call site param, it has argument number, it has reference to variable metadata, and it has an expression or that variable. Now, if a cold argument is constant, here we would have only DI expression which represent constant. So, this DI call site param is used as a backup location for catching this parameter at entry. I will show primary location later. And with this metadata, we actually emulate jumping back into functions frame and printing certain expression. We also need to mention that in order to use this new value and to value for representing other variables, especially parameter variables, we need to verify that parameter has ever been modified through the course of the function. So, in order to check this, we use SEM constant check and we wrote that information inside parameter variable debug metadata. So, this approach has certain benefits and it has certain limitations and regarding benefits, it resembles to dwarf tag, and it follows that idea. Also, we have additional backup for representing of course site parameter once primary location is lost. And also, we are able to produce tag call site parameter that can have DVOP entry value in itself. And that means that we can look two or more frames up in search for some entry value. And regarding limitations, there is no support for representing expression between multiple variables. To do so, we would probably need new kind of debug metadata. Also, since we are emulating jumping back and printing variable location, we are able to do so because there is a system for tracking variables location in LLVM, but there is no support for tracking functions return value location. And that is the reason that we can represent arguments that are functions, function calls. Also, there is no easy way to represent address of variable. It is hard to distinguish in debug metadata between variables address and variables value. It is not impossible, but it is pretty complicated. Also, we need in order to provide reference in the DICore site parameter to DI variable, variables metadata, we needed to change a pretty standard and stable interface of DI builder interface. Previously, creation and preservation of variables metadata was done in one function call, but we needed to separate this. Next pass that I'm going to talk about is instruction selection pass. Now, it is important to mention this pass since this is the place of our implementation that could possibly be improved. So, we implemented the general algorithm that should work for various architectures. Job of this algorithm is to recognize instructions, copy instructions that forward function arguments with the following function call. So, we can see, for example, this pseudo instructions like this. So, process of this algorithm starts after target call lowering whose result is target call lowering if object. This object in itself contains sequence of selection-dag nodes that represent call sequence. So, we iterate through this sequence and we search for copy-to-reg selection-dag nodes. These nodes should later be mapped to copy instructions. Then we try to match copied value with one of the functions input argument. Such verification is required, because we could have additional copy instructions inside this calling sequence. For example, for variadic functions, additional register copy instruction is required. Some of the function calling ABIs might load additional value that is not function argument. This algorithm could be lowered to target specific level, more precisely to the level of where call sequence is being generated. So, once we have matched these nodes, we just preserve them in instruction selection representation of call site and later, we emit them as dbg call site and dbg call site pair, pseudo-instructions. So, our backup implementation pretty much relies on how dbg value pseudo-instruction is handled. This pseudo-instruction is used to track variables location in registers, virtual or physical stack locations, or some others or in some addresses. So, here we can see this dbg call site and dbg call site pair instructions. For dbg call site, first operand is Boolean value, whether reference call is stale or not. The second argument is provided if call is indirect call, and then it is that calls register location, and last argument is reference to the AI call site. Now, this could be implemented differently, but we choose to keep all information about call site at one place. Now, we can see here that dbg call site pair instructions are attached as a bundle to dbg call site. The first argument of dbg call site pair is a register that forwards argument to the following function call. Second is reference to the AI call site pair, and the last arguments represent the location that is loaded into parameter forward register. Now, I will mention that this machine, machine IR is produced with LLM4.0. I have just stripped some of the instructions in order to call to be more clear. Here, we can follow behavior of variable C, and we can see that it is indeed forwarded as the first argument of function full. So, its first value is value four. After this function call, it is returned as EAX and moved to ebx register and later it is forwarded as a function call argument through EDI. So, in order to handle this instruction in back end, we needed modification in a prologue, epilogue, and setter pass, register allocation, split kit, virtual registry, writer, and most important for us in light debug values pass. Now, a job of this pass is to broadcast, broadcast DBG value of celled instructions into successive blocks, where preserved location is not clobbered. That location is valid. So, as a natural, it should emit replacement for parameters, for DBG values that represent parameters. Once these locations are clobbered, we should emit this DBG value with this new expression, dvop entry value. Also, this pass knows for each basic block range, which variables are live at that point. So, also, we adjust a DBG call side param instructions here. By adjusting, we mean that we delete these instructions that are not valid. These actions that are not valid are ones that do not have primary location nor backup location. By backup location, we mean, invalid backup location are ones that reference variables that are not seen at that point of block. Also, regarding producing this, printing this location in object file, it is done in dwarf debug pass, and it is handled similarly as for DBG value instruction. So, there is nothing special to say here. It relies pretty much on similar structures as DBG value. So, Georgia will now present you some measurements that we have. So, yeah, I'll show you some numbers that actually confirm our improvements. So, in order to do that, we used a lock start tool from L-Futiles package. It actually looks for a scope of variable and calculates a debug location coverage we need. So, for testing purpose, we, for these slides, we used gdb7.11 and spec 2006 benchmark. So, also, we noticed increment in debug location coverage. Also, we didn't touch code generation, which is very important. There is no change in text, BSS or data sections. There is only change in dot debug sections as expected. So, yeah. Just to mention that for O2 and O3 level, we noticed very similar results. So, yeah. First example is gdb7.11. So, we build the latest release version of that. So, we noticed over there the increment of fully covered function parameters for about 15 percent. It is about 17,000 more debug variables with fully debug location coverage, which is a very good number. Yeah. So, average coverage per variable increased for about 10 percent. So, there is no change in code generation. There is only change in dot debug sections. In this case, we noticed build time increase for about 2 percent. So, yeah. Another example. Yeah. We built spec 2006 benchmark. It is huge project design to stress processor, CPU, compiler, memory subsystem, and so on. It is pretty standard. So, over there, we noticed the increment of fully covered function parameters for about 8 percent, which is about 12,000 more debug variables with fully coverage. So, in this case, we noticed the increment of average coverage per variable for about 4 percent. So, there is no change in code generation. The change as expected is only in dot debug sections and build time in this case, increase for about 1 percent. So, yeah. Those improvement in debug location coverage is the most important. So, I will just wrap up this presentation. So, after we finish this implementation, we identified two main spots in our implementation that require further discussion. So, there is a question about the usefulness of the I call site param. There is a question whether algorithm in an instruction selection phase should be lower to target specific level, but that requires target specific knowledge. What does our implementation provides? It provides most importantly correct debug data. We try to be strict as much as we could in order to achieve this. Also, our measurements show that we didn't touch code generation process, and this is important because our implementations takes part through the whole compilation pipeline. So, it is also important to mention that it provides infrastructure for collecting information about core sites. We believe that we have touched all necessary passes, and that current flow is sufficient, but it certainly needs some improvements. It gives us desired results. It gives us improvement in parameter location coverage, and it provides us new functionality in debugger. It provides us function entry values. These entry values with debugger clearly provide better user debugging experience in programs produced with LLVM. Before we finish, we would like to mention that we have implemented this feature in collaboration with Cisco, especially with Anand Solvda and Ivan Bayer. So, thank you for listening. Thank you for that. Thank you. Thank you. I was curious in the slide where you showed the measurements. So, you show dash G dash F in the program entry values. Is that dash F flag added into the dash G groups or any of the G level groups, or is this something I explicitly need to enable? Actually, firstly, just to mention that we, yeah. So, the question was, does we include this F emit a param option into dash G default options? So, actually, for now, no? Why? We initially implemented this for an internal version of LLVM 4.0 compiler, and we tested this within Cisco on large projects, but, and also we introduced a new option in order to make all of those testing and make sure that we didn't clobber anything, especially cogeneration. And as soon as we make sure that everything goes well, we will include this in default minus G. And actually, just to mention that we are in the process of backporting this onto LLVM Trank, the latest version. Actually, we backported it. So, we are finishing testing phase, and as soon as we are done with that, we will post those patches onto LLVM. Awesome. We can do the debug info. Yeah, thank you. It's supposed to be this month, so yeah, we expect this. I noticed you had some target-specific code in there. Is it your intention that you've targets implement this yourself, or are you going to implement this all back end? So, the question is where is the target-specific implementation? Target-specific implementation part is in instruction for selection, and it is part for selection-deck nodes generation. It concerns about how some targets generate this core sequence. And we noticed that there are some issues for matching those selection-deck nodes, because you could, for example, you could have some node, you could have node value, and you could have that node value wrapped up with some extension, for example, zero extension or sine extension, and you can't match these two nodes. You just need explicitly to match this selection-deck node, which does not have this extension. Also, we also implemented some saluting function that preserves some location, where we, for example, when we lose track of primary location in virtual registry writer, we go back up to the stream to search for instruction that loads that parameter, and we try to interpret that instruction. We implemented the saluting for x86 lia instruction, for example. But when in the upstreaming process, are you going to implement that for all targets, or is it sort of selectively people have to turn this on and they'll have to make sure the back end supports it? Sorry, can you repeat the question? Yes, sir, so when in the process of upstreaming, as it stands now, it sounds like some parts will only work in x86, so I'm just thinking, are you good to try and approach the back end implementers to get them to implement it, or are you going to implement it yourself? No, this... Yeah, so the question is whether this only works for 886 architecture. We just tested it for x86 architecture. We tested this feature only to build complex software for various architecture such as MIPS and R, but we didn't go into deep details to see where we lose information. So... Do you have the negative experience during the coverage that you see that I use in the same context? Actually, yeah, when we started looking at this feature, and yeah, we did, yeah, we had, you know, seen those measurements. We calculated those numbers also with GCC, but comparing GCC and LVM doesn't make sense because the code is different, generated code is different. But yeah, honestly, LVM is still behind GCC in debug location coverage because, yeah, this feature is pre-standard over there since 2011, and it was improved in stages, so yeah. If your question was does GCC has better debug location coverage, yeah, it still has, but LVM with this will have certainly better location coverage, yeah, and we are running to even, you know, be at least like GCC, you know. You can hear that as a bench like this, still some... Yeah, yeah. I had a really good question to that. So, yep. First of all, thank you very much. This is really useful work because it's an area where LVM debug-optimized coding LVM is behind GCC and has been improved. Have you looked at the impact of this actually on the GDB regression test suite? Because that actually has some quite good corner cases of testing things. So, the question was whether we looked at GDB for some corner test cases. Thank you for that question. We didn't, and we will gladly look it. We will investigate it. Thank you. So, just to mention here that LDB doesn't support reading of entry values. I think that for now it will be just ignored. But within GDB, we tried to debug user experience even with binaries compiled with LVM, with this version, and yeah, it works for a bunch of cases. So, thank you for the question. Yes? You may have mentioned it, but is this functionality only available when you're generating for R5 or is it also available for R4? Actually, the question was if this functionality is available only for R5, actually, initially, it was introduced as a GNU extension and used in GCC like that. But since R5 released, it is in the part of the standard. So, for now, yeah, for this purpose, we internally generated GNU extensions as well. But yeah, it's supposed to be both of that. Sure, yeah, yeah, we should support GNU as well as for five symbols. So, yeah, thank you for the question. So, on this metrics, I'm not entirely sure exactly what the metric average coverage per variable really means, but I'm assuming that it's impossible to get 100% because some variables will be completely eliminated. So, even if you were perfect to find it, do you know what the theoretical per maximum number would be? Just to put it in the right form? So, the question is, what is the theoretical maximum for coverage percentage? We use this tool, lock stat, now, it is not able to measure variable visibility from where it is defined to last use of that variable. It can only measure its coverage only to that lexical block where it is defined. So, these numbers just show us how much we did improve, show that we just improved something. And we similar, this tool was also used by Jellinek in his paper to show up this improvement. Yeah, actually, it would be perfect if we have a tool that actually looks for a life of variable, but yeah, we don't have that. We use just this one as a reference to measure improvement. Yeah, but if someone knows for some tool that looks for a variable's life, please be free to advise us. There are no more questions than we can back to speakers. Thank you.
 Yeah. So, hi everyone. Thanks for coming.  My name is George Zodorović.  This is Nikola Brica.  We are coming from RTK company from Serbia.  So, we have been working as a team  on various projects in field of compilers,  debuggers, profilers, and so on.  We are going to be talking today how far can we go with  debugging for an optimized code in LVM,  especially with unimprovement by looking at  function parameters entry values at call point,  at call site point.  So, since we know that debugging  optimized code is very challenging,  in these days, we work very hard in order to improve that.  So, yeah. So, RTK is  software company specialized in  system software and embedded systems.  So, as I said, we are part of the group working on  compilers and tools from open source area,  such as GCC, BNU, TILS, LVM, LuaJIT, and so on.  So, the group has been working on LVM since 2010,  and we are working on  debug related issues in LVM for the last two years.  So, yeah. Here are points we're going to talk about today.  Firstly, we will start with  some general story about debugging software release products.  So, also, we'll describe a technique  that can be used within debugger for  finding some actual values of function parameters,  even they are described as optimized out.  So, after that, we will point to some parts of our implementation.  In LVM, we took to support this feature,  and at the end, we'll show you some numbers that actually  confirmed that we are improving something in debug location coverage.  So, yeah. Let's start.  So, software release products are compiled with some kind of optimizations.  So, for compilers like GCC and LVM Clang,  it is usually O2 or O3 level.  So, such a product might produce  a core DOM file on an embedded system,  and it could be starting point of our analysis of the problem.  So, first thing we usually do after loading  a core file into debugger on our local machines,  is analysis of the call trace from the crash.  So, through the optimization pipeline,  we lose a lot of debug information.  So, in those call traces,  we see a lot of optimize out parameters values.  So, actually, we also notice in those debug sessions  that even if a variable is alive at some point,  it could be clobbered even earlier and reported as optimized out.  So, yeah.  So, developers with more experience with  the buggers are aware that some of those values  could be found at parent's frame or frame above.  So, yeah.  Looking at this example here,  we see that parameter X is reported as optimized out.  But if we jump into frame two,  we are able to print the actual value at call site point.  So, yeah.  If we can do that,  why not optimize all these process within debugger?  But in order to do that,  we need additional information by compiler side.  So, in this example here,  we see all the process optimized on both sides,  debugger and compiler.  We also see these entry values printed out.  So, actually, those optimized out values turned into actual values.  So, yeah.  A little bit of motivation here to listen to  the rest of presentation carefully by implementing this feature  in LVM Clang.  We noticed that the number of fully covered function parameters  increase even up to 15 percent,  which is very good number.  So, yeah.  There are several dwarf symbols  introduced in order to support the feature.  So, does everyone know dwarf?  I hope no, yeah.  For those who are not familiar,  actually dwarf is standard for describing  debug information on Unix-like operating systems.  So, compilers generate that,  so the bugger's consume it.  So, yeah. To mention that it was initially  introduced by Jakub Elenec,  and it was implemented in GCC and GDB since 2011.  So, basically, those two tags  represent call site and call site parameters.  So, those attributes describe them.  So, there is also  a dwarf operand that can be used within  dwarf expression for describing  actual value for parameters.  So, let's jump into real example.  So, we see here a real call site  printed into debug info section.  So, it says that it lives at this address in memory,  this call PC.  Actually, it is address of a call instruction in memory.  This call origin actually represents a reference  to debug information about call function.  This call site parameter is a child of this particular call site,  and it says that it lives at register five,  and at call point, it had value seven.  So, yeah. It's another example.  So, if the parameter has  untouched unchanged value through the course of the function,  we can use this entry value,  actually entry value for describing  actual value for that parameter at  the places where it has no location information at all.  So, let's imagine that a parameter has  its code from address X to address Z.  But from X to epsilon address,  it has location information.  But for the rest of its scope,  we generate additional entry value  for describing the rest of the scope.  So, yeah.  So, this too.  Mkola will continue with implementation details.  So, hello everyone.  I will present you entities that we  introduce on IR and machine IR level in  order to follow information about  call site to the compilation process.  I will also introduce you with some of  the concerns that we have  about our certain parts of implementation.  So, how many of you is familiar with  debug info metadata in LLVM?  So, basically, I will explain it briefly.  Basically, it is inspired by  dwarf tags and it is used to represent source entities such  as file functions, lines,  lines, lexical blocks, variables, etc.  So, since debug info metadata is  inspired by dwarf and we have that resemblance.  And George showed that  call site information in dwarf is represented by  tags, tag call site, and tag call site parameter.  We decided to introduce  DI call site and DI call site param metadata.  So, here we can see for call instruction  that it has attached metadata node call site,  which reference to call site metadata.  And we can see that call site has  following arguments such as scope file,  it has reference to array of DI call site param,  it has line, and it has reference to cold subprogram.  And for the I call site param,  it has argument number,  it has reference to variable metadata,  and it has an expression or that variable.  Now, if a cold argument is constant,  here we would have only DI expression which represent constant.  So, this DI call site param is used as  a backup location for catching this parameter at entry.  I will show primary location later.  And with this metadata,  we actually emulate jumping back into functions frame  and printing certain expression.  We also need to mention that in order to use  this new value and to value for representing other variables,  especially parameter variables,  we need to verify that parameter has  ever been modified through the course of the function.  So, in order to check this,  we use SEM constant check and we wrote that information inside  parameter variable debug metadata.  So, this approach has certain benefits and  it has certain limitations and regarding benefits,  it resembles to dwarf tag,  and it follows that idea.  Also, we have additional backup for  representing of course site parameter  once primary location is lost.  And also, we are able to produce  tag call site parameter that can have  DVOP entry value in itself.  And that means that we can look two or more frames up  in search for some entry value.  And regarding limitations,  there is no support for representing  expression between multiple variables.  To do so, we would probably need  new kind of debug metadata.  Also, since we are emulating jumping back  and printing variable location,  we are able to do so because there is  a system for tracking variables location in LLVM,  but there is no support for  tracking functions return value location.  And that is the reason that we can represent  arguments that are functions, function calls.  Also, there is no easy way to represent address of variable.  It is hard to distinguish in  debug metadata between variables address and variables value.  It is not impossible, but it is pretty complicated.  Also, we need in order to provide reference in  the DICore site parameter to DI variable,  variables metadata, we needed to change  a pretty standard and stable interface of DI builder interface.  Previously, creation and  preservation of variables metadata  was done in one function call,  but we needed to separate this.  Next pass that I'm going to talk about  is instruction selection pass.  Now, it is important to mention this pass since this is  the place of our implementation that could possibly be improved.  So, we implemented the general algorithm  that should work for various architectures.  Job of this algorithm is to recognize  instructions, copy instructions that  forward function arguments with the following function call.  So, we can see, for example,  this pseudo instructions like this.  So, process of this algorithm starts after  target call lowering whose result is target call lowering if object.  This object in itself contains sequence of  selection-dag nodes that represent call sequence.  So, we iterate through this sequence and we search  for copy-to-reg selection-dag nodes.  These nodes should later be mapped to copy instructions.  Then we try to match copied value with  one of the functions input argument. Such verification is required,  because we could have additional copy instructions inside this calling sequence.  For example, for variadic functions,  additional register copy instruction is required.  Some of the function calling ABIs might load  additional value that is not function argument.  This algorithm could be lowered to target specific level,  more precisely to the level of where call sequence is being generated.  So, once we have matched these nodes,  we just preserve them in  instruction selection representation of call site and later,  we emit them as dbg call site and dbg call site pair,  pseudo-instructions.  So, our backup implementation pretty much relies on  how dbg value pseudo-instruction is handled.  This pseudo-instruction is used to track  variables location in registers,  virtual or physical stack locations,  or some others or in some addresses.  So, here we can see this dbg call site and dbg call site pair instructions.  For dbg call site, first operand is Boolean value,  whether reference call is stale or not.  The second argument is provided if call is indirect call,  and then it is that calls register location,  and last argument is reference to the AI call site.  Now, this could be implemented differently,  but we choose to keep all information about call site at one place.  Now, we can see here that dbg call site pair instructions are  attached as a bundle to dbg call site.  The first argument of dbg call site pair is  a register that forwards argument to the following function call.  Second is reference to the AI call site pair,  and the last arguments represent the location  that is loaded into parameter forward register.  Now, I will mention that this machine,  machine IR is produced with LLM4.0.  I have just stripped some of the instructions in order to call to be more clear.  Here, we can follow behavior of variable C,  and we can see that it is indeed forwarded as the first argument of function full.  So, its first value is value four.  After this function call, it is returned as EAX and moved to  ebx register and later it is forwarded as a function call argument through EDI.  So, in order to handle this instruction in back end,  we needed modification in a prologue,  epilogue, and setter pass, register allocation,  split kit, virtual registry,  writer, and most important for us in light debug values pass.  Now, a job of this pass is to broadcast,  broadcast DBG value of celled instructions into successive blocks,  where preserved location is not clobbered.  That location is valid.  So, as a natural, it should emit replacement for parameters,  for DBG values that represent parameters.  Once these locations are clobbered,  we should emit this DBG value with  this new expression, dvop entry value.  Also, this pass knows for each basic block range,  which variables are live at that point.  So, also, we adjust a DBG call side param instructions here.  By adjusting, we mean that we delete  these instructions that are not valid.  These actions that are not valid are ones that do not have  primary location nor backup location.  By backup location, we mean,  invalid backup location are ones that reference  variables that are not seen at that point of block.  Also, regarding producing this,  printing this location in object file,  it is done in dwarf debug pass,  and it is handled similarly as for DBG value instruction.  So, there is nothing special to say here.  It relies pretty much on similar structures as DBG value.  So, Georgia will now present you some measurements that we have.  So, yeah, I'll show you some numbers that  actually confirm our improvements.  So, in order to do that,  we used a lock start tool from L-Futiles package.  It actually looks for a scope of  variable and calculates a debug location coverage we need.  So, for testing purpose,  we, for these slides,  we used gdb7.11 and spec 2006 benchmark.  So, also, we noticed increment in debug location coverage.  Also, we didn't touch code generation,  which is very important.  There is no change in text,  BSS or data sections.  There is only change in dot debug sections as expected.  So, yeah. Just to mention that for  O2 and O3 level, we noticed very similar results.  So, yeah. First example is gdb7.11.  So, we build the latest release version of that.  So, we noticed over there the increment of  fully covered function parameters for about 15 percent.  It is about 17,000 more debug variables  with fully debug location coverage,  which is a very good number.  Yeah. So, average coverage per variable  increased for about 10 percent.  So, there is no change in code generation.  There is only change in dot debug sections.  In this case, we noticed  build time increase for about 2 percent.  So, yeah. Another example.  Yeah. We built spec 2006 benchmark.  It is huge project design to stress processor, CPU,  compiler, memory subsystem, and so on.  It is pretty standard.  So, over there, we noticed the increment  of fully covered function parameters for about 8 percent,  which is about 12,000 more debug variables with fully coverage.  So, in this case, we noticed the increment of  average coverage per variable for about 4 percent.  So, there is no change in code generation.  The change as expected is only in  dot debug sections and build time in this case,  increase for about 1 percent.  So, yeah. Those improvement in  debug location coverage is the most important.  So, I will just wrap up this presentation.  So, after we finish this implementation,  we identified two main spots in  our implementation that require further discussion.  So, there is a question about  the usefulness of the I call site param.  There is a question whether algorithm in  an instruction selection phase should be  lower to target specific level,  but that requires target specific knowledge.  What does our implementation provides?  It provides most importantly correct debug data.  We try to be strict as much as we could in  order to achieve this.  Also, our measurements show that we  didn't touch code generation process,  and this is important because  our implementations takes  part through the whole compilation pipeline.  So, it is also important to mention that it  provides infrastructure for  collecting information about core sites.  We believe that we have touched all necessary passes,  and that current flow is sufficient,  but it certainly needs some improvements.  It gives us desired results.  It gives us improvement in parameter location coverage,  and it provides us new functionality in debugger.  It provides us function entry values.  These entry values with debugger clearly  provide better user debugging experience in  programs produced with LLVM.  Before we finish, we would like to mention that we  have implemented this feature in collaboration with Cisco,  especially with Anand Solvda and Ivan Bayer.  So, thank you for listening.  Thank you for that.  Thank you.  Thank you.  I was curious in the slide where you showed the measurements.  So, you show dash G dash F in the program entry values.  Is that dash F flag added into the dash G groups  or any of the G level groups,  or is this something I explicitly need to enable?  Actually, firstly, just to mention that we, yeah.  So, the question was, does we include this F emit  a param option into dash G default options?  So, actually, for now, no?  Why?  We initially implemented this for an internal version  of LLVM 4.0 compiler, and we tested this within Cisco  on large projects, but, and also we introduced a new option  in order to make all of those testing and make sure that we  didn't clobber anything, especially cogeneration.  And as soon as we make sure that everything goes well,  we will include this in default minus G.  And actually, just to mention that we are in the process  of backporting this onto LLVM Trank, the latest version.  Actually, we backported it.  So, we are finishing testing phase,  and as soon as we are done with that,  we will post those patches onto LLVM.  Awesome.  We can do the debug info.  Yeah, thank you.  It's supposed to be this month, so yeah, we expect this.  I noticed you had some target-specific code in there.  Is it your intention that you've targets  implement this yourself, or are you going to implement this  all back end?  So, the question is where is the target-specific  implementation?  Target-specific implementation part is in instruction  for selection, and it is part for selection-deck  nodes generation.  It concerns about how some targets generate this  core sequence.  And we noticed that there are some issues  for matching those selection-deck nodes,  because you could, for example, you could have some node,  you could have node value, and you could have that node value  wrapped up with some extension, for example,  zero extension or sine extension,  and you can't match these two nodes.  You just need explicitly to match this selection-deck node,  which does not have this extension.  Also, we also implemented some saluting function  that preserves some location, where we, for example,  when we lose track of primary location in virtual registry  writer, we go back up to the stream to search for  instruction that loads that parameter,  and we try to interpret that instruction.  We implemented the saluting for x86 lia instruction,  for example.  But when in the upstreaming process, are you going to implement  that for all targets, or is it sort of selectively  people have to turn this on and they'll have to make sure  the back end supports it?  Sorry, can you repeat the question?  Yes, sir, so when in the process of upstreaming,  as it stands now, it sounds like some parts will only work  in x86, so I'm just thinking, are you good to try  and approach the back end implementers to get them to implement it,  or are you going to implement it yourself?  No, this...  Yeah, so the question is whether this only works  for 886 architecture.  We just tested it for x86 architecture.  We tested this feature only to build complex software  for various architecture such as MIPS and R,  but we didn't go into deep details to see where we lose information.  So...  Do you have the negative experience during the coverage  that you see that I use in the same context?  Actually, yeah, when we started looking at this feature,  and yeah, we did, yeah, we had, you know, seen those measurements.  We calculated those numbers also with GCC,  but comparing GCC and LVM doesn't make sense  because the code is different, generated code is different.  But yeah, honestly, LVM is still behind GCC in debug location coverage  because, yeah, this feature is pre-standard over there since 2011,  and it was improved in stages, so yeah.  If your question was does GCC has better debug location coverage,  yeah, it still has, but LVM with this will have certainly better location coverage,  yeah, and we are running to even, you know, be at least like GCC, you know.  You can hear that as a bench like this, still some...  Yeah, yeah.  I had a really good question to that.  So, yep.  First of all, thank you very much. This is really useful work  because it's an area where LVM debug-optimized coding LVM is behind GCC  and has been improved.  Have you looked at the impact of this actually on the GDB regression test suite?  Because that actually has some quite good corner cases of testing things.  So, the question was whether we looked at GDB for some corner test cases.  Thank you for that question.  We didn't, and we will gladly look it.  We will investigate it. Thank you.  So, just to mention here that LDB doesn't support reading of entry values.  I think that for now it will be just ignored.  But within GDB, we tried to debug user experience even with binaries compiled with LVM,  with this version, and yeah, it works for a bunch of cases.  So, thank you for the question. Yes?  You may have mentioned it, but is this functionality only available when you're generating  for R5 or is it also available for R4?  Actually, the question was if this functionality is available only for R5,  actually, initially, it was introduced as a GNU extension and used in GCC like that.  But since R5 released, it is in the part of the standard.  So, for now, yeah, for this purpose, we internally generated GNU extensions as well.  But yeah, it's supposed to be both of that.  Sure, yeah, yeah, we should support GNU as well as for five symbols.  So, yeah, thank you for the question.  So, on this metrics, I'm not entirely sure exactly what the metric average coverage per variable  really means, but I'm assuming that it's impossible to get 100%  because some variables will be completely eliminated.  So, even if you were perfect to find it, do you know what the theoretical per maximum number would be?  Just to put it in the right form?  So, the question is, what is the theoretical maximum for coverage percentage?  We use this tool, lock stat, now, it is not able to measure variable visibility from where it is defined  to last use of that variable.  It can only measure its coverage only to that lexical block where it is defined.  So, these numbers just show us how much we did improve, show that we just improved something.  And we similar, this tool was also used by Jellinek in his paper to show up this improvement.  Yeah, actually, it would be perfect if we have a tool that actually looks for a life of variable,  but yeah, we don't have that.  We use just this one as a reference to measure improvement.  Yeah, but if someone knows for some tool that looks for a variable's life, please be free to advise us.  There are no more questions than we can back to speakers.  Thank you.
Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__0_155.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__156_1451.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__1452_2435.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__2436_2483.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__2484_3611.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__3612_3707.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__3708_4211.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__4212_5555.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__5556_5975.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__5976_6275.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__6276_6407.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__6408_6455.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__6456_7367.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__7368_8087.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__8088_8855.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__8856_9791.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__9792_10847.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__10848_12323.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__12324_13379.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__13380_13439.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__13440_15107.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__15108_17147.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__17148_20351.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__20352_20399.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__20400_20759.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__20760_23711.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__23712_24323.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__24324_24407.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__24408_24719.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__24720_25619.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__25620_25859.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__25860_26351.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__26352_26495.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__26496_26675.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__26676_27047.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__27048_27227.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__27228_27407.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__27408_30479.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__30480_30983.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__30984_32555.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__32556_33887.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__33888_35819.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__35820_36071.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__36072_36779.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__36780_38807.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__38808_38855.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__38856_38903.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__38904_38999.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__39000_39047.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__39048_39095.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__39096_39515.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__39516_39563.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__39564_54767.png Debug_info_in_optimized_code_-_how_far_can_we_go__Improving_LLVM_debug_info_with_function_entry_val__54768_54882.png