This is an archive of the discontinued LLVM Phabricator instance.

[clang-format][NFC] Code Tidies in UnwrappedLineFormatter
ClosedPublic

Authored by HazardyKnusperkeks on Dec 3 2021, 11:46 AM.

Details

Summary
  • Give I[1] and I[-1] a name:
    • Easier to understand
    • Easier to debug (since you don't go through operator[] everytime)
  • TheLine->First != TheLine->Last follows since last is a l brace and first isn't.
  • Factor the check for is(tok::l_brace) out.
  • Drop else after return.

Diff Detail

Event Timeline

HazardyKnusperkeks requested review of this revision.Dec 3 2021, 11:46 AM
HazardyKnusperkeks created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptDec 3 2021, 11:46 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
curdeius accepted this revision.Dec 3 2021, 12:58 PM

LGTM. Don't forget to reformat please.

This revision is now accepted and ready to land.Dec 3 2021, 12:58 PM

How about naming I[-1] as well? And maybe I[i + 1] too?

owenpan accepted this revision.Dec 3 2021, 6:55 PM
HazardyKnusperkeks edited the summary of this revision. (Show Details)

Fixed formatting and added a name for I[-1].

I[i + 1] is used in the loop condition, which also checks if i + 1 is valid, so do not give a name here.

owenpan accepted this revision.Dec 4 2021, 2:27 PM

LGTM.

@HazardyKnusperkeks, it *seems* as if this commit (or one of others indicated on Changes tab of the link below) provoked failures in ASan. But it could be something else.
https://lab.llvm.org/buildbot/#/builders/5/builds/16734
Could you have a look?

@HazardyKnusperkeks, it *seems* as if this commit (or one of others indicated on Changes tab of the link below) provoked failures in ASan. But it could be something else.
https://lab.llvm.org/buildbot/#/builders/5/builds/16734
Could you have a look?

Okay, I don't have access to ASAN or so, I'm using MinGW on Windows. But I suspect it is the Assignment of the PreviousLine since this is not existent every time. So I see the following solutions:

  1. Only name NextLine, and use I[-1].
  2. const auto HasPreviousLine = I != AnnotatedLines.begin(); const auto &PreviousLine = HasPreviousLine ? *I[-1] : *I; which is safe, since PreviousLine is only used if HasPreviousLine is true, but is a bit confusing. It would get an explaining comment.
  3. Rearrange the statements so that we can have only one check if there is a previous line and define PreviousLine inside that if. It remains to be seen if that's NFC.

I would prefer option 3, but if that would change the behavior would go for option 2.

This revision is now accepted and ready to land.Jan 5 2022, 3:48 AM
curdeius accepted this revision.Jan 5 2022, 5:31 AM

That's look good. And it's a nice clean up with all those repeated checks removed. Don't forget to reformat before landing.

But I suspect it is the Assignment of the PreviousLine since this is not existent every time.

Yep!

So I see the following solutions:

  1. Only name NextLine, and use I[-1].
  2. const auto HasPreviousLine = I != AnnotatedLines.begin(); const auto &PreviousLine = HasPreviousLine ? *I[-1] : *I; which is safe, since PreviousLine is only used if HasPreviousLine is true, but is a bit confusing. It would get an explaining comment.
  3. Rearrange the statements so that we can have only one check if there is a previous line and define PreviousLine inside that if. It remains to be seen if that's NFC.

I would prefer option 3, but if that would change the behavior would go for option 2.

There is option 4: change the type of PreviousLine to a pointer, and replace PreviousLine. with PreviousLine->. (You can rename PreviousLine if you think the naming is inconsistent with NextLine.) This would keep the patch being NFC.

But I suspect it is the Assignment of the PreviousLine since this is not existent every time.

Yep!

So I see the following solutions:

  1. Only name NextLine, and use I[-1].
  2. const auto HasPreviousLine = I != AnnotatedLines.begin(); const auto &PreviousLine = HasPreviousLine ? *I[-1] : *I; which is safe, since PreviousLine is only used if HasPreviousLine is true, but is a bit confusing. It would get an explaining comment.
  3. Rearrange the statements so that we can have only one check if there is a previous line and define PreviousLine inside that if. It remains to be seen if that's NFC.

I would prefer option 3, but if that would change the behavior would go for option 2.

There is option 4: change the type of PreviousLine to a pointer, and replace PreviousLine. with PreviousLine->. (You can rename PreviousLine if you think the naming is inconsistent with NextLine.) This would keep the patch being NFC.

I'm open for that, but I think the current diff (plus corrected formatting) is better. And at least according to our tests it is NFC.

owenpan added a comment.EditedJan 7 2022, 3:36 AM

Moving the handling of empty record blocks might be non-NFC? Maybe option 4 for now and the refactoring in another patch?

clang/lib/Format/UnwrappedLineFormatter.cpp
360

Is TheLine->First != TheLine->Last redundant?

381

I don't think you can drop else here.

388

Ditto.

406–431

Handling empty record blocks here instead of earlier may have unknown side effects?

HazardyKnusperkeks planned changes to this revision.Jan 7 2022, 11:43 AM
HazardyKnusperkeks marked 2 inline comments as done.

Maybe option 4 for now

So I can get it through.

and the refactoring in another patch?

Probably won't do it.

clang/lib/Format/UnwrappedLineFormatter.cpp
388

Same.

406–431

Of course it may have side effects.

HazardyKnusperkeks marked 2 inline comments as done.

Updated, now using a pointer (potential null) for PreviousLine.

This revision is now accepted and ready to land.Jan 16 2022, 1:14 PM
clang/lib/Format/UnwrappedLineFormatter.cpp
360

This seems to be an error on my side.

owenpan added inline comments.Jan 16 2022, 6:42 PM
clang/lib/Format/UnwrappedLineFormatter.cpp
215

I would move this line to just before handling empty record blocks below.

266–267

I'd either leave this lambda alone or further simplify it as suggested here.

316

Drop the I if you decide to further simplify the lambda as suggested above.

381

I don't think you can drop else here.

I was wrong. For some reason, I didn't see the return statement.

388

I missed the return here as well.

403–414

If you want, you can factor out PreviousLine && TheLine->First->is(tok::l_brace) and even combine the two if statements as they both return 0.

HazardyKnusperkeks marked 5 inline comments as done.Jan 16 2022, 11:47 PM
HazardyKnusperkeks added inline comments.
clang/lib/Format/UnwrappedLineFormatter.cpp
215

I'd rather keep the definitions close together.

266–267

I'm no fan of capturing everything, but some things I've applied.

403–414

Kept the two cases apart for their comments.

HazardyKnusperkeks marked an inline comment as done.
owenpan added inline comments.Jan 17 2022, 1:39 AM
clang/lib/Format/UnwrappedLineFormatter.cpp
215

If it were just a simple initialization, it wouldn't matter much. However, it would be a bit wasteful as PreviousLine always gets computed here even if the function may return before the pointer would get chance to be used. If you really want to keep all related definitions together, wouldn't you want to move lines 214-215 up to right after line 211?

266–267

[&] doesn't capture everything. It only captures the variables that are used in the lambda body. That being said, I'm okay with explicitly capturing each one.

HazardyKnusperkeks marked 3 inline comments as done.Jan 17 2022, 12:08 PM
HazardyKnusperkeks added inline comments.
clang/lib/Format/UnwrappedLineFormatter.cpp
215

In a release build I'm betting that the compiler is smart enough to never calculate PreviousLine and that performance doesn't really matter was shown in D116318.

But yeah moving it up to TheLine is consistent and will do.

owenpan added inline comments.Jan 17 2022, 6:16 PM
clang/lib/Format/UnwrappedLineFormatter.cpp
215

In a release build I'm betting that the compiler is smart enough to never calculate PreviousLine

No compiler will (or should) skip generating code that calculates PreviousLine, which may or may not get used at runtime. I'm not aware of any compiler that is smart enough to move the initialization code to just before where the variable is first used.

To illustrate the difference, I compiled the code below with clang++ -Wall -std=c++11 -O3 -S foo.cpp:

#include <vector>

using namespace std;
using Type = vector<int *>;

int f(const Type &V, Type::const_iterator I) {
  const auto *P = I != V.begin() ? I[-1] : nullptr;
  if (I == V.end())
    return 0;
  return *P;
}

The generated code in foo.s includes the following:

	.cfi_startproc
; %bb.0:
	ldr	x8, [x0]
	cmp	x8, x1
	b.eq	LBB0_3
; %bb.1:
	ldur	x8, [x1, #-8]
	ldr	x9, [x0, #8]
	cmp	x9, x1
	b.eq	LBB0_4
LBB0_2:
	ldr	w0, [x8]
	ret
LBB0_3:
	mov	x8, #0
	ldr	x9, [x0, #8]
	cmp	x9, x1
	b.ne	LBB0_2
LBB0_4:
	mov	w0, #0
	ret
	.cfi_endproc

As you can see, the initialization code was neither optimized away nor moved.

When I changed the function body to:

if (I == V.end())
  return 0;
const auto *P = I != V.begin() ? I[-1] : nullptr;
return *P;

The generated code became much simpler:

	.cfi_startproc
; %bb.0:
	ldr	x8, [x0, #8]
	cmp	x8, x1
	b.eq	LBB0_2
; %bb.1:
	ldur	x8, [x1, #-8]
	ldr	w0, [x8]
	ret
LBB0_2:
	mov	w0, #0
	ret
	.cfi_endproc
owenpan added inline comments.Jan 17 2022, 6:27 PM
clang/lib/Format/UnwrappedLineFormatter.cpp
215

and that performance doesn't really matter was shown in D116318.

It wasn't quite the same there as we must pay either in the caller or in the callee. That being said, I agree that the performance hit here would be negligible.

This revision was landed with ongoing or failed builds.Feb 3 2022, 1:56 PM
This revision was automatically updated to reflect the committed changes.
HazardyKnusperkeks marked an inline comment as done.