Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve debug info in scalar replacement pass #3461

Merged
merged 9 commits into from
Jul 27, 2020

Conversation

jaebaek
Copy link
Contributor

@jaebaek jaebaek commented Jun 25, 2020

Preserve OpenCL.DebugInfo.100 and line information in scalar
replacement pass.

  1. Set the debug scope and line information for the new replacement
    instructions.
  2. Replace DebugDeclare and DebugValue if their OpVariable or value
    operands are replaced by scalars.
  • If the initial aggregate has DebugValue, we clone a DebugValue
    for each scalar and add one more index for the scalar to 'Indexes'
    operand of the cloned DebugValue as we add an index to 'Indexes'
    operand of OpAccessChain.
  • If the initial aggregate has DebugDeclare, we create a DebugValue
    with Deref operation for each scalar and add an index for the scalar
    to 'Indexes' operand.
  • For example,
   struct S { int a; int b;}
   S foo; // before scalar replacement

   int foo_a; // after scalar replacement
   int foo_b;

   DebugDeclare %dbg_foo %foo %null_expr // before

   DebugValue %dbg_foo %foo_a %Deref_expr 0 // after
   DebugValue %dbg_foo %foo_b %Deref_expr 1 // means Value(foo.members[1]) == Deref(%foo_b)

Note that the DebugValue instructions for the SROA'd structure
elements are linked to the original debug info for S foo via the
%dbg_foo. Each DebugValue has Deref and 'Indexes' i.e., 0
for %foo_a and 1 for %foo_b in the above example.
DebugValue %dbg_foo %foo_a %Deref_expr 0 means that
Deref(%foo_a) is the value of 0th member of %dbg_foo.

@jaebaek
Copy link
Contributor Author

jaebaek commented Jun 25, 2020

FYI, @greg-lunarg This is the PR for the scalar replacement.

@jaebaek
Copy link
Contributor Author

jaebaek commented Jul 6, 2020

We currently discuss some SPIR-V spec issues related to this PR. I will update this PR after that.

@jaebaek jaebaek force-pushed the dbg_scalar_replacement branch from 84cc461 to d45f950 Compare July 15, 2020 17:54
Copy link
Contributor

@dnovillo dnovillo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial questions. Still haven't read through the whole thing.

@@ -630,6 +630,9 @@ class ConstantManager {
// Returns the id of a 32-bit floating point constant with value |val|.
uint32_t GetFloatConst(float val);

// Returns the id of a 32-bit singed integer constant with value |val|.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/singed/signed/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

uint32_t expr_id,
uint32_t index_id,
Instruction* insert_before) {
std::unique_ptr<Instruction> new_dbg_value(new Instruction(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this re-use AddDebugValue? Shouldn't it need to check the same things that AddDebugValue checks? And now in #3511, AddDebugValue returns a boolean flag indicating success. It seems odd that this would not be also expected in this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AddDebugValueWithIndex() simply generates and inserts a single DebugValue while AddDebugValue() does the same thing for the multiple DebugValue. I updated AddDebugValue() to use AddDebugValueWithIndex().

In terms of the boolean return of AddDebugValue(), it does not matter that much of this PR. It will follow #3511 when I merge it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so now I have a question about AddDebugValue(). It seems to be a low-level primitive, and yet it may (under some conditions) not actually add a DebugValue(). This is confusing, as it would mean that a low-level helper decides whether or not to do something (despite the name of the function). Perhaps rename the function to reflect this? Something like MaybeAdd... or (better) make the caller responsible for calling AddDebugValue when it really means to add a value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that these names are confusing. I just update AddDebugValue() to AddDebugValueIfVarDeclIsVisible().

Copy link
Contributor Author

@jaebaek jaebaek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your code review. I updated it once. PTAL!

@@ -630,6 +630,9 @@ class ConstantManager {
// Returns the id of a 32-bit floating point constant with value |val|.
uint32_t GetFloatConst(float val);

// Returns the id of a 32-bit singed integer constant with value |val|.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

uint32_t expr_id,
uint32_t index_id,
Instruction* insert_before) {
std::unique_ptr<Instruction> new_dbg_value(new Instruction(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AddDebugValueWithIndex() simply generates and inserts a single DebugValue while AddDebugValue() does the same thing for the multiple DebugValue. I updated AddDebugValue() to use AddDebugValueWithIndex().

In terms of the boolean return of AddDebugValue(), it does not matter that much of this PR. It will follow #3511 when I merge it.

@dnovillo
Copy link
Contributor

Preserve OpenCL.DebugInfo.100 and line information in scalar
replacement pass.

  1. Set the debug scope and line information for the new replacement
    instructions.
  2. Replace DebugDeclare and DebugValue if their OpVariable or value
    operands are replaced by scalars. It uses 'Indexes' operand of
    DebugValue. For example,
    struct S { int a; int b;}
    S foo; // before scalar replacement
    int foo_a; // after scalar replacement
    int foo_b;
    DebugDeclare %dbg_foo %foo %null_expr // before
    DebugValue %dbg_foo %foo_a %Deref_expr 0 // after
    DebugValue %dbg_foo %foo_b %Deref_expr 1 // means Value(foo.members[1]) == Deref(%foo_b)

Add some commentary on why we have to replace DebugDeclare with DebugValue? My understanding from reading https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.DebugInfo.100.html#DebugDeclare is used to link debug information to a local declaration. When we scalarize the variable, this declaration disappears because the symbol foo disappears. What is not completely clear in this description, is how will a debugger request for foo.a be linked to the dbg_foo debug symbol.

I would add something along the lines of "the DebugValue expressions for the SROA'd structure elements are linked to the original debug info for foo via the dbg_foo symbol. Each DebugValue will have instructions on what field is being accessed via the Deref_* expressions."

Does that sound like I'm understanding the difference between the two?

uint32_t expr_id,
uint32_t index_id,
Instruction* insert_before) {
std::unique_ptr<Instruction> new_dbg_value(new Instruction(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so now I have a question about AddDebugValue(). It seems to be a low-level primitive, and yet it may (under some conditions) not actually add a DebugValue(). This is confusing, as it would mean that a low-level helper decides whether or not to do something (despite the name of the function). Perhaps rename the function to reflect this? Something like MaybeAdd... or (better) make the caller responsible for calling AddDebugValue when it really means to add a value.

Copy link
Contributor Author

@jaebaek jaebaek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your comments. I think you correctly understand it.
I update the description with more details.
PTAL!

uint32_t expr_id,
uint32_t index_id,
Instruction* insert_before) {
std::unique_ptr<Instruction> new_dbg_value(new Instruction(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that these names are confusing. I just update AddDebugValue() to AddDebugValueIfVarDeclIsVisible().

Copy link
Contributor

@dnovillo dnovillo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks fine to me, but I defer to @s-perron for final approval, as I'm less familiar with this code.

@jaebaek jaebaek force-pushed the dbg_scalar_replacement branch from ebb3182 to a1678d0 Compare July 22, 2020 19:23
Copy link
Collaborator

@s-perron s-perron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small change, then this is good to merge.

source/opt/scalar_replacement_pass.cpp Outdated Show resolved Hide resolved
jaebaek added 9 commits July 27, 2020 10:32
1. Set the debug scope and line information for the new replacement
   instructions.
2. Replace DebugDeclare and DebugValue if their OpVariable or value
   operands are replaced by scalars. It uses 'Indexes' operand of
   DebugValue. For example,

   struct S { int a; int b;}
   S foo; // before scalar replacement

   int foo_a; // after scalar replacement
   int foo_b;

   DebugDeclare %dbg_foo %foo %null_expr // before

   DebugValue %dbg_foo %foo_a %Deref_expr 0 // after
   DebugValue %dbg_foo %foo_b %Deref_expr 1 // means Value(foo.members[1]) == Deref(%foo_b)
@jaebaek jaebaek force-pushed the dbg_scalar_replacement branch from 7176ca0 to 71373ab Compare July 27, 2020 14:44
Copy link
Contributor Author

@jaebaek jaebaek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

source/opt/scalar_replacement_pass.cpp Outdated Show resolved Hide resolved
@s-perron s-perron merged commit 6a3eb67 into KhronosGroup:master Jul 27, 2020
@jaebaek jaebaek deleted the dbg_scalar_replacement branch July 27, 2020 17:52
dnovillo pushed a commit to dnovillo/SPIRV-Tools that referenced this pull request Aug 19, 2020
1. Set the debug scope and line information for the new replacement
   instructions.
2. Replace DebugDeclare and DebugValue if their OpVariable or value
   operands are replaced by scalars. It uses 'Indexes' operand of
   DebugValue. For example,

   struct S { int a; int b;}
   S foo; // before scalar replacement

   int foo_a; // after scalar replacement
   int foo_b;

   DebugDeclare %dbg_foo %foo %null_expr // before

   DebugValue %dbg_foo %foo_a %Deref_expr 0 // after
   DebugValue %dbg_foo %foo_b %Deref_expr 1 // means Value(foo.members[1]) == Deref(%foo_b)
dneto0 pushed a commit to dneto0/SPIRV-Tools that referenced this pull request Sep 14, 2024
* Rolling 2 dependencies and updating expectations

Roll third_party/spirv-cross/ 6575e451f..0376576d2 (5 commits)

KhronosGroup/SPIRV-Cross@6575e45...0376576

$ git log 6575e451f..0376576d2 --date=short --no-merges --format='%ad %ae %s'
2020-07-22 tommek Enabling setting a fixed sampleMask in Metal fragment shaders.
2020-02-20 cdavis MSL: Add support for processing more than one patch per workgroup.
2020-07-22 dsinclair Roll GLSLang, SPIRV-Headers and SPIRV-Tools.
2020-07-22 cdavis MSL: Factor creating a uint type into its own method.
2020-07-22 cdavis MSL: Factor a really gnarly condition into its own method.

Created with:
  roll-dep third_party/spirv-cross

Roll third_party/spirv-tools/ 969f028..b63f0e5 (13 commits)

KhronosGroup/SPIRV-Tools@969f028...b63f0e5

$ git log 969f028..b63f0e5 --date=short --no-merges --format='%ad %ae %s'
2020-07-27 rdb Fix SyntaxWarning in Python 3.8 (KhronosGroup#3388)
2020-07-27 bclayton CMake: Enable building with BUILD_SHARED_LIBS=1 (KhronosGroup#3490)
2020-07-27 dneto Avoid operand type range checks (KhronosGroup#3379)
2020-07-27 jaebaek Preserve debug info in scalar replacement pass (KhronosGroup#3461)
2020-07-27 pierremoreau Update OpenCL capabilities validation (KhronosGroup#3149)
2020-07-27 stevenperron build(deps): bump lodash from 4.17.15 to 4.17.19 in /tools/sva (KhronosGroup#3596)
2020-07-27 antonikarp spirv-fuzz: adds TransformationReplaceLoadStoreWithCopyMemory (KhronosGroup#3586)
2020-07-27 jaebaek Preserve OpenCL.DebugInfo.100 through private-to-local pass (KhronosGroup#3571)
2020-07-27 stefanomil spirv-fuzz: Relax type checking for int contants (KhronosGroup#3573)
2020-07-27 stefanomil spirv-fuzz: Generalise transformation access chain (KhronosGroup#3546)
2020-07-27 stefanomil spirv-fuzz: Split blocks starting with OpPhi before trying to outline (KhronosGroup#3581)
2020-07-27 afdx spirv-fuzz: Set message consumer in replayer when shrinking (KhronosGroup#3591)
2020-07-24 vasniktel spirv-fuzz: Don't use default parameters (KhronosGroup#3583)

Created with:
  roll-dep third_party/spirv-tools

* Add in missing expectations update
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants