Page MenuHomePhabricator

[IPRA] Interprocedural Register Allocation - Analysis Passes

Authored by vivekvpandya on May 28 2016, 3:12 AM.


 This commit addes pass to change CodeGen order to be bottom up order on Call Graph. The patch for the same has been provided by dear Mehdi Amini.
	This commit added required analysis passes for IPRA.
 1) lib/CodeGen/RegUsageInfoCollector.cpp (MachineFunction Pass) to create RegMask based on actual register usage, scheduled at POST-RA
 2) lib/CodeGen/RegisterUsageInfo.cpp (Immutable Pass) to store RegMask details for functions which has been processed in bottom up order on Call Graph, Scheduled before RegAllocation.
 This commit also adds a method setRegMask() to MachineOperand class.
 This commit also adds command line option to enable IPRA -enable-ipra and debug type "ip-regalloc".
 Changes to adher to coding standards, correction for ownership of RegMask vector in related functions.

Diff Detail

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
hfinkel added inline comments.May 31 2016, 6:22 PM
10–11 ↗(On Diff #59113)

How about:

// This pass is required to take advantage of the interprocedural-register-allocation infrastructure.
15 ↗(On Diff #59113)

If you change from using a StringMap, update this comment.

54 ↗(On Diff #59113)

I'd also prefer a GlobalVariable * here, as that currently establishes our canonical function identify. If we work to further separate the MI level from the IR level, I suspect we'd establish some other function object which would have pointer-based identify, and we can always then update this code to use that instead.

mehdi_amini added inline comments.May 31 2016, 6:31 PM
54 ↗(On Diff #59113)

Since MatzeB commented about the allocation in std::vector in the MachineFunctionPass, it seems equally important to override doInitialization(Module &M) in order to reserve the size of the map with the number of functions defined in the module, and doFinalization to clear the map.
(clearing the map is actually a correctness issue)


What is regMaskSize on ARM and X86?
Before moving on with stack allocation here, I think we have to consider that:

  • First this is ran once per function, so having one malloc per function during codegen does not make it an expensive analysis.
  • Second the vector will be moved in the immutable pass map. So having a SmallVector makes it less inefficient to move and store (we may not want to have a DenseMap anymore, and thus we'd have to make an extra malloc there!).
vivekvpandya marked an inline comment as done.May 31 2016, 10:34 PM
vivekvpandya added inline comments.

I will consider it, do we required to revert those changes ? If yes then please suggest easy way, I am using git.

29 ↗(On Diff #58934)

Actually I run git clang-format , but that was after committing my changes so it did not changed any thing. I have applied clang-format on each file.


@qcolombet Could you please explain why is that required?

1–2 ↗(On Diff #59113)

oh yes this is already mentioned in coding standards but I really didn't check for it.


Isn't this will be called by method generated due to macroINITIALIZE_PASS_BEGIN ?


Have thought of any thing for this?


I believe CallGraphWrapperPass is required, though I have not look at this code closely as it was given by you :D


No these dependencies are not required, I am yet to find why not technically but I just removed it and compiled llvm again and things are working.

101 ↗(On Diff #59113)

I thought it is not for primitive type. I will change it.

vivekvpandya marked 2 inline comments as done.May 31 2016, 10:36 PM
mehdi_amini added inline comments.May 31 2016, 11:16 PM
30 ↗(On Diff #59113)

git clang-format takes a commit range, so you can format patches that are already committed.
(i.e, git clang-format HEAD~ formats the last commit, you can just amend it afterward)


If there is something in the macro expansion that makes you think it is called, please elaborate.

vivekvpandya added inline comments.Jun 1 2016, 6:05 AM

No, I look carefully at that macro it provides definition for initialize.. method but yes some where we need to call that method. Also I haven't mentioned this pass as dependency for any other pass with INITIALIZE_PASS_DEPENDENCY other wise it can call that function. Now I am also having same question as you.

vivekvpandya added inline comments.Jun 1 2016, 11:41 AM
283 ↗(On Diff #59113)

@hfinkel X86RegUsageInfoPropagate.cpp will be generic pass soon then I will do this change too.

vivekvpandya edited edge metadata.

Correction in typos , more adhering to coding standards.
PhysicalRegisterUsageInfo.cpp -> RegisterUsageInfo.cpp
DenseMap of GlobelVariable * to RegMask is used instead of StringMap.
DummyCGSCCPass moved to CallGraphSCCPass.h and .cpp

We're getting there, the patch is looking really good now! :)

Still a little bit of work ahead, see inline comments.


Describe the class with a doxygen comment.


Do not repeat the name of the function in the doxygen comment (other places that do it are outdated).




You shouldn't introduce implementation details in high-level description.


It is a good practice to decoupled software component. Having separate patches helps to make sure we indeed have correctly separated the components.
It also forces to make sure the component are individually testable, and make sure we actually test them.

So I agree with Quentin on the principle, and I think it is also a good exercise for you to split the patch an submit the analysis alone and tested. Have a look at "CostModelAnalysis::print()" in lib/Analysis/CostModel.cpp and see how it is tested in test/Analysis/CostModel/X86/cast.ll




Why "compile time"? I'd just write "Enable inter-procedural register allocation"


You forgot to remove this hunk

vivekvpandya added inline comments.Jun 3 2016, 9:25 PM

@mehdi_amini I understand what you explain above but here I think RegisterUsageInfo is not tastable alone because it just holds RegMasks, RegisterInfoCollector is a trigger to IP regalloc and both of them can be tested together. Also to test X86RegUsageInfoPropagate it requires both of the above mentioned passes. But we can separate patches for RegisterUsageInfo + InfoCollector and X86RegUsageInfoPropagate ( condition that first patch is required to test second one) .
Is there any better plan in your mind?

mehdi_amini added inline comments.Jun 3 2016, 10:06 PM

Splitting in two is what I had in mind: the analysis part on one side, the transformation part on another.

vivekvpandya added inline comments.Jun 3 2016, 10:19 PM

Just to make sure RegisterUsageInfo.cpp and RegUsageInfoCollector.cpp both are part of analysis so there is not need of separate patch for them but I will separate changes related to X86RegUsageInfoPropagate.cpp in other patch.

@mehdi_amini I have made all suggested changes , I am writing a simple test for RegUsageInfoCollector so that next review you can also look at that. Thanks for your patience.

vivekvpandya retitled this revision from [IPRA] Interprocedural Register Allocation to [IPRA] Interprocedural Register Allocation - Analysis Passes.
vivekvpandya updated this object.

patch is splited into analysis and optimization pass. Simple test cases has been added.

mehdi_amini added inline comments.Jun 5 2016, 10:35 AM

add a method print() like other analysis, and call it here behind a flag.






I don't like that we can't pass the test in release mode. I suggested that the dump occurs in doFinalization() for the analysis pass (i.e. PhysicalRegisterUsageInfo). You need to implement a proper cl::opt that controls a dump there, that could be used in release mode.


I'm worried that we don't provide any stability guarantee on the numbers printed here.
Having a nicer textual form would be better.
I just don't see how to do it other than keep a pointer to the TRI in the DenseMap in the immutable pass to be able to get the register name.

vivekvpandya added inline comments.Jun 5 2016, 10:46 AM

Aren't we refering


as analysis pass,


is there for keeping data around.


If RegUsageInfoCollector is considered as analysis pass then we can add cl::opt into that file and have analysis printed from that.

mehdi_amini added inline comments.Jun 5 2016, 10:50 AM

Technically in LLVM the analysis is the pass that you require and query the result from (i.e. a pass you're using as getAnalysis()). But yeah terminology can be fuzzy.

vivekvpandya added inline comments.Jun 5 2016, 10:52 AM

SO What is your suggestion? Which file should be changed?

mehdi_amini added inline comments.Jun 5 2016, 10:55 AM

I think I already told you: the way analysis are tested at the IR level is using the -analyze flag in opt. Since we don't have -analyze in llc, the closest I can imagine is to implement the analysis (in the LLVM sense) with the "print(...)" method as other analyses, and call it in doFinalization() when a cl::opt flag is set.

vivekvpandya added inline comments.Jun 5 2016, 11:57 AM

Will TRI pointer assigned a value by the MachineFunction pass ? Or Is there any way to get TargetMachine or TargetRegisterInfo from Module object? Also if PReg name is required to be printed then MCRegisterInfo will be required.

a new command line option dump-regusage has been added so that reg usage information can be printed in release build. The test case is also changed accordingly.

mehdi_amini added inline comments.Jun 6 2016, 1:20 PM

Is the TRI dependent on the Target or the SubTarget?
If it is the latter, it can change on each function and thus needs to be in the map (at which point we better have a dedicated class for the map value)


Same question.


I'm not sure the name of the option is great, but I'll leave the naming to Quentin/Matthias.


Can you implement the print in a separate print method with the same signature as the other analyses for consistency?
And call it from here being the DumpRegUsage flag?

mehdi_amini added inline comments.Jun 6 2016, 10:21 PM

Mdl is not usual, M alone is more common (or sometimes Mod)

vivekvpandya added inline comments.Jun 6 2016, 10:27 PM

Ok I will take care for naming , but that would be not required if we are going with Function * , because MF.getFunction() would be enough.

mehdi_amini added inline comments.Jun 6 2016, 10:28 PM

This is not the right API: getNamedGlobal is for global *variables*, not function.


Add an assertion that MFGlobalVar is not null (and the name isn't very explicit)

vivekvpandya added inline comments.Jun 6 2016, 10:31 PM

now I think such assertion wold be for Function *, right ?

vivekvpandya added inline comments.Jun 6 2016, 11:17 PM

I tried out

PRUI->storeUpdateRegUsageInfo(Mdl->getGlobalVariable(MF.getFunction()->getName(),true), std::move(RegMask));


PRUI->storeUpdateRegUsageInfo(Mdl->getGlobalVariable(MF.getFunction()->getName()), std::move(RegMask));

but both returns nullptr for some functions.

mehdi_amini added inline comments.Jun 7 2016, 8:46 AM

My previous comment called out the fact that you were using an API for global *variables* instead of function, and you replaced with a call to getGlobalVariable?

There is a getFunction() API on the module that returns only functions, or there is a getNamedValue() that will return any symbol.

However you have MF.getFunction(), so you should not call any of these.

RegMasks uses Function * as key, print method and TargetMachine * have added to RegisterUsageInfo. Command line option -dump-regusage has been renamed to -print-regusage, test case is also updated to reflect the changes.

mehdi_amini added inline comments.Jun 7 2016, 6:00 PM

pair is not coding-convention friendly.

Also you are iterating on a map that is keyed on pointer values, which does not provided any ordering guarantee. Even with names as keys, the map is unordered anyway.
You need to generate a vector and sort it first.


This test is not OK, for the reasons I explained when I provided the other test (stability).

Test case changed to simple test case which is originally provided by Mehdi Amini, print() now sorts analysis details before printing in RegisterUsageInfo.cpp

mehdi_amini added inline comments.Jun 8 2016, 9:01 PM

I think MatzeB mentioned that TRI is a subclass of MCRI, so I'm not sure why you're using MCRI at all while you have TRI.


Why aren't you using MachineOperand::clobbersPhysReg here?


What will be printed for bar1 and bar2?
Add the CHECK lines here.

git clang-formated , test case changes, MCRI is not required , clobberedReg expression removed.

mehdi_amini added inline comments.Jun 9 2016, 9:03 AM

Doxygen the two public API above.


No braces


No braces.


No braces


No braces

mehdi_amini added inline comments.Jun 9 2016, 9:04 AM

trailing whitespace here.

Hi Vivek,

I was thinking about debug ability and usability of the produced code.
Something to consider in a following patch would be to add in the assembly output comments at the beginning of the function and/or related call site of the function listing what are the register preserved by the function.

The rationale is that now if we play with assembly files produced by different optimization phase, we want a quick way to check if two functions are equivalent.
Let say we have two assembly files produced for the same application:

  • bad.s which fails, produced with ipra
  • good.s which works, produced without ipra

When bisecting which function causes the failure, it is important to know if it is fine to take a function foo from good.s and replace it into bad.s. This may not be possible if the preserve register are not compatible.


vivekvpandya added a comment.EditedJun 9 2016, 10:49 AM

@qcolombet. It will be very help full, I will look into that. Do we need to keep it default or a separate switch to get those comments ?

mehdi_amini accepted this revision.Jun 9 2016, 1:28 PM
mehdi_amini edited edge metadata.

LGTM, with one inline comment.


Strip the "this method is provided to" everywhere.
And here add that it will return null if the function is not known.

This revision is now accepted and ready to land.Jun 9 2016, 1:28 PM
vivekvpandya edited edge metadata.

inline-asm related test case added Thanks to Mehdi Amini, and previous test case modified so that it do not fail due to transformation pass for IPRA.

Do you have commit access?

No I do not have commit access.

This revision was automatically updated to reflect the committed changes.