Page MenuHomePhabricator

First stage of call lowering for Mips fast-isel

Authored by rkotler on Oct 9 2014, 6:17 PM.



This has most of what is needed for mips fast-isel call lowering for O32.
What is missing I will add on the next patch because this patch is already too large.
It should not be doing anything wrong but it will punt on some cases that it is basically
capable of doing.

The mechanism is there for parameters to be passed on the stack but I have not enabled it because it serves as a way for now to prevent some of the strange cases of O32 register passing that I have not fully checked yet and have some issues.

The Mips O32 abi rules are very complicated as far how data is passed in floating and integer registers.

However there is a way to think about this all very simply and this implementation reflects that.

Basically, the ABI rules are written as if everything is passed on the stack and aligned as such.
Once that is conceptually done, it is nearly trivial to reassign those locations to registers and
then all the complexity disappears.

So I have told tablegen that all the data is passed on the stack and during the lowering I fix
this by assigning to registers as per the ABI doc.

This has been my approach and you can line up what I did with the ABI document and see 1 to 1 what
is going on.

Diff Detail

Event Timeline

rkotler updated this revision to Diff 14692.Oct 9 2014, 6:17 PM
rkotler retitled this revision from to First stage of call lowering for Mips fast-isel.
rkotler updated this object.
rkotler edited the test plan for this revision. (Show Details)
rkotler added a reviewer: dsanders.
rkotler added a subscriber: rfuhler.
rkotler updated this object.Oct 9 2014, 6:21 PM
rkotler added subscribers: mcrosier, Unknown Object (MLST).
rkotler updated this object.Oct 9 2014, 6:29 PM
rkotler added a subscriber: ahatanak.

Basic executable test. callabisub.c should be compiled with non fast-isel llvm or normal gcc.

Will make a "make check" version of callabi.c




Eh? What's with all of these?

Have cleaned up the executable test case a bit to make it convert to make check test better.

Am working on the make check test. So far no code bugs have been found in this abi testing.


I have a patch that fixes that with function attributes as in:

static bool CC_Mips16RetHelper(unsigned ValNo, MVT ValVT,
                   MVT LocVT, CCValAssign::LocInfo LocInfo,
                   ISD::ArgFlagsTy ArgFlags, CCState &State)

There was interest in seeing the patch earlier, internally at Mips, so i
uploaded this draft version.

So far no bugs have been found in testing but I'm working on the make
check test and then
need to do my code review before asking for commit permission.

There's no testcase showing up in this diff at all FWIW.


Best to just leave them out for now.

There is a pair of C programs as an attachment.
They are an executable test case.

I'm working on converting one the C programs to a make check test right now.
Hopefully tomorrow I will be ready to push it.

It's an extensive abi test for functions that pass all their arguments
in registers, which
is the extent of the first call lowering putbakc.

Ah, there they are. Yes, best to get that into a .ll file as quick as possible for review.

Yes. I'm working on it.

Lots of cases for mips32 o32 abi. lol.

Yep. It depresses me that anyone still uses it.

I'm still missing a few cases in my test but I will finish this up soon
and make
the .ll test from it.

This is the version of the executable test case that i will do the .ll "make check" test from. The only function that this patch cannot handle is xfid. This is the case of (float, int, double). It's not rocket science to fix this but it's easier to do it on another patch. In this situation the double needs to be loaded into a2,a3. If I have time I will add it to the patch but probably on a small follow on patch.

rkotler updated this revision to Diff 15155.Oct 20 2014, 3:22 PM
rkotler edited the test plan for this revision. (Show Details)

Add the test case for this putback and do some small cleanup of the code.
Still more review to do. It's not ready to push upstream yet.

dsanders edited edge metadata.Oct 21 2014, 6:46 AM

This direction is a big improvement on the custom C++ O32 implementation used by SelectionDAG. I'm not suggesting we do this straight away but I think there are further improvements we can make. In particular, I think we can remove the conversion from stack arguments to register arguments fairly easily.

The main rules that make O32 tricky are:

  1. The fixed portion of a vararg function is unaffected by the use of varargs.
  2. The variable portion of a vararg function is passed using integer registers and the stack only.
  3. The second argument is passed in a floating point register if it is a floating point argument and the first argument was also floating point

1 and 2 are tricky because the tablegen-erated code isn't given information about which arguments are part of the variable portion. The information we need is in ArgListEntry::IsFixed. I've already had to solve this problem to remove our custom implementation of CCState::AnalyzeCallOperands. This change is part of a fairly long WIP branch so here's a link to the commit on my github repo To summarize the approach, MipsCCState (a subclass of CCState) holds a vector containing the values of ArgListEntry::IsFixed for each argument and is populated before calling CCState::AnalyzeCallOperands, we then use CCIf to access this vector from the tablegen-erated code. The same trick is used to gain access to the original argument type so that we can identify f128 arguments.

3 is tricky because the rule depends on outcome of the previous argument. I haven't tried this yet but I believe we can use CCAssignToRegWithShadow to implement the rule. Just to illustrate my thoughts, here is a toy example:

CCIfType<[f32], CCAssignToRegWithShadow<[F12, F14], [A0, A1]>>
CCAssignToRegWithShadow<[A0, A1, A2, A3], [F12AndF14, F12AndF14, F12AndF14, F12AndF14]>

where F12AndF14 is a register containing F12, and F14 as subregisters. I believe this behaves as follows:

  • Given (i32 %a, f32 %b): %a is allocated to A0 and prevents the allocation of F12 and F14. %b is allocated to A1.
  • Given (f32 %a, f32 %b): %a is allocated to F12 and prevents the allocation of A0. %b is allocated to F14 and prevents the allocation of A1
  • Given (f32 %a, i32 %b): %a is allocated to F12 and prevents the allocation of A0. %b is allocated to A1 and prevents the allocation of F14.

The 16-bytes reserved space is allocated by the prologue of the callee not the caller.

However, I discovered something strange in the SelectionDAG implementation this morning. MipsTargetLowering::LowerCall() calls CCInfo.AllocateStack() to allocate the reserved argument area even though LowerCall is lowering from the callers point of view. Removing the call breaks the frame size calculation so it's clearly important but I haven't figured out why. I would have expected the one in MipsTargetLowering::LowerFormalArguments() to be the important one.


We don't need to track the precise MVT. Just whether it was floating point or not.


It makes no difference for 32-bit but AExt is normally treated the same way as SExt by our backend.


We don't use custom arguments. We ought to delete the references to VA.needsCustom()


We should use RoundUpToAlignment()


Didn't we do this on line 767 too?


This isn't correct for MIPS32r6 and I've realised that we don't guard against MIPS32r6. hasMips32() is true for MIPS32, MIPS32r2, MIPS32r6, MIPS64, MIPS64r2, and MIPS64r6. Just correct the main guard for now.

605 ↗(On Diff #14692)

I think this class should get it's own header and implementation file.

Adding comments responding to Daniels comments.


For O32, I think it's the caller.
From the ABI Doc:

  1. The caller will always build an argument data

structure, even though it may remain unused in whole
or part. Moreover, the data structure is always a
minimum of 16 bytes (four register-sized slots) in


BTW, with this patch, I pass all of test-suite at O0/O2 for mips32r1 and mips32r2.


What do you want here?


It seems we should then make this llvm_unreachable then. If someone later changes the compiler and we have custom args, we want to fail here because that is our assumption.


Yes. Probably a merge error when I went to the AArch64 model of fast-isel.



dsanders added inline comments.Nov 6 2014, 7:37 AM

Yes you're right, I had double-checked with a misleading testcase. This makes me suspicious of the code in LowerFormalArguments() instead since it also allocates the reserved region of the stack despite operating from the callee side.


I think that in the absence of a good reason to do otherwise, we should be consistent with the other parts of our backend and generate sign-extends for AExt. It's not required though.


That sounds good to me.

rkotler updated this revision to Diff 16016.Nov 10 2014, 3:11 PM
rkotler edited edge metadata.

Update patch to work with tip of tree. Majority of changes to MipsISelLowering.<cpp,h> have been replaced by new files MipsCCState.<h,cpp>

rkotler updated this revision to Diff 16019.Nov 10 2014, 3:39 PM

Fix some small changes requested by Daniel; handling of AExt as SExt, and call to llvm_unreachable if an attempt is made to use custom args, since we don't use them and hence don't expect that situation to occur.

dsanders accepted this revision.Nov 11 2014, 3:53 AM
dsanders edited edge metadata.

Thanks. LGTM with a few nits and a couple minor changes.

I'll unify the two O32 implementations as I work my way through the O32 refactoring.


Nit: Too many blank lines


Nit: Too many blank lines


Nit: You already have this at the top of the file.


I'd prefer these to contain llvm_unreachable so that we can easily demonstrate that Fast ISel doesn't use them.

In case anyone wonders why these functions exist: They are a side-effect of my recent ABI refactoring work. I added CustomCallingConv as a way to migrate the O32 implementation to a tablegen-erated definition without having to do it all at once. This worked nicely when only one file #included but now MipsFastISel.cpp does it too and has to provide an implementation of the static functions that tablegen doesn't provide. Fortunately, this patch doesn't need to use CC_MipsO32_F{32,64} so we can just use stub functions for the moment. I'll clean this up as I work through the O32 implementation.


Nit: Too many blank lines.


Nit: Empty comment and missing blank line.


Nit: Capitalization in comment and missing punctuation

There are a few more instances of this in this function.


I agree that using llvm_unreachable() is better than what I suggested.

Nit: Indentation


Nit: AArch64 not AARch64.

Also '... fine for Mips too but the finish work on it will be enabled ...' is rather strangely worded.


You missed this comment: We should use RoundUpToAlignment()


Yes. Probably a merge error when I went to the AArch64 model of fast-isel.

Given that you've said this is probably a merge error, shouldn't you remove this?


I missed this the first time around. Could you delete the commented out code?


Nit: Too many blank lines

This revision is now accepted and ready to land.Nov 11 2014, 3:53 AM
rkotler updated this revision to Diff 16121.Nov 12 2014, 3:42 PM
rkotler edited edge metadata.

Incorporate comments for LGTM from Daniel Sanders

rkotler updated this revision to Diff 16182.Nov 13 2014, 2:59 PM

Fix one cosmetic nit

rkotler updated this revision to Diff 16183.Nov 13 2014, 3:10 PM

Oops.. made a mistake on last patch and included some non Mips fast-isel code that had already been committed.

rkotler updated this object.Nov 13 2014, 3:36 PM
rkotler closed this revision.Nov 13 2014, 3:37 PM