This is an archive of the discontinued LLVM Phabricator instance.

[IROutliner] Allowing PHINodes in Exit Blocks
ClosedPublic

Authored by AndrewLitteken on Jul 28 2021, 1:09 PM.

Details

Summary

In addition to having multiple exit locations, there can be multiple blocks leading to the same exit location, which results in a potential phi node. If we find that multiple blocks within the region branch to the same block outside the region, resulting in a phi node, the code extractor pulls this phi node into the function and uses it as an output.

We make sure that this phi node is given an output slot, and that the two values are removed from the outputs if they are not used anywhere else outside of the region. Across the extracted regions, the phi nodes are combined into a single block for each potential output block, similar to the previous patch.

Diff Detail

Event Timeline

AndrewLitteken created this revision.Jul 28 2021, 1:09 PM
AndrewLitteken requested review of this revision.Jul 28 2021, 1:09 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 28 2021, 1:09 PM

Updating to handle a global in the split phi node, and correcting which successor gets reassigned when creating a new aggregate phi block.

Updating to clean up the patch, splitting into several patches, and adding more tests.

AndrewLitteken added inline comments.Aug 24 2021, 1:04 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
940

clang-format

paquette added inline comments.Sep 8 2021, 10:52 AM
llvm/lib/Transforms/IPO/IROutliner.cpp
56

Why this number?

272
757

run on?

788

avoid double negative with variable name?

798

this comment is a bit of a run-on

823

if you rename NotOnlyUsedInExitBlocks to OnlyUsedInExitBlocks and change the code accordingly, you can just return that variable.

848

in for loops like this, it's more idiomatic to write

for (unsigned I = 0, E = PN.getNumIncomingValues(); I < E; ++I)
   ...
855

Using empty() would be more explicit here.

857

Don't need else since you would have continued already

883

Add comments for what these types represent?

920

Can this use

if (any_of(...))
  return None;

?

933

Maybe pull PN->getNumIncomingValues into a variable to avoid recalculating it across the two loops?

937

actually, can this loop be merged into the previous one?

943

what happens if BBGVN doesn't have a value?

1137

comments?

1187

this looks like it could be

bool GVNMatches = all_of(...);

or even better:

if (all_of(...))
   return CurrPN;
1926
1990

What happens if OVGN doesn't have a value?

AndrewLitteken added inline comments.Sep 8 2021, 11:32 AM
llvm/lib/Transforms/IPO/IROutliner.cpp
56

It has to count backwards from -3 (or rather the unsigned version) since -2, and -1 are reserved as tombstone and empty values for unsigned integers in the DenseMap. I'll add it as a comment.

937

yes, I think so. But I think enough values would need to be passed into the lambda for this that I don't think it makes sense to put it in any_of if that's the case.

943

It shouldn't since the block of a Phi node containing should be the target of some branch in the region, and will have been marked in that case, but I will add an assertion to make sure it exists.

1990

Right now, it will throw an assertion in the Optional code that there isn't a value.

Updating based on initial comments.

paquette added inline comments.Sep 14 2021, 10:35 AM
llvm/lib/Transforms/IPO/IROutliner.cpp
59

Can we assert somewhere that -2 and -1 are actually used by DenseMap?

774

avoid recalculating loop invariant

779

probably don't need the variable here

781

probably don't need the variable here either

808

drop braces

845

we calculate IncomingVals.size()s twice here

how about

unsigned NumIncoming = IncomingVals.size();

if (NumIncoming == 0)
  continue;

if (NumIncoming == 1) {
   ...
}
848

comments here?

897
928

comment?

1151

can you do this like

if (!AdjustArgNo) {
// The call instruction was already removed when we created a call to an outlined function. So, we have all the arguments already. Just grab the argument.
IVal = CI->getArgOperand(ArgNum);
continue;
}

if (Region.AggArgToConstant.count(ArgNum)) {
  // The argument is/isn't a constant...
  // do stuff
  continue;
}

// Other case
1197

use phis()?

1214

avoid recalculating loop invariant

1220

getFirstNonPHI can return nullptr. assert?

1925

comment?

1935

why is there an assert below and not here?

1981

code duplication with change above?

llvm/lib/Transforms/IPO/IROutliner.cpp
59

I'm not sure where to do that? They are representing the tombstone value, and empty key value, so you can't use them as keys for other items.

1151

There is a shared action between all three of the cases. I can clean up what the checks are, but I don't think it makes sense to use this pattern to continue and then duplicate the canonical number finding below in each case. These cases are to make sure we are getting the canonical number for the correct value, and then we can use the same code below to find the canonical number.

paquette added inline comments.Sep 14 2021, 2:45 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
59

The MachineOutliner does:

InstructionMapper() {
  // Make sure that the implementation of DenseMapInfo<unsigned> hasn't
  // changed.
  assert(DenseMapInfo<unsigned>::getEmptyKey() == (unsigned)-1 &&
         "DenseMapInfo<unsigned>'s empty key isn't -1!");
  assert(DenseMapInfo<unsigned>::getTombstoneKey() == (unsigned)-2 &&
         "DenseMapInfo<unsigned>'s tombstone key isn't -2!");
}
AndrewLitteken marked 15 inline comments as done.Sep 15 2021, 9:08 AM

Updating based on comments

paquette added inline comments.Sep 15 2021, 1:02 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
774

don't recalculate loop invariant

also can this just be an any_of?

785

this comment could be more succinct, like "Check if the value is used by any instructions outside of the region."

786

this could probably also be an any_of

793

This sentence is pretty long and kind of confusing. Can you simplify it?

798

can you explain this a bit more?

813

this is kind of wordy, maybe rewrite it like

"Test whether \p ExitBlock contains any PhiNodes that should be considered outputs. PhiNodes should be outputs when...(blah)"

818

the comments here don't line up with the variable names in the function

this could be a more descriptive name as well, like "PotentialExitsFromRegion"

819

this could be named "BasicBlocksInRegion"

822

I think this variable would be better-named "OutputsReplacedByPhis"

824

maybe this could have a more descriptive name too, like "OutputsWithNonPhiUses" or "OutputsThatCouldNotBeReplacedWithPhis"

(second option is kind of wordy, but it describes what's happening pretty well)

835

don't recalculate loop invariant

836

these could use more descriptive names

893
902

this could probably be called "BasicBlocksInRegion" or something

911

can this be named Cand or something?

914

since you don't use the index here, could this just be a loop like this?

for (Value *Incoming : PN->incoming_values()) {
   ...
}
917

comment is pretty wordy, split it up?

920

can you pull C.getGVN(V) into a variable, since you reuse it below?

921–922

pull Group.ArgumentTypes.size() into a variable and reuse it? it's calculated 4 times in this function.

927

is this guaranteed to have a value?

928

simpler?

930

can you add a comment explaining what you're going to do in this portion of the function here?

930
932
934

this comment has a lot of run-ons; can you split it up a little?

936

this comment is confusing. Is it two PhiNodes or one?

938

can you expand on the store sets a little more? I feel like it's kind of out of nowhere.

1066

simpler:

Find or create a BasicBlock in the outlined function containing PhiBlocks for \p RetVal.

1077

I think this could be called like "PhiBlockForRetVal"

1078

this could also use a more descriptive name

1102
  • this can be a one-liner
  • I think this should use cast?
1106

don't recalculate loop invariant

1118

simpler:

\returns The Value representing \p A at the call location for some outlined function.

1122

maybe this should be "the region corresponding to the outlined function" or something?

1123

or even simpler:

"True when \p A's location must be adjusted. This happens when... (stuff)."

I think this could also be named something like "HasAlreadyBeenReplacedWithOutlinedCall" or something?

1125
1158

this could use a better name (like above)

1161

formatting

1178

is this guaranteed to have a value?

1196

should this ever be null? can it be a reference?

1203

unfinished comment?

1206

this could use a more descriptive name or a comment

1222
PHINode *cloneImpl() const;

do you have to cast here? static_cast seems wrong too

1226

just call this IncomingVal?

1227

just call this IncomingBlock?

1231

call this FirstNonPhi?

1233

this could use a more descriptive name?

1916

this sentence is confusing

\returns The Value represented by a canonical number \p OutputCanon in \p Region.

I assume this is an output as well? Should this function be called "findOutputValueInRegion" or something?

Updating based off of newest comments.

paquette added inline comments.Sep 15 2021, 5:17 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
757

we can be even more concise here:

\returns true if \p V has any uses outside its region other than \p PN.
766

this is redundant, since you mention it in the first part of the comment.

774

Would it make sense to use a SmallVector here?

777

couple probably be a one-liner?

return (Idx != PhiLoc || V == PN.getIncomingValue(Idx) || !BlocksInRegion.contains(PN.getIncomingBlock(Idx)));
788

Return the any_of rather than using an if?

821

"it" is unclear IMO

also update comment for updated variable names?

1102

braces

1105

comment on the successors?

1207
paquette added inline comments.Sep 15 2021, 5:21 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
1158

update comment to reflect variable name?

1916
1917

"one the first incoming value" doesn't parse for me

Updating comment variables and few stylistic points.

paquette added inline comments.Dec 20 2021, 12:12 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
283

This is being computed twice?

1094
1099

This comment would be more useful if it said something like "find the predecessors in order to (blah)"

1128

I think I'd prefer two functions here rather than one with a flag? It'd be clearer what's going on.

Something like

  • getPassedArgumentAndAdjustArgumentLocation(Argument *A, OutlinableRegion &Region)
  • getPassedArgumentInAlreadyOutlinedFunction(Argument *A, const OutlinableRegion &Region)

Also I think A can probably be const?

Updating based on comments

Updating diff with context

paquette added inline comments.Jan 5 2022, 4:02 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
916

probably want a comment here explaining what's going on?

943

comment for this part?

1136

This can probably be a one-liner?

1160

Can probably eliminate the variable.

1266

Can probably just do this as a one-liner?

paquette added inline comments.Jan 5 2022, 4:10 PM
llvm/lib/Transforms/IPO/IROutliner.cpp
1085
1234

Missing /* ReplacedWithOutlinedCall = */ on bool param?

Updating with one-liners and extra comments.

ormris removed a subscriber: ormris.Jan 18 2022, 4:24 PM
This revision is now accepted and ready to land.Jan 21 2022, 2:20 PM
This revision was landed with ongoing or failed builds.Jan 25 2022, 9:34 AM
This revision was automatically updated to reflect the committed changes.