diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst --- a/llvm/docs/GlobalISel/GenericOpcode.rst +++ b/llvm/docs/GlobalISel/GenericOpcode.rst @@ -480,6 +480,16 @@ See :ref:`i_intr_llvm_canonicalize`. +G_IS_FPCLASS +^^^^^^^^^^^^ + +Tests if the first operand, which must be floating-point scalar or vector, has +floating-point class specified by the second operand. The third operand +specifies floating-point semantics of the tested value. Returns non-zero (true) +or zero (false). It's target specific whether a true value is 1, ~0U, or some +other non-zero value. If the first operand is a vector, the returned value is a +vector of the same length. + G_FMINNUM ^^^^^^^^^ diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -155,7 +155,8 @@ S_IEEEdouble, S_x87DoubleExtended, S_IEEEquad, - S_PPCDoubleDouble + S_PPCDoubleDouble, + S_MaxSemantics = S_PPCDoubleDouble }; static const llvm::fltSemantics &EnumToSemantics(Semantics S); diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -620,6 +620,9 @@ /// f64) is allowed. HANDLE_TARGET_OPCODE(G_FCOPYSIGN) +/// Generic test for floating-point class. +HANDLE_TARGET_OPCODE(G_IS_FPCLASS) + /// Generic FP canonicalize value. HANDLE_TARGET_OPCODE(G_FCANONICALIZE) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -745,6 +745,13 @@ let hasSideEffects = false; } +// Generic opcode equivalent to the llvm.is_fpclass intrinsic. +def G_IS_FPCLASS: GenericInstruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type1:$src, unknown:$test, unknown:$fpsem); + let hasSideEffects = false; +} + // FMINNUM/FMAXNUM - Perform floating-point minimum or maximum on two // values. // diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -32,6 +32,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Analysis/EHPersonalities.h" +#include "llvm/CodeGen/CodeGenCommonISel.h" #include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/LiveIntervals.h" #include "llvm/CodeGen/LiveRangeCalc.h" @@ -1650,6 +1651,43 @@ verifyAllRegOpsScalar(*MI, *MRI); break; } + case TargetOpcode::G_IS_FPCLASS: { + LLT DestTy = MRI->getType(MI->getOperand(0).getReg()); + LLT DestEltTy = DestTy.getScalarType(); + if (!DestEltTy.isScalar()) { + report("Destination must be a scalar or vector of scalars", MI); + break; + } + LLT SrcTy = MRI->getType(MI->getOperand(1).getReg()); + LLT SrcEltTy = SrcTy.getScalarType(); + if (!SrcEltTy.isScalar()) { + report("Source must be a scalar or vector of scalars", MI); + break; + } + if (!verifyVectorElementMatch(DestTy, SrcTy, MI)) + break; + const MachineOperand &TestMO = MI->getOperand(2); + if (!TestMO.isImm()) { + report("floating-point class set (operand 2) must be an immediate", MI); + break; + } + int64_t Test = TestMO.getImm(); + if (Test < 0 || Test > fcAllFlags) { + report("Incorrect floating-point class set (operand 2)", MI); + break; + } + const MachineOperand &SemanticsMO = MI->getOperand(3); + if (!SemanticsMO.isImm()) { + report("floating-point semantics (operand 3) must be an immediate", MI); + break; + } + int64_t Semantics = SemanticsMO.getImm(); + if (Semantics < 0 || Semantics > APFloat::S_MaxSemantics) { + report("Incorrect floating-point semantics (operand 3)", MI); + break; + } + break; + } default: break; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir @@ -484,6 +484,9 @@ # DEBUG-NEXT: G_FCOPYSIGN (opcode {{[0-9]+}}): 2 type indices # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined +# DEBUG-NEXT: G_IS_FPCLASS (opcode {{[0-9]+}}): 2 type indices, 0 imm indices +# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined +# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined # DEBUG-NEXT: G_FCANONICALIZE (opcode {{[0-9]+}}): 1 type index, 0 imm indices # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined diff --git a/llvm/test/MachineVerifier/test_g_is_fpclass.mir b/llvm/test/MachineVerifier/test_g_is_fpclass.mir new file mode 100644 --- /dev/null +++ b/llvm/test/MachineVerifier/test_g_is_fpclass.mir @@ -0,0 +1,40 @@ +# RUN: not --crash llc -o - -march=aarch64 -global-isel -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s +# REQUIRES: aarch64-registered-target + +--- +name: test_fcmp +legalized: true +regBankSelected: false +selected: false +tracksRegLiveness: true +liveins: +body: | + bb.0: + liveins: $x0, $w0, $q0 + %s32:_(s32) = COPY $w0 + %ptr:_(p0) = COPY $x0 + %vector:_(<4 x s32>) = COPY $q0 + + %val1:_(s1) = G_IS_FPCLASS %s32, 1 + ; CHECK: *** Bad machine code: Too few operands *** + ; CHECK: 4 operands expected, but 3 given. + + %val2:_(p0) = G_IS_FPCLASS %s32, 3, 2 + ; CHECK: *** Bad machine code: Destination must be a scalar or vector of scalars *** + + %val3:_(s1) = G_IS_FPCLASS %s32, 1, 66 + ; CHECK: *** Bad machine code: Incorrect floating-point semantics (operand 3) *** + + %val4:_(s1) = G_IS_FPCLASS %s32, 7777, 2 + ; CHECK: *** Bad machine code: Incorrect floating-point class set (operand 2) *** + + %val5:_(s1) = G_IS_FPCLASS %ptr:_(p0), 3, 2 + ; CHECK: *** Bad machine code: Source must be a scalar or vector of scalars *** + + %var6:_(s1) = G_IS_FPCLASS %vector:_(<4 x s32>), 1, 2 + ; CHECK: *** Bad machine code: operand types must be all-vector or all-scalar *** + + %var7:_(<2 x s1>) = G_IS_FPCLASS %vector:_(<4 x s32>), 1, 2 + ; CHECK: *** Bad machine code: operand types must preserve number of vector elements *** + +...