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

[Coverage] Let Decision take account of expansions #78969

Merged
merged 12 commits into from
Feb 2, 2024

Conversation

chapuni
Copy link
Contributor

@chapuni chapuni commented Jan 22, 2024

The current implementation (D138849) assumes Branch(es) would follow after the corresponding Decision. It is not true if Branch(es) are forwarded to expanded file ID. As a result, consecutive Decision(s) would be confused with insufficient number of Branch(es).

Expansion will point Branch(es) in other file IDs if Expansion is included in the range of Decision.

Fixes #77871

@chapuni chapuni requested a review from ornata January 22, 2024 13:09
@evodius96
Copy link
Contributor

I'd be OK going this direction as opposed to #78819, since it doesn't have to scan ahead to add branch regions, but it does add new complexity to the tracking. Can you also post your tests?

Copy link
Contributor Author

@chapuni chapuni left a comment

Choose a reason for hiding this comment

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

I have rewritten DecisionRow and added comments.

Tests are not ready. Please be patient.

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
: DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()),
DecisionEndLoc(Decision.endLoc()) {}

/// Determine whether `R` is included in `DecisionRegion`.
Copy link

Choose a reason for hiding this comment

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

Nit:

E.g.

\returns true if \p R is included in DecisionRegion

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 haven't written doxygen comments for long time. Please point out any mistakes.

Copy link
Member

Choose a reason for hiding this comment

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

Doxygen comments are not required. I think much new code doesn't use Doxygen...

});
}

enum class UpdateResult {
Copy link

Choose a reason for hiding this comment

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

This should be documented

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 didn't do since I thought the enums are descriptive.

Copy link
Contributor Author

@chapuni chapuni left a comment

Choose a reason for hiding this comment

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

TODO:

  • Revise comments in the latter half
  • Construct tests

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
});
}

enum class UpdateResult {
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 didn't do since I thought the enums are descriptive.

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
MCDCDecision = &Region;
NumConds = Region.MCDCParams.NumConditions;
// Start recording `Region` as the `Decision`
Decisions.emplace_back(Region);
Copy link

Choose a reason for hiding this comment

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

why emplace_back instead of push_back?

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 thought it would be made smaller if the constructor has default constructors for SmallVector.

llvm/lib/ProfileData/Coverage/CoverageMapping.cpp Outdated Show resolved Hide resolved
NumConds = Region.MCDCParams.NumConditions;
// MCDCDecisionRegion should be handled first since it overlaps with
// others inside.
if (MCDCDecisions.registerDecision(Region))
Copy link
Member

Choose a reason for hiding this comment

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

I think it reads better if the CounterMappingRegion::MCDCDecisionRegion guard is moved here. The same applies to MCDCDecisions.processRegion(Region);

I.e. we check different types of Region here and dispatch actions to MCDCDecisions.

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 did because of symmetry to processRegion. I can rework this.

processRegion(const CounterMappingRegion &Region) {

// Record ExpansionRegion.
if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
Copy link
Member

@MaskRay MaskRay Jan 28, 2024

Choose a reason for hiding this comment

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

I think it's clearer to move ExpansionRegion handling to the caller.

This class then doesn't need to check Region.Kind

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 wanted to make MCDCDecisionRecorder richer, since it simply encapsulated SmallVector<DecisionRecord> Decisions.

@MaskRay
Copy link
Member

MaskRay commented Jan 29, 2024

The description is too brief for the involved problem:) Feel free to incorporate my comment #77871 (comment) into the description/commit message.

@whentojump
Copy link
Member

whentojump commented Jan 31, 2024

Hey everyone. Thanks for this great work!

Will you please add this test:

#define C c
#define D 1
#define E (C != a) && (C > a)
#define F E
#define G(x) x

void __attribute__((noinline)) func1(void) { return; }

void __attribute__((noinline)) func(int a, int b, int c) {
  if (a && D && E || b)
    func1();
  if (b && D)
    func1();
  if (a && (b && C) || (D && F))
    func1();
  if (G(a) && G(b))
    func1();
}

int main() {
  func(2, 3, 3);
  return 0;
}

Currently it doesn't seem to work on my side. I'm also glad to investigate that.


Revise: I further minimize the problematic G. As a bit of context, my use case is code like this. (See also one of my immature PR here)

@MaskRay
Copy link
Member

MaskRay commented Jan 31, 2024

I think this is correct, but the consumer side complexity makes me wonder whether the additional complexity makes our "boring algorithm" overall worse than GCC https://gcc.gnu.org/pipermail/gcc-patches/2024-January/644269.html

(From https://maskray.me/blog/2024-01-28-mc-dc-and-compiler-implementations)

Pros:

  • Easier to understand
  • Each condition instrumentation adds just one single bitwise OR instruction, instead of possibly three (one bitwise AND plus two bitwise OR).

Cons:

  • More bits to encode N conditions (2**N vs. 2*N)
  • More metadata to encode the reduced ordered BDDs, required by the reader to compute independence pairs
  • Determining independent pairs involves a brute-force algorithm in llvm-cov, which has a high time complexity but probably acceptable due to the limited condition count.

@chapuni
Copy link
Contributor Author

chapuni commented Jan 31, 2024

@whentojump Could you try #78966, too?

@MaskRay

I think this is correct,

What about "this"?

@evodius96
Copy link
Contributor

evodius96 commented Jan 31, 2024

I think this is correct, but the consumer side complexity makes me wonder whether the additional complexity makes our "boring algorithm" overall worse than GCC

From the perspective of embedded, I think it makes more sense to keep the instrumentation light and off-load processing in llvm-cov. Also, I think we can look at better modularization of metadata sections (I.e. keeping them in the executable but out of what is loaded in memory, which is what we do downstream and was discussed at the last Developers' meeting embedded workshop). Even going beyond six conditions isn't that bad, but I don't think 32 conditions (as mentioned in GCC context) is at all typical, especially in embedded context. I know we want this to work outside of embedded as well, but we also have to keep in mind when MC/DC is not only useful but practical to fulfill.

Conceivably (just thinking out loud) we may also be able to enable different modes that balance the tradeoffs differently between the different algorithms.

@whentojump
Copy link
Member

@whentojump Could you try #78966, too?

These two PRs combined worked smoothly for my case. Thanks a lot!

@chapuni
Copy link
Contributor Author

chapuni commented Feb 1, 2024

Thanks @MaskRay . I know I have to do;

  1. Rewrite the description (and possibly the subject)
  2. Regenerate and test the testcase.o

By the way, do you have any comments in #78966?

@chapuni chapuni changed the title [Coverage] Rework Decision/Expansion/Branch [Coverage] Let Decision take account of expansions Feb 2, 2024
@chapuni chapuni merged commit d912f1f into llvm:main Feb 2, 2024
4 checks passed
@chapuni chapuni deleted the mcdc/expansion77871 branch February 2, 2024 11:34
@evodius96
Copy link
Contributor

@chapuni Can you backport this onto 18.x branch along with #78966?

llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Feb 3, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
(cherry picked from commit d912f1f)
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Feb 5, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
(cherry picked from commit d912f1f)
agozillon pushed a commit to agozillon/llvm-project that referenced this pull request Feb 5, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
(cherry picked from commit d912f1f)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
(cherry picked from commit d912f1f)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
(cherry picked from commit d912f1f)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
The current implementation (D138849) assumes `Branch`(es) would follow
after the corresponding `Decision`. It is not true if `Branch`(es) are
forwarded to expanded file ID. As a result, consecutive `Decision`(s)
would be confused with insufficient number of `Branch`(es).

`Expansion` will point `Branch`(es) in other file IDs if `Expansion` is
included in the range of `Decision`.

Fixes llvm#77871

---------

Co-authored-by: Alan Phipps <a-phipps@ti.com>
(cherry picked from commit d912f1f)
@pointhex pointhex mentioned this pull request May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Malformed MC/DC Coverage record with macro definitions
5 participants