This is an archive of the discontinued LLVM Phabricator instance.

[GISel]: ConstantFold operations when building MIR
AbandonedPublic

Authored by aditya_nandakumar on Jul 18 2017, 5:52 PM.

Details

Summary

Initial implementation.
Based on feedback, I'll add support for FPConstants.

Diff Detail

Event Timeline

Gerolf added a subscriber: Gerolf.Jul 18 2017, 6:00 PM

Thanks for working on this! Please add comments and show off one or two examples that highlight the benefits of your extensions.

Cheers
Gerolf

This is helpful in cases where you try to build a generic operation on a constant.
For e.g.,
vreg1(s16) = G_CONSTANT 0
Builder.buildZExt(s32, vreg1) would result in
vreg1(s16) = G_CONSTANT 0
vreg2(s16) = G_ZEXT vreg1

Instead - we can constant fold operations and instead generate
vreg2(s32) = G_CONSTANT i32 0

Similarly we can constant fold binary operations such as Add/sub/or/and/xor/mul.

We also can constant fold intrinsics FABS/FLOG... (constant) -> constant.

dsanders edited edge metadata.Jul 26 2017, 2:16 AM

Could you run clang-format on this patch? There's a few indentation and style nits in this patch. There's also a few in the neighbouring code which we should deal with separately

Similarly we can constant fold binary operations such as Add/sub/or/and/xor/mul.

I don't see XOR in this patch

Thanks for working on this! Please add comments and show off one or two examples that highlight the benefits of your extensions.

Cheers
Gerolf

! In D35594#814884, @aditya_nandakumar wrote:

This is helpful in cases where you try to build a generic operation on a constant.
For e.g.,
vreg1(s16) = G_CONSTANT 0
Builder.buildZExt(s32, vreg1) would result in
vreg1(s16) = G_CONSTANT 0
vreg2(s16) = G_ZEXT vreg1

Instead - we can constant fold operations and instead generate
vreg2(s32) = G_CONSTANT i32 0

Similarly we can constant fold binary operations such as Add/sub/or/and/xor/mul.

We also can constant fold intrinsics FABS/FLOG... (constant) -> constant.

I think Gerolf intended the comments and examples to be added to the patch itself.

In my opinion, the main thing this patch is missing is the test case. Is it possible to extend one (preferably a few) of the select-*.mir tests to cover a constant folding case?

include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
81–87

This will need refreshing to account for the updates to one of your other patches.

lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
184–185

XOR seems to be missing

aditya_nandakumar marked an inline comment as done.Jul 26 2017, 3:08 PM

I can try changing one of IRTranslator's build methods to use this API instead and then I should be able to write a test case.

include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
81–87

This is not needed anymore. The other patch went in.

lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
184–185

Missed that. Thanks.

aditya_nandakumar marked an inline comment as done.

Updated diff . Added some test cases by making IRTranslator use buildInstr for binary opcodes.

Added remaining IntegerOps + test cases for them.

aditya_nandakumar marked an inline comment as done.Jul 26 2017, 7:23 PM
Gerolf added inline comments.Jul 27 2017, 12:17 AM
include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
94

How do you sort the opcodes? The order here is different from other functions (ConstantFoldBinop) in your code? Why not be consistent and eg. order all arithmetic (alphabetical), then all logical (alphabetical) or all alphabetical or ...

126

What about G_TRUNC?

lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
200

BoolValue? Should that be an explicit check for zero instead?

398

For AnyExt ConstandFoldUnaryOp() uses Zext, here you use Sext?

408

Since ConstandFoldUnaryOp supports 4 opcodes, I had expected four calls to it in functions buildSExt, buildZext, buildAnyExt and *buildTrunc*. But the last one seems missing. If the function below (buildSExtorTrunc is covering that than I miss a call to ConstandFoldUnaryOp() there. So either way the code doesn't look quite kosher.

aditya_nandakumar marked an inline comment as done.Jul 27 2017, 11:45 AM
aditya_nandakumar added inline comments.
include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
94

I hadn't thought about sorting. The order is mostly similar to the one in the DAG. I will alphabetically sort it here though.

126

I hadn't initially implemented all of them - as I thought I'd do that based on feedback. I'll certainly add G_TRUNC here.

lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
200

That is how you check for zero in APInt.

/// This converts the APInt to a boolean value as a test against zero.
bool getBoolValue() const { return !!*this; }
398

Will change to Zext here. Not sure if it matters for any_ext though.

408

I hadn't hooked up G_TRUNC yet. Was planning to do it based on feedback.
I'll add it shortly.

aditya_nandakumar marked an inline comment as done.

Added more integer operations, along with tests.
Disabled constant folding cast instructions as MIR currently doesn't infer legality of constants of type that it creates.

qcolombet edited edge metadata.Jul 28 2017, 3:24 PM

Disabled constant folding cast instructions as MIR currently doesn't infer legality of constants of type that it creates.

Would it make sense to have a mode in the builder where combines are allow or not, just not type changes?
What I am thinking is every pass before legalization would run in combine mode and every pass after would run in non-combine mode.

Is that one flag that basically enables/disables all optimizations/folding ? Or we have some sort of API where the user opt's in/out into certain transformations..

Is that one flag that basically enables/disables all optimizations/folding ?

Yes, I would go with that for now. But I could see your concerns that we are going to generate crapy code for no good reason, thus you'd like more control.

Or we have some sort of API where the user opt's in/out into certain transformations..

Hi Aditya,

It feels to me that we are attacking the problem of the combine optimizations and I wouldn't want complicated APIs for this. Basically, the way I see it is with a dumb MachineIRBuilder base class that would be specialized with the combines that make sense for a target at a given point for a given optimization level. The challenge here is to define which combines are available and when they are valid to apply (e.g., ok before legalization, etc.) for each target. I can see a table gen path here.

To summarize, I'd like to keep the combiner logic as simple as possible (ideally none at all for O0) because I fear we are already touching something we haven't carefully thought yet.

Cheers,
-Quentin

Hi Aditya,

Is there anything in this patch we still need? I believe you committed similar functionality along with a CSE'ing builder

aditya_nandakumar abandoned this revision.Jul 18 2019, 9:54 PM

Yes - this is not required any more.