proposed change to class BasicTTI

For being able to change subtargets within a compilation unit, among other things, I need to be able to change the target lowering class that is used by BasicTTI

For example we have a mips16 and non mips16 version.

On the original call that creates this class, I'd like to pass the address of the address of the TargetLoweringBase class.

That way I can insert a function pass before this pass which examines the function attributes and changes the pointer.

So we would get:

ImmutablePass *
llvm::createBasicTargetTransformInfoPass(const TargetLoweringBase **TLI_) {
   return new BasicTTI(TLI);
}

we would add the variable

TargetLoweringBase **TLI_

and at the beginning of each pass

TLI = *TLI_;

Maybe there is a more elegant way to do this but this is essentially what I need to do.

Another way to do this would to be to have a reset virtual function which is passed the Function, and the address of TLI so that it could be modified.

This seems somewhat cleaner.

The reset virtual function would be added to base class TargetLoweringBase.

Just realized that BasicTransformInfoClass is an immutable pass.

Not sure how to reconcile this with fact that there will be different answers needed depending on the subtarget.

Seems like BasicTansformInfoClass should become a function pass that does not modify anything.

Hi Reed,

We will need to reconstruct the target machine and the TTI chain when the function attributes change. We currently don’t have code for doing that but I suggest that you talk with Bill Wendling about the best way to implement this.

Thanks,
Nadav

Cool. Bill’s new attribute work has already made this task much easier for me. I’m willing to contribute to the compiler in this area and any advice is greatly appreciated. If Bill is already scheduled to do this then i can also wait like I did for his attribute work. Reed

I'm making good progress sorting all of this out.

I think that for Mips16/32 I can do what I need without touching target independent code but I'm not done yet so there may be some issues.

If my plan works, then I think some of it could be moved into target independent code so that other targets could use it without reinventing the wheel.

Most of this would surely be usable by arm/thumb.

So I have dual mode 16/32 compilation on a per function basis working.

I need to clean up some things and then will push the change.

I managed to do everything without needing to change anything in target independent code thus far. It was a fun puzzle to solve as to how to do this using only the given APIs.

As for the BasicTransformInfoPassass, for this dual mode I'm using createNoTargetTransformInfoPass right now.

I will solve this issue of the BasicTransformInfoPass being immutable after this initial checking which gets all the functionality. I was able to make in a function pass but ran into some issues so I put that
aside for now.

The basic problem was to be able to compile:

void __attribute__((mips16)) foo (void) {

}

void __attribute__((nomips16)) nofoo (void) {

}

So first function is compiled as mips16 and the second as mips32.

Thanks to Bill Wendling for all this new attribute work he did which allowed me to just focus on the exact problem in hand.

Hi Reed,

As for the BasicTransformInfoPassass, for this dual mode I’m using createNoTargetTransformInfoPass right now.

So, MIPS does not need LSR, LowerSwitch and other optimizations that depend on TTI ?

I will solve this issue of the BasicTransformInfoPass being immutable after this initial checking which gets all the functionality. I was able to make in a function pass but ran into some issues so I put that
aside for now.

IMHO the right way to handle target function attributes is to re-initialize the target machine and TTI for every function (if the attributes changed). Do you have another solution in mind ?

Thanks,
Nadav

As an experiment, I built a flavor of llvm inside of Mips that always uses I agree. I need to study that code more to have some ideas as to how to do this. Maybe you or Bill Wendling know exactly how to do this. If you guys want to work on that I can leave it alone or else I’ll probably start to work on it after I push what I have thus far. I will probably push my changes sometime next week after more testing and cleanup. I will be putting this createNoTargetTransformationInfoPass on a mips specific switch for now. In gcc, they actually have an option which compiles every other function as either mips16 or nomips16 as a way to test this on a large source base. I will probably add that option. My solution to all of this was surprisingly simple after I got a good handle on this problem. It would work for ARM and ARM thumb easily. It’s not a very big patch but I went through many iterations and was able to eliminate all target independent parts of the patch in that way.

Spent a lot of time testing and cleaning up the patch this weekend and all looks good.

Akira is going to review it internally this week and then I'll probably push it later in the week or on the weekend. It's all in the lib/TargetMips directory.

Doing this same thing with Arm and Thumb should be trivial. It's a very simple solution I came up.

I will start to think about this further work concerning the BasicTransformInfoPass and being able to reset the target.

Reed

I don't really understand this.

TargetMachine and TTI may be quite expensive to initialize. Doing so for
each (sometimes tiny) function processed doesn't make a lot of sense to me.

Wouldn't it be better to design a TargetMachine (and TTI, or other passes
that are similar) which provides context-sensitive answers? You could
imagine this being a wrapper which delegates to one of two real TM and TTI
implementations based on a mode switch.

Alternatively, we could look at partitioning functions into two modules,
and then bring up the infrastructure once per module.

I would personally choose between these based on how much shared
functionality there would be in the TM and TTI between the two.

Yes. But we can keep a few TMs around and only initialize TTI, which should be inexpensive to initialize because it has no state.

I assume that even for LTO builds, the target attributes won’t change very often.

This can work, but I don’t have enough information about two things:

  1. How often do we switch TMs. (and how expensive it is)
  2. How complex is it to create a wrapper and what overhead is the wrapper going to add.

Do you have a design in mind for such a wrapper ?

I am not sure if this can work. I see a scenario where a non-AVX function can call an AVX functions. Splitting these into two modules can potentially prevent some optimizations.

For changing subtargets, i.e. mips16 to mips32 on a per function basis, I only have one copy of all that is needed for both mips16 and mips32. What I do is I have two versions of the instruction selection pass (mips16 and mips32) and a controller pass which is used to reset parts of target machine when needed (ptrs to target lowering, register info, frame lowering which in the case of mips16 / mips32 are different derived classes). If the run machine function is called in the mips16 instruction selection pass, it returns immediately if it’s in mips32 mode and similarly in the mips32 instruction selection pass. The one hole is this immutable pass for basic target transform info which should be a function pass. This can also be done so that maybe only at most two copies of this pass are present and the information is reset when the subtarget changes. I’m attaching the current state of the patch in case you want to see how I’m doing this now. Many things can be handled with just options to the normal setup but something which differs as much as mips16 and mips32 or thumb1 and arm need a subtarget reset.

mips16_32_1.txt (22.7 KB)

One set of issues here is that target independent optimizations that use the TTI would have to all be function passes too if they are going to change based on the subtarget (mip32/mips16 or arm/thumb1).