-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[AMDGPU] Improved Lowering of abs(i8/i16) and -abs(i8/i16) #165626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-backend-amdgpu Author: Patrick Simmons (linuxrocks123) ChangesThis PR improves the lowering of abs(i16) and -abs(i16) on the AMDGPU target. It is written as an early Machine IR-level pass since the transformation is only profitable for SGPR registers as there is no dedicated abs instruction for VGPRs, and it is only possible to determine whether a value is VGPR or SGPR after ISel. An earlier failed, correct-but-pessimizing attempt overriding expandABS at the DAG level is in the Git history. Full diff: https://github.com/llvm/llvm-project/pull/165626.diff 4 Files Affected:
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.h b/llvm/lib/Target/AMDGPU/AMDGPU.h
index ce2b4a5f6f2e9..43a052b687109 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.h
@@ -39,6 +39,7 @@ FunctionPass *createSIAnnotateControlFlowLegacyPass();
FunctionPass *createSIFoldOperandsLegacyPass();
FunctionPass *createSIPeepholeSDWALegacyPass();
FunctionPass *createSILowerI1CopiesLegacyPass();
+FunctionPass *createSISAbs16FixupLegacyPass();
FunctionPass *createSIShrinkInstructionsLegacyPass();
FunctionPass *createSILoadStoreOptimizerLegacyPass();
FunctionPass *createSIWholeQuadModeLegacyPass();
@@ -93,6 +94,13 @@ class SILowerI1CopiesPass : public PassInfoMixin<SILowerI1CopiesPass> {
MachineFunctionAnalysisManager &MFAM);
};
+class SISAbs16FixupPass : public PassInfoMixin<SISAbs16FixupPass> {
+public:
+ SISAbs16FixupPass() = default;
+ PreservedAnalyses run(MachineFunction &MF,
+ MachineFunctionAnalysisManager &MFAM);
+};
+
void initializeAMDGPUDAGToDAGISelLegacyPass(PassRegistry &);
void initializeAMDGPUAlwaysInlinePass(PassRegistry&);
@@ -197,6 +205,9 @@ extern char &SILowerWWMCopiesLegacyID;
void initializeSILowerI1CopiesLegacyPass(PassRegistry &);
extern char &SILowerI1CopiesLegacyID;
+void initializeSISAbs16FixupLegacyPass(PassRegistry &);
+extern char &SISAbs16FixupLegacyID;
+
void initializeAMDGPUGlobalISelDivergenceLoweringPass(PassRegistry &);
extern char &AMDGPUGlobalISelDivergenceLoweringID;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index 996b55f42fd0b..90405fed8efdd 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -551,6 +551,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUTarget() {
initializeAMDGPUPrepareAGPRAllocLegacyPass(*PR);
initializeGCNDPPCombineLegacyPass(*PR);
initializeSILowerI1CopiesLegacyPass(*PR);
+ initializeSISAbs16FixupLegacyPass(*PR);
initializeAMDGPUGlobalISelDivergenceLoweringPass(*PR);
initializeAMDGPURegBankSelectPass(*PR);
initializeAMDGPURegBankLegalizePass(*PR);
@@ -1517,6 +1518,7 @@ bool GCNPassConfig::addInstSelector() {
AMDGPUPassConfig::addInstSelector();
addPass(&SIFixSGPRCopiesLegacyID);
addPass(createSILowerI1CopiesLegacyPass());
+ addPass(createSISAbs16FixupLegacyPass());
return false;
}
@@ -2209,6 +2211,7 @@ Error AMDGPUCodeGenPassBuilder::addInstSelector(AddMachinePass &addPass) const {
addPass(AMDGPUISelDAGToDAGPass(TM));
addPass(SIFixSGPRCopiesPass());
addPass(SILowerI1CopiesPass());
+ addPass(SISAbs16FixupPass());
return Error::success();
}
diff --git a/llvm/lib/Target/AMDGPU/CMakeLists.txt b/llvm/lib/Target/AMDGPU/CMakeLists.txt
index a1e0e5293c706..cd9225acdb002 100644
--- a/llvm/lib/Target/AMDGPU/CMakeLists.txt
+++ b/llvm/lib/Target/AMDGPU/CMakeLists.txt
@@ -185,6 +185,7 @@ add_llvm_target(AMDGPUCodeGen
SIPreEmitPeephole.cpp
SIProgramInfo.cpp
SIRegisterInfo.cpp
+ SISAbs16Fixup.cpp
SIShrinkInstructions.cpp
SIWholeQuadMode.cpp
diff --git a/llvm/test/CodeGen/AMDGPU/s_abs_i16.ll b/llvm/test/CodeGen/AMDGPU/s_abs_i16.ll
new file mode 100644
index 0000000000000..e61abb7173d78
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/s_abs_i16.ll
@@ -0,0 +1,22 @@
+; RUN: llc -mtriple=amdgcn-- -mcpu=gfx900 < %s | FileCheck %s
+
+define amdgpu_ps i16 @abs_i16(i16 inreg %arg) {
+; CHECK-LABEL: abs_i16:
+; CHECK: %bb.0:
+; CHECK-NEXT: s_sext_i32_i16 s0, s0
+; CHECK-NEXT: s_abs_i32 s0, s0
+
+ %res = call i16 @llvm.abs.i16(i16 %arg, i1 false)
+ ret i16 %res
+}
+
+define amdgpu_ps i16 @abs_i16_neg(i16 inreg %arg) {
+; CHECK-LABEL: abs_i16_neg:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_sext_i32_i16 s0, s0
+; CHECK-NEXT: s_abs_i32 s0, s0
+; CHECK-NEXT: s_sub_i32 s0, 0, s0
+ %res1 = call i16 @llvm.abs.i16(i16 %arg, i1 false)
+ %res2 = sub i16 0, %res1
+ ret i16 %res2
+}
\ No newline at end of file
|
|
Patch is missing the new file. Also I would really hope we can find a way to do this without adding a dedicated pass. |
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
@jayfoad thanks, I added the new file. To avoid adding a new pass, maybe we could combine this and By the way, this isn't DAG-level because the transformation pessimizes 16-bit abs on VGPRs if it runs on them, and we don't know what the register classes are in the DAG yet. |
jmmartinez
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To see better the improvement motivating this patch.
Could you squash the commits and split them in 2: one where you pre-commit the tests, and one where you solve the issue.
| @@ -0,0 +1,22 @@ | |||
| ; RUN: llc -mtriple=amdgcn-- -mcpu=gfx900 < %s | FileCheck %s | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you run update_llc_test_checks.py over this file ?
Please add a GISel test line too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
Hi @jmmartinez, thanks for reviewing this PR. Normally I would not have a problem squashing the commits as you suggested, but, in this case, the commit history contains two failed implementation attempts that I would like to preserve during the review process in case a method of fixing one of them is discovered. Would it be acceptable if I posted the master/branch assemblies of the s_cmp_0.ll testcase instead to facilitate seeing the improvement? |
No problem in keeping the previous cases, but at least seeing the difference in |
|
@jmmartinez interestingly, the problem doesn't exist with global isel enabled. The main branch generates the optimal instruction selection without this PR. If we are planning to switch to global isel soon, we may not need this. |
|
@jmmartinez, for non-global-isel, here are the differing testcase files: |
|
@jmmartinez @jayfoad I think this is everything. If we're ready to merge this as a new pass, I'll update the llc-pipeline tests to pass. If we'd rather combine this with an existing early MIR pass, such as |
arsenm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't really fit with the usual strategy for dealing with this sort of issue (it's sort of backwards). The usual strategy is something closer to treat the operation as legal, and deal with it later if it isn't.
There are a few options. What I suggest is to make ISD::ABS custom for i16. In the custom lowering, check if the input is divergent, return to use the default expansion.
That should get the right result most of the time. There's a possible edge case where SIFixVGPRCopies will need to deal s_abs_i16 with SGPR inputs
| @@ -0,0 +1,26 @@ | |||
| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 | |||
| ; RUN: llc -mtriple=amdgcn-- -mcpu=gfx900 < %s | FileCheck %s | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would hope we wouldn't need a new test for this. It looks like the abs tests could use some gardening. test/CodeGen/AMDGPU/GlobalISel/llvm.abs.ll looks reasonably comprehensive; can you start by precommitting moving that up to the main directory, and adding dag run lines? It then should gain the negated abs cases
(I also noticed the test is minorly broken, fixed by #165965)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@arsenm have you looked at b83ae56? I think that earlier failed attempt is close to what you were suggesting. Perhaps that earlier method could work better if I checked for whether the input is divergent as you suggested, so how would I go about checking whether the input is divergent? |
|
@arsenm also am I making the lowering "custom for i16" properly in that commit, or is there another way? It bugged me that I had to make that function virtual to override it since I thought, if this was the right way to go, some other target probably would have made it virtual by now. |
Like this
No, you shouldn't need to make anything virtual. You should call |
|
@arsenm why SITargetLowering instead of AMDGPUTargetLowering? |
R600 doesn't need this, AMDGPUTargetLowering is generally for shared stuff |
| assert(Op.getValueType() == MVT::i16 && | ||
| "Tried to select abs i16 lowering with non-i16 type."); | ||
|
|
||
| // divergent means will not end up using SGPRs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: comments should generally be full sentences starting with a capital and ending with a period, here and elsewhere. See coding standards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
Do you have examples showing that the codegen is actually better with this patch than it was before? |
|
@jayfoad if you mean did I search real code for examples, no. If you mean did I construct examples, yes. Running the testcase with main versus branch shows the improvement. |
In that situation it's helpful to push two commits to the same PR, the first one just adding the test and showing the old codegen, and the second one adding the real fix and showing the improved codegen. So that all your reviewers don't have to build two compilers themselves just to see the effect of your patch. |
|
@jayfoad thanks, I'll keep that in mind for the future. |
81223ab to
55c3456
Compare
|
This might be a separate PR, but can you check if abs(i8) is handled well. |
|
@LU-JOHN thanks I will check that and make another PR if needed. |
|
@arsenm LGTM? |
|
@arsenm @LU-JOHN per @LU-JOHN's suggestion I updated this PR to handle i8 absolute values as well. Unfortunately, this required a return to the approach of overriding Currently, I am overriding the function in AMDGPUTargetLowering. It may be more appropriate to override in SITargetLowering instead. Please let me know. The reason is that MVT::i8 is not a valid type on our architecture, so setting a custom operation action no longer works. If either of you has a better idea than overriding |
| if (!IsNegative) | ||
| return TruncResult; | ||
|
|
||
| return DAG.getNode(ISD::SUB, DL, N->getValueType(0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use getNegative
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| #include "llvm/IR/IntrinsicsR600.h" | ||
| #include "llvm/IR/MDBuilder.h" | ||
| #include "llvm/Support/CommandLine.h" | ||
| #include "llvm/Support/Compiler.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed it. Note that clang-format or clang-tidy or whatever added it, not me.
fae5af6 to
afd852d
Compare
afd852d to
4a09913
Compare
RKSimon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really not keen on overriding expansions like this. Have you tried adding a local combineABS to just extend anything smaller than i32?
|
@RKSimon you can examine my previous attempt using The target-dependent |
Don't expand the scope of the patch to cover i8, leave that for later. That shouldn't require overriding anything either, you could handle i8 the same way and mix in the promotion
It does work, it just goes through ReplaceNodeResults instead of LowerOperation |
It also double complicates the vector of i8 case, but I'd expect you could just rely on i8 being legalized to i16 and not have to worry about either |
|
@arsenm @RKSimon I tried it prior to reverting to the I don't have a strong opinion on whether this PR should handle |
This PR improves the lowering of abs(i16) and -abs(i16) on the AMDGPU target. It is written as an early Machine IR-level pass since the transformation is only profitable for SGPR registers as there is no dedicated abs instruction for VGPRs, and it is only possible to determine whether a value is VGPR or SGPR after ISel.
An earlier failed, correct-but-pessimizing attempt overriding expandABS at the DAG level is in the Git history.