From e595a2c9644cd70f506a968acec1ea9b6dafa5e6 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 10 Jul 2019 16:31:15 +0000 Subject: [PATCH] GlobalISel: Define the full family of FP min/max instructions llvm-svn: 365657 --- llvm/include/llvm/Support/TargetOpcodes.def | 12 +++ llvm/include/llvm/Target/GenericOpcodes.td | 56 ++++++++++++++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 8 ++ .../irtranslator-fp-min-max-intrinsics.ll | 88 ++++++++++++++++++++++ .../GlobalISel/legalizer-info-validation.mir | 18 +++++ 5 files changed, 182 insertions(+) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fp-min-max-intrinsics.ll diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index fa02463..598c106 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -493,6 +493,18 @@ HANDLE_TARGET_OPCODE(G_FCOPYSIGN) /// Generic FP canonicalize value. HANDLE_TARGET_OPCODE(G_FCANONICALIZE) +/// FP min/max matching libm's fmin/fmax +HANDLE_TARGET_OPCODE(G_FMINNUM) +HANDLE_TARGET_OPCODE(G_FMAXNUM) + +/// FP min/max matching IEEE-754 2008's minnum/maxnum semantics. +HANDLE_TARGET_OPCODE(G_FMINNUM_IEEE) +HANDLE_TARGET_OPCODE(G_FMAXNUM_IEEE) + +/// FP min/max matching IEEE-754 2018 draft semantics. +HANDLE_TARGET_OPCODE(G_FMINIMUM) +HANDLE_TARGET_OPCODE(G_FMAXIMUM) + /// Generic pointer offset HANDLE_TARGET_OPCODE(G_GEP) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index 11fbf62..4571832 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -505,6 +505,62 @@ def G_FCANONICALIZE : GenericInstruction { let hasSideEffects = 0; } +// FMINNUM/FMAXNUM - Perform floating-point minimum or maximum on two +// values. +// +// In the case where a single input is a NaN (either signaling or quiet), +// the non-NaN input is returned. +// +// The return value of (FMINNUM 0.0, -0.0) could be either 0.0 or -0.0. +def G_FMINNUM : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +def G_FMAXNUM : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +// FMINNUM_IEEE/FMAXNUM_IEEE - Perform floating-point minimum or maximum on +// two values, following the IEEE-754 2008 definition. This differs from +// FMINNUM/FMAXNUM in the handling of signaling NaNs. If one input is a +// signaling NaN, returns a quiet NaN. +def G_FMINNUM_IEEE : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +def G_FMAXNUM_IEEE : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +// FMINIMUM/FMAXIMUM - NaN-propagating minimum/maximum that also treat -0.0 +// as less than 0.0. While FMINNUM_IEEE/FMAXNUM_IEEE follow IEEE 754-2008 +// semantics, FMINIMUM/FMAXIMUM follow IEEE 754-2018 draft semantics. +def G_FMINIMUM : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + +def G_FMAXIMUM : GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2); + let hasSideEffects = 0; + let isCommutable = 1; +} + //------------------------------------------------------------------------------ // Floating Point Binary ops. //------------------------------------------------------------------------------ diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 96efcf7..6e99bdb 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1222,6 +1222,14 @@ unsigned IRTranslator::getSimpleIntrinsicOpcode(Intrinsic::ID ID) { return TargetOpcode::G_FABS; case Intrinsic::copysign: return TargetOpcode::G_FCOPYSIGN; + case Intrinsic::minnum: + return TargetOpcode::G_FMINNUM; + case Intrinsic::maxnum: + return TargetOpcode::G_FMAXNUM; + case Intrinsic::minimum: + return TargetOpcode::G_FMINIMUM; + case Intrinsic::maximum: + return TargetOpcode::G_FMAXIMUM; case Intrinsic::canonicalize: return TargetOpcode::G_FCANONICALIZE; case Intrinsic::floor: diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fp-min-max-intrinsics.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fp-min-max-intrinsics.ll new file mode 100644 index 0000000..ff92d4c --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-fp-min-max-intrinsics.ll @@ -0,0 +1,88 @@ +; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +; RUN: llc -mtriple=aarch64-- -verify-machineinstrs -global-isel -stop-after=irtranslator -o - %s | FileCheck %s + +define float @test_minnum(float %x, float %y) { + ; CHECK-LABEL: name: test_minnum + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $s0, $s1 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1 + ; CHECK: [[FMINNUM:%[0-9]+]]:_(s32) = G_FMINNUM [[COPY]], [[COPY1]] + ; CHECK: $s0 = COPY [[FMINNUM]](s32) + ; CHECK: RET_ReallyLR implicit $s0 + %val = call float @llvm.minnum.f32(float %x, float %y) + ret float %val +} + +define float @test_minnum_nnan(float %x, float %y) { + ; CHECK-LABEL: name: test_minnum_nnan + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $s0, $s1 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1 + ; CHECK: %2:_(s32) = nnan G_FMINNUM [[COPY]], [[COPY1]] + ; CHECK: $s0 = COPY %2(s32) + ; CHECK: RET_ReallyLR implicit $s0 + %val = call nnan float @llvm.minnum.f32(float %x, float %y) + ret float %val +} + +define float @test_maxnum(float %x, float %y) { + ; CHECK-LABEL: name: test_maxnum + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $s0, $s1 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1 + ; CHECK: [[FMAXNUM:%[0-9]+]]:_(s32) = G_FMAXNUM [[COPY]], [[COPY1]] + ; CHECK: $s0 = COPY [[FMAXNUM]](s32) + ; CHECK: RET_ReallyLR implicit $s0 + %val = call float @llvm.maxnum.f32(float %x, float %y) + ret float %val +} + +define float @test_minimum(float %x, float %y) { + ; CHECK-LABEL: name: test_minimum + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $s0, $s1 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1 + ; CHECK: [[FMINIMUM:%[0-9]+]]:_(s32) = G_FMINIMUM [[COPY]], [[COPY1]] + ; CHECK: $s0 = COPY [[FMINIMUM]](s32) + ; CHECK: RET_ReallyLR implicit $s0 + %val = call float @llvm.minimum.f32(float %x, float %y) + ret float %val +} + +define float @test_minimum_nnan(float %x, float %y) { + ; CHECK-LABEL: name: test_minimum_nnan + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $s0, $s1 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1 + ; CHECK: %2:_(s32) = nnan G_FMINIMUM [[COPY]], [[COPY1]] + ; CHECK: $s0 = COPY %2(s32) + ; CHECK: RET_ReallyLR implicit $s0 + %val = call nnan float @llvm.minimum.f32(float %x, float %y) + ret float %val +} + +define float @test_maximum(float %x, float %y) { + ; CHECK-LABEL: name: test_maximum + ; CHECK: bb.1 (%ir-block.0): + ; CHECK: liveins: $s0, $s1 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $s0 + ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $s1 + ; CHECK: [[FMAXIMUM:%[0-9]+]]:_(s32) = G_FMAXIMUM [[COPY]], [[COPY1]] + ; CHECK: $s0 = COPY [[FMAXIMUM]](s32) + ; CHECK: RET_ReallyLR implicit $s0 + %val = call float @llvm.maximum.f32(float %x, float %y) + ret float %val +} + +declare float @llvm.minnum.f32(float, float) #0 +declare float @llvm.maxnum.f32(float, float) #0 + +declare float @llvm.minimum.f32(float, float) #0 +declare float @llvm.maximum.f32(float, float) #0 + +attributes #0 = { nounwind readnone speculatable } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir index 37bd3c8..6b27848 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -303,6 +303,24 @@ # DEBUG-NEXT: G_FCANONICALIZE (opcode {{[0-9]+}}): 1 type index # DEBUG: .. type index coverage check SKIPPED: no rules defined # +# DEBUG-NEXT: G_FMINNUM (opcode 131): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FMAXNUM (opcode 132): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FMINNUM_IEEE (opcode 133): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FMAXNUM_IEEE (opcode 134): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FMINIMUM (opcode 135): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# +# DEBUG-NEXT: G_FMAXIMUM (opcode 136): 1 type index +# DEBUG: .. type index coverage check SKIPPED: no rules defined +# # DEBUG-NEXT: G_GEP (opcode {{[0-9]+}}): 2 type indices # DEBUG: .. the first uncovered type index: 2, OK # -- 2.7.4