-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
[SDAG] Reverse the canonicalization of isInf/isNanOrInf #81404
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3467,12 +3467,51 @@ void SelectionDAGBuilder::visitICmp(const User &I) { | |
setValue(&I, DAG.getSetCC(getCurSDLoc(), DestVT, Op1, Op2, Opcode)); | ||
} | ||
|
||
SDValue SelectionDAGBuilder::lowerIsFpClass(Value *ClassVal, | ||
FPClassTest ClassTest) { | ||
const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | ||
const DataLayout &DL = DAG.getDataLayout(); | ||
SDLoc sdl = getCurSDLoc(); | ||
|
||
EVT DestVT = | ||
TLI.getValueType(DL, CmpInst::makeCmpResultType(ClassVal->getType())); | ||
EVT ArgVT = TLI.getValueType(DL, ClassVal->getType()); | ||
MachineFunction &MF = DAG.getMachineFunction(); | ||
const Function &F = MF.getFunction(); | ||
SDValue Op = getValue(ClassVal); | ||
SDNodeFlags Flags; | ||
Flags.setNoFPExcept(!F.getAttributes().hasFnAttr(llvm::Attribute::StrictFP)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can just be true, is.fpclass can never raise exceptions (don't even need the flag?) |
||
// If ISD::IS_FPCLASS should be expanded, do it right now, because the | ||
// expansion can use illegal types. Making expansion early allows | ||
// legalizing these types prior to selection. | ||
if (!TLI.isOperationLegalOrCustom(ISD::IS_FPCLASS, ArgVT)) | ||
return TLI.expandIS_FPCLASS(DestVT, Op, ClassTest, Flags, sdl, DAG); | ||
|
||
SDValue Check = DAG.getTargetConstant(ClassTest, sdl, MVT::i32); | ||
return DAG.getNode(ISD::IS_FPCLASS, sdl, DestVT, {Op, Check}, Flags); | ||
} | ||
|
||
void SelectionDAGBuilder::visitFCmp(const User &I) { | ||
FCmpInst::Predicate predicate = FCmpInst::BAD_FCMP_PREDICATE; | ||
if (const FCmpInst *FC = dyn_cast<FCmpInst>(&I)) | ||
if (const FCmpInst *FC = dyn_cast<FCmpInst>(&I)) { | ||
predicate = FC->getPredicate(); | ||
else if (const ConstantExpr *FC = dyn_cast<ConstantExpr>(&I)) | ||
|
||
// Reverse the canonicalization if it is a FP class test | ||
auto ShouldReverseTransform = [](FPClassTest ClassTest) { | ||
return ClassTest == fcInf || ClassTest == (fcInf | fcNan); | ||
}; | ||
auto [ClassVal, ClassTest] = | ||
fcmpToClassTest(predicate, *FC->getParent()->getParent(), | ||
FC->getOperand(0), FC->getOperand(1)); | ||
if (ClassVal && (ShouldReverseTransform(ClassTest) || | ||
ShouldReverseTransform(~ClassTest))) { | ||
setValue(&I, lowerIsFpClass(ClassVal, ClassTest)); | ||
return; | ||
} | ||
} else if (const ConstantExpr *FC = dyn_cast<ConstantExpr>(&I)) { | ||
predicate = FCmpInst::Predicate(FC->getPredicate()); | ||
} | ||
|
||
dtcxzyw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SDValue Op1 = getValue(I.getOperand(0)); | ||
SDValue Op2 = getValue(I.getOperand(1)); | ||
|
||
|
@@ -6666,29 +6705,11 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, | |
DAG.setRoot(Res.getValue(0)); | ||
return; | ||
case Intrinsic::is_fpclass: { | ||
const DataLayout DLayout = DAG.getDataLayout(); | ||
EVT DestVT = TLI.getValueType(DLayout, I.getType()); | ||
EVT ArgVT = TLI.getValueType(DLayout, I.getArgOperand(0)->getType()); | ||
FPClassTest Test = static_cast<FPClassTest>( | ||
cast<ConstantInt>(I.getArgOperand(1))->getZExtValue()); | ||
MachineFunction &MF = DAG.getMachineFunction(); | ||
const Function &F = MF.getFunction(); | ||
SDValue Op = getValue(I.getArgOperand(0)); | ||
SDNodeFlags Flags; | ||
Flags.setNoFPExcept( | ||
!F.getAttributes().hasFnAttr(llvm::Attribute::StrictFP)); | ||
// If ISD::IS_FPCLASS should be expanded, do it right now, because the | ||
// expansion can use illegal types. Making expansion early allows | ||
// legalizing these types prior to selection. | ||
if (!TLI.isOperationLegalOrCustom(ISD::IS_FPCLASS, ArgVT)) { | ||
SDValue Result = TLI.expandIS_FPCLASS(DestVT, Op, Test, Flags, sdl, DAG); | ||
setValue(&I, Result); | ||
return; | ||
} | ||
|
||
SDValue Check = DAG.getTargetConstant(Test, sdl, MVT::i32); | ||
SDValue V = DAG.getNode(ISD::IS_FPCLASS, sdl, DestVT, {Op, Check}, Flags); | ||
setValue(&I, V); | ||
setValue(&I, | ||
lowerIsFpClass( | ||
I.getArgOperand(0), | ||
static_cast<FPClassTest>( | ||
cast<ConstantInt>(I.getArgOperand(1))->getZExtValue()))); | ||
return; | ||
} | ||
case Intrinsic::get_fpenv: { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4 | ||
; RUN: llc -mtriple=aarch64 -mattr=+sve < %s | FileCheck %s | ||
|
||
define i1 @test_is_inf_or_nan(double %arg) { | ||
; CHECK-LABEL: test_is_inf_or_nan: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: fmov x9, d0 | ||
; CHECK-NEXT: mov x8, #9218868437227405311 // =0x7fefffffffffffff | ||
; CHECK-NEXT: and x9, x9, #0x7fffffffffffffff | ||
; CHECK-NEXT: cmp x9, x8 | ||
; CHECK-NEXT: cset w0, gt | ||
; CHECK-NEXT: ret | ||
%abs = tail call double @llvm.fabs.f64(double %arg) | ||
%ret = fcmp ueq double %abs, 0x7FF0000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define i1 @test_is_not_inf_or_nan(double %arg) { | ||
; CHECK-LABEL: test_is_not_inf_or_nan: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: fmov x9, d0 | ||
; CHECK-NEXT: mov x8, #9218868437227405312 // =0x7ff0000000000000 | ||
; CHECK-NEXT: and x9, x9, #0x7fffffffffffffff | ||
; CHECK-NEXT: cmp x9, x8 | ||
; CHECK-NEXT: cset w0, lt | ||
; CHECK-NEXT: ret | ||
%abs = tail call double @llvm.fabs.f64(double %arg) | ||
%ret = fcmp one double %abs, 0x7FF0000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define i1 @test_is_inf(double %arg) { | ||
; CHECK-LABEL: test_is_inf: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: fabs d0, d0 | ||
; CHECK-NEXT: mov x8, #9218868437227405312 // =0x7ff0000000000000 | ||
; CHECK-NEXT: fmov d1, x8 | ||
; CHECK-NEXT: fcmp d0, d1 | ||
; CHECK-NEXT: cset w0, eq | ||
; CHECK-NEXT: ret | ||
%abs = tail call double @llvm.fabs.f64(double %arg) | ||
%ret = fcmp oeq double %abs, 0x7FF0000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define i1 @test_is_not_inf(double %arg) { | ||
; CHECK-LABEL: test_is_not_inf: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: fabs d0, d0 | ||
; CHECK-NEXT: mov x8, #9218868437227405312 // =0x7ff0000000000000 | ||
; CHECK-NEXT: fmov d1, x8 | ||
; CHECK-NEXT: fcmp d0, d1 | ||
; CHECK-NEXT: cset w0, ne | ||
; CHECK-NEXT: ret | ||
%abs = tail call double @llvm.fabs.f64(double %arg) | ||
%ret = fcmp une double %abs, 0x7FF0000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define <vscale x 2 x i1> @test_vec_is_inf_or_nan(<vscale x 2 x double> %arg) { | ||
; CHECK-LABEL: test_vec_is_inf_or_nan: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: ptrue p0.d | ||
; CHECK-NEXT: mov z1.d, #0x7ff0000000000000 | ||
; CHECK-NEXT: and z0.d, z0.d, #0x7fffffffffffffff | ||
; CHECK-NEXT: cmpge p0.d, p0/z, z0.d, z1.d | ||
; CHECK-NEXT: ret | ||
%abs = tail call <vscale x 2 x double> @llvm.fabs.nxv2f64(<vscale x 2 x double> %arg) | ||
%ret = fcmp ueq <vscale x 2 x double> %abs, splat (double 0x7FF0000000000000) | ||
ret <vscale x 2 x i1> %ret | ||
} | ||
|
||
define <vscale x 2 x i1> @test_vec_is_not_inf_or_nan(<vscale x 2 x double> %arg) { | ||
; CHECK-LABEL: test_vec_is_not_inf_or_nan: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: ptrue p0.d | ||
; CHECK-NEXT: mov z1.d, #0x7ff0000000000000 | ||
; CHECK-NEXT: and z0.d, z0.d, #0x7fffffffffffffff | ||
; CHECK-NEXT: cmpgt p0.d, p0/z, z1.d, z0.d | ||
; CHECK-NEXT: ret | ||
%abs = tail call <vscale x 2 x double> @llvm.fabs.nxv2f64(<vscale x 2 x double> %arg) | ||
%ret = fcmp one <vscale x 2 x double> %abs, splat (double 0x7FF0000000000000) | ||
ret <vscale x 2 x i1> %ret | ||
} | ||
|
||
define <vscale x 2 x i1> @test_vec_is_inf(<vscale x 2 x double> %arg) { | ||
; CHECK-LABEL: test_vec_is_inf: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: ptrue p0.d | ||
; CHECK-NEXT: mov x8, #9218868437227405312 // =0x7ff0000000000000 | ||
; CHECK-NEXT: mov z1.d, x8 | ||
; CHECK-NEXT: fabs z0.d, p0/m, z0.d | ||
; CHECK-NEXT: fcmeq p0.d, p0/z, z0.d, z1.d | ||
; CHECK-NEXT: ret | ||
%abs = tail call <vscale x 2 x double> @llvm.fabs.nxv2f64(<vscale x 2 x double> %arg) | ||
%ret = fcmp oeq <vscale x 2 x double> %abs, splat (double 0x7FF0000000000000) | ||
ret <vscale x 2 x i1> %ret | ||
} | ||
|
||
define <vscale x 2 x i1> @test_vec_is_not_inf(<vscale x 2 x double> %arg) { | ||
; CHECK-LABEL: test_vec_is_not_inf: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: ptrue p0.d | ||
; CHECK-NEXT: mov x8, #9218868437227405312 // =0x7ff0000000000000 | ||
; CHECK-NEXT: mov z1.d, x8 | ||
; CHECK-NEXT: fabs z0.d, p0/m, z0.d | ||
; CHECK-NEXT: fcmne p0.d, p0/z, z0.d, z1.d | ||
; CHECK-NEXT: ret | ||
%abs = tail call <vscale x 2 x double> @llvm.fabs.nxv2f64(<vscale x 2 x double> %arg) | ||
%ret = fcmp une <vscale x 2 x double> %abs, splat (double 0x7FF0000000000000) | ||
ret <vscale x 2 x i1> %ret | ||
} | ||
|
||
define i1 @test_fp128_is_inf_or_nan(fp128 %arg) { | ||
; CHECK-LABEL: test_fp128_is_inf_or_nan: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: mov x8, #9223090561878065151 // =0x7ffeffffffffffff | ||
; CHECK-NEXT: str q0, [sp, #-16]! | ||
; CHECK-NEXT: .cfi_def_cfa_offset 16 | ||
; CHECK-NEXT: ldr x9, [sp, #8] | ||
; CHECK-NEXT: and x9, x9, #0x7fffffffffffffff | ||
; CHECK-NEXT: cmp x9, x8 | ||
; CHECK-NEXT: cset w0, gt | ||
; CHECK-NEXT: add sp, sp, #16 | ||
; CHECK-NEXT: ret | ||
%abs = tail call fp128 @llvm.fabs.f128(fp128 %arg) | ||
%ret = fcmp ueq fp128 %abs, 0xL00000000000000007FFF000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define i1 @test_fp128_is_not_inf_or_nan(fp128 %arg) { | ||
; CHECK-LABEL: test_fp128_is_not_inf_or_nan: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: mov x8, #9223090561878065152 // =0x7fff000000000000 | ||
; CHECK-NEXT: str q0, [sp, #-16]! | ||
; CHECK-NEXT: .cfi_def_cfa_offset 16 | ||
; CHECK-NEXT: ldr x9, [sp, #8] | ||
; CHECK-NEXT: and x9, x9, #0x7fffffffffffffff | ||
; CHECK-NEXT: cmp x9, x8 | ||
; CHECK-NEXT: cset w0, lt | ||
; CHECK-NEXT: add sp, sp, #16 | ||
; CHECK-NEXT: ret | ||
%abs = tail call fp128 @llvm.fabs.f128(fp128 %arg) | ||
%ret = fcmp one fp128 %abs, 0xL00000000000000007FFF000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define i1 @test_fp128_is_inf(fp128 %arg) { | ||
; CHECK-LABEL: test_fp128_is_inf: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: str q0, [sp, #-16]! | ||
; CHECK-NEXT: .cfi_def_cfa_offset 16 | ||
; CHECK-NEXT: ldp x9, x8, [sp], #16 | ||
; CHECK-NEXT: and x8, x8, #0x7fffffffffffffff | ||
; CHECK-NEXT: eor x8, x8, #0x7fff000000000000 | ||
; CHECK-NEXT: orr x8, x9, x8 | ||
; CHECK-NEXT: cmp x8, #0 | ||
; CHECK-NEXT: cset w0, eq | ||
; CHECK-NEXT: ret | ||
%abs = tail call fp128 @llvm.fabs.f128(fp128 %arg) | ||
%ret = fcmp oeq fp128 %abs, 0xL00000000000000007FFF000000000000 | ||
ret i1 %ret | ||
} | ||
|
||
define i1 @test_fp128_is_not_inf(fp128 %arg) { | ||
; CHECK-LABEL: test_fp128_is_not_inf: | ||
; CHECK: // %bb.0: | ||
; CHECK-NEXT: str q0, [sp, #-16]! | ||
; CHECK-NEXT: .cfi_def_cfa_offset 16 | ||
; CHECK-NEXT: ldp x9, x8, [sp], #16 | ||
; CHECK-NEXT: and x8, x8, #0x7fffffffffffffff | ||
; CHECK-NEXT: eor x8, x8, #0x7fff000000000000 | ||
; CHECK-NEXT: orr x8, x9, x8 | ||
; CHECK-NEXT: cmp x8, #0 | ||
; CHECK-NEXT: cset w0, ne | ||
; CHECK-NEXT: ret | ||
%abs = tail call fp128 @llvm.fabs.f128(fp128 %arg) | ||
%ret = fcmp une fp128 %abs, 0xL00000000000000007FFF000000000000 | ||
ret i1 %ret | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 don't feel great about having SelectionDAGBuilder perform random optimizations. I can see the appeal of reusing the IR implementation of fcmpToClassTest. You would also need to reimplement the same thing in GlobalISel.
Maybe it would be better to do this in CodeGenPrepare?
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 will post an alternative later.