Skip to content

[IR] Allow fast math flags on calls with homogeneous FP struct types #110506

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

Merged
merged 9 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/test/CodeGen/X86/cx-complex-range.c
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ _Complex _Float16 mulf16(_Complex _Float16 a, _Complex _Float16 b) {
// FULL_FAST-NEXT: [[C_IMAG:%.*]] = load half, ptr [[C_IMAGP]], align 2
// FULL_FAST-NEXT: [[CONV:%.*]] = fpext half [[C_REAL]] to x86_fp80
// FULL_FAST-NEXT: [[CONV1:%.*]] = fpext half [[C_IMAG]] to x86_fp80
// FULL_FAST-NEXT: [[CALL:%.*]] = call { x86_fp80, x86_fp80 } @__divxc3(x86_fp80 noundef nofpclass(nan inf) [[B_REAL]], x86_fp80 noundef nofpclass(nan inf) [[B_IMAG]], x86_fp80 noundef nofpclass(nan inf) [[CONV]], x86_fp80 noundef nofpclass(nan inf) [[CONV1]]) #[[ATTR1]]
// FULL_FAST-NEXT: [[CALL:%.*]] = call reassoc nnan ninf nsz arcp afn nofpclass(nan inf) { x86_fp80, x86_fp80 } @__divxc3(x86_fp80 noundef nofpclass(nan inf) [[B_REAL]], x86_fp80 noundef nofpclass(nan inf) [[B_IMAG]], x86_fp80 noundef nofpclass(nan inf) [[CONV]], x86_fp80 noundef nofpclass(nan inf) [[CONV1]]) #[[ATTR1]]
// FULL_FAST-NEXT: [[TMP0:%.*]] = extractvalue { x86_fp80, x86_fp80 } [[CALL]], 0
// FULL_FAST-NEXT: [[TMP1:%.*]] = extractvalue { x86_fp80, x86_fp80 } [[CALL]], 1
// FULL_FAST-NEXT: [[CONV2:%.*]] = fptrunc x86_fp80 [[TMP0]] to half
Expand Down
42 changes: 21 additions & 21 deletions clang/test/CodeGen/cx-complex-range.c

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions clang/test/CodeGen/nofpclass.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
}

// CFINITEONLY: Function Attrs: noinline nounwind optnone
// CFINITEONLY-LABEL: define dso_local { double, double } @defined_complex_func_f64_ret
// CFINITEONLY-LABEL: define dso_local nofpclass(nan inf) { double, double } @defined_complex_func_f64_ret
// CFINITEONLY-SAME: (double noundef nofpclass(nan inf) [[C_COERCE0:%.*]], double noundef nofpclass(nan inf) [[C_COERCE1:%.*]]) #[[ATTR0]] {
// CFINITEONLY-NEXT: entry:
// CFINITEONLY-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8
Expand Down Expand Up @@ -548,7 +548,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
// CFINITEONLY-NEXT: [[ISNAN_CMP5:%.*]] = fcmp nnan ninf uno double [[MUL_I]], [[MUL_I]]
// CFINITEONLY-NEXT: br i1 [[ISNAN_CMP5]], label [[COMPLEX_MUL_LIBCALL:%.*]], label [[COMPLEX_MUL_CONT]], !prof [[PROF2]]
// CFINITEONLY: complex_mul_libcall:
// CFINITEONLY-NEXT: [[CALL:%.*]] = call { double, double } @__muldc3(double noundef nofpclass(nan inf) [[C_REAL]], double noundef nofpclass(nan inf) [[C_IMAG]], double noundef nofpclass(nan inf) [[C_REAL2]], double noundef nofpclass(nan inf) [[C_IMAG4]]) #[[ATTR7:[0-9]+]]
// CFINITEONLY-NEXT: [[CALL:%.*]] = call nnan ninf nofpclass(nan inf) { double, double } @__muldc3(double noundef nofpclass(nan inf) [[C_REAL]], double noundef nofpclass(nan inf) [[C_IMAG]], double noundef nofpclass(nan inf) [[C_REAL2]], double noundef nofpclass(nan inf) [[C_IMAG4]]) #[[ATTR7:[0-9]+]]
// CFINITEONLY-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[CALL]], 0
// CFINITEONLY-NEXT: [[TMP3:%.*]] = extractvalue { double, double } [[CALL]], 1
// CFINITEONLY-NEXT: br label [[COMPLEX_MUL_CONT]]
Expand All @@ -563,7 +563,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
// CFINITEONLY-NEXT: ret { double, double } [[TMP4]]
//
// CLFINITEONLY: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
// CLFINITEONLY-LABEL: define dso_local { double, double } @defined_complex_func_f64_ret
// CLFINITEONLY-LABEL: define dso_local nofpclass(nan inf) { double, double } @defined_complex_func_f64_ret
// CLFINITEONLY-SAME: (double noundef nofpclass(nan inf) [[C_COERCE0:%.*]], double noundef nofpclass(nan inf) [[C_COERCE1:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CLFINITEONLY-NEXT: entry:
// CLFINITEONLY-NEXT: [[MUL_AD:%.*]] = fmul nnan ninf double [[C_COERCE0]], [[C_COERCE1]]
Expand All @@ -576,7 +576,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
// CLFINITEONLY-NEXT: ret { double, double } [[DOTFCA_1_INSERT]]
//
// NONANS: Function Attrs: noinline nounwind optnone
// NONANS-LABEL: define dso_local { double, double } @defined_complex_func_f64_ret
// NONANS-LABEL: define dso_local nofpclass(nan) { double, double } @defined_complex_func_f64_ret
// NONANS-SAME: (double noundef nofpclass(nan) [[C_COERCE0:%.*]], double noundef nofpclass(nan) [[C_COERCE1:%.*]]) #[[ATTR0]] {
// NONANS-NEXT: entry:
// NONANS-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8
Expand Down Expand Up @@ -605,7 +605,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
// NONANS-NEXT: [[ISNAN_CMP5:%.*]] = fcmp nnan uno double [[MUL_I]], [[MUL_I]]
// NONANS-NEXT: br i1 [[ISNAN_CMP5]], label [[COMPLEX_MUL_LIBCALL:%.*]], label [[COMPLEX_MUL_CONT]], !prof [[PROF2]]
// NONANS: complex_mul_libcall:
// NONANS-NEXT: [[CALL:%.*]] = call { double, double } @__muldc3(double noundef nofpclass(nan) [[C_REAL]], double noundef nofpclass(nan) [[C_IMAG]], double noundef nofpclass(nan) [[C_REAL2]], double noundef nofpclass(nan) [[C_IMAG4]]) #[[ATTR7:[0-9]+]]
// NONANS-NEXT: [[CALL:%.*]] = call nnan nofpclass(nan) { double, double } @__muldc3(double noundef nofpclass(nan) [[C_REAL]], double noundef nofpclass(nan) [[C_IMAG]], double noundef nofpclass(nan) [[C_REAL2]], double noundef nofpclass(nan) [[C_IMAG4]]) #[[ATTR7:[0-9]+]]
// NONANS-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[CALL]], 0
// NONANS-NEXT: [[TMP3:%.*]] = extractvalue { double, double } [[CALL]], 1
// NONANS-NEXT: br label [[COMPLEX_MUL_CONT]]
Expand All @@ -620,7 +620,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
// NONANS-NEXT: ret { double, double } [[TMP4]]
//
// NOINFS: Function Attrs: noinline nounwind optnone
// NOINFS-LABEL: define dso_local { double, double } @defined_complex_func_f64_ret
// NOINFS-LABEL: define dso_local nofpclass(inf) { double, double } @defined_complex_func_f64_ret
// NOINFS-SAME: (double noundef nofpclass(inf) [[C_COERCE0:%.*]], double noundef nofpclass(inf) [[C_COERCE1:%.*]]) #[[ATTR0]] {
// NOINFS-NEXT: entry:
// NOINFS-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8
Expand Down Expand Up @@ -649,7 +649,7 @@ _Complex float defined_complex_func(_Complex float a, _Complex double b, _Comple
// NOINFS-NEXT: [[ISNAN_CMP5:%.*]] = fcmp ninf uno double [[MUL_I]], [[MUL_I]]
// NOINFS-NEXT: br i1 [[ISNAN_CMP5]], label [[COMPLEX_MUL_LIBCALL:%.*]], label [[COMPLEX_MUL_CONT]], !prof [[PROF2]]
// NOINFS: complex_mul_libcall:
// NOINFS-NEXT: [[CALL:%.*]] = call { double, double } @__muldc3(double noundef nofpclass(inf) [[C_REAL]], double noundef nofpclass(inf) [[C_IMAG]], double noundef nofpclass(inf) [[C_REAL2]], double noundef nofpclass(inf) [[C_IMAG4]]) #[[ATTR7:[0-9]+]]
// NOINFS-NEXT: [[CALL:%.*]] = call ninf nofpclass(inf) { double, double } @__muldc3(double noundef nofpclass(inf) [[C_REAL]], double noundef nofpclass(inf) [[C_IMAG]], double noundef nofpclass(inf) [[C_REAL2]], double noundef nofpclass(inf) [[C_IMAG4]]) #[[ATTR7:[0-9]+]]
// NOINFS-NEXT: [[TMP2:%.*]] = extractvalue { double, double } [[CALL]], 0
// NOINFS-NEXT: [[TMP3:%.*]] = extractvalue { double, double } [[CALL]], 1
// NOINFS-NEXT: br label [[COMPLEX_MUL_CONT]]
Expand Down
49 changes: 29 additions & 20 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1499,11 +1499,12 @@ Currently, only the following parameter attributes are defined:
``nofpclass(<test mask>)``
This attribute applies to parameters and return values with
floating-point and vector of floating-point types, as well as
arrays of such types. The test mask has the same format as the
second argument to the :ref:`llvm.is.fpclass <llvm.is.fpclass>`,
and indicates which classes of floating-point values are not
permitted for the value. For example a bitmask of 3 indicates
the parameter may not be a NaN.
:ref:`supported aggregates <fastmath_return_types>` of such types
(matching the supported types for :ref:`fast-math flags <fastmath>`).
The test mask has the same format as the second argument to the
:ref:`llvm.is.fpclass <llvm.is.fpclass>`, and indicates which classes
of floating-point values are not permitted for the value. For example
a bitmask of 3 indicates the parameter may not be a NaN.

If the value is a floating-point class indicated by the
``nofpclass`` test mask, a :ref:`poison value <poisonvalues>` is
Expand Down Expand Up @@ -3685,9 +3686,9 @@ Fast-Math Flags

LLVM IR floating-point operations (:ref:`fneg <i_fneg>`, :ref:`fadd <i_fadd>`,
:ref:`fsub <i_fsub>`, :ref:`fmul <i_fmul>`, :ref:`fdiv <i_fdiv>`,
:ref:`frem <i_frem>`, :ref:`fcmp <i_fcmp>`), :ref:`phi <i_phi>`,
:ref:`select <i_select>` and :ref:`call <i_call>`
may use the following flags to enable otherwise unsafe
:ref:`frem <i_frem>`, :ref:`fcmp <i_fcmp>`), and :ref:`phi <i_phi>`,
:ref:`select <i_select>`, or :ref:`call <i_call>` instructions that return
floating-point types may use the following flags to enable otherwise unsafe
floating-point transformations.

``fast``
Expand All @@ -3709,6 +3710,16 @@ floating-point transformations.
argument or zero result as insignificant. This does not imply that -0.0
is poison and/or guaranteed to not exist in the operation.

Note: For :ref:`phi <i_phi>`, :ref:`select <i_select>`, and :ref:`call <i_call>`
instructions, the following return types are considered to be floating-point
types:

.. _fastmath_return_types:

- Floating-point scalar or vector types
- Array types (nested to any depth) of floating-point scalar or vector types
- Homogeneous literal struct types of floating-point scalar or vector types

Rewrite-based flags
^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -4343,7 +4354,7 @@ recursive, can be opaqued, and are never uniqued.
:Examples:

+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``{ i32, i32, i32 }`` | A triple of three ``i32`` values |
| ``{ i32, i32, i32 }`` | A triple of three ``i32`` values (this is a "homogeneous" struct as all element types are the same) |
+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``{ float, ptr }`` | A pair, where the first element is a ``float`` and the second element is a :ref:`pointer <t_pointer>`. |
+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Expand Down Expand Up @@ -12472,9 +12483,8 @@ instruction's return value on the same edge).
The optional ``fast-math-flags`` marker indicates that the phi has one
or more :ref:`fast-math-flags <fastmath>`. These are optimization hints
to enable otherwise unsafe floating-point optimizations. Fast-math-flags
are only valid for phis that return a floating-point scalar or vector
type, or an array (nested to any depth) of floating-point scalar or vector
types.
are only valid for phis that return :ref:`supported floating-point types
<fastmath_return_types>`.

Semantics:
""""""""""
Expand Down Expand Up @@ -12523,8 +12533,8 @@ class <t_firstclass>` type.
#. The optional ``fast-math flags`` marker indicates that the select has one or more
:ref:`fast-math flags <fastmath>`. These are optimization hints to enable
otherwise unsafe floating-point optimizations. Fast-math flags are only valid
for selects that return a floating-point scalar or vector type, or an array
(nested to any depth) of floating-point scalar or vector types.
for selects that return :ref:`supported floating-point types
<fastmath_return_types>`..

Semantics:
""""""""""
Expand Down Expand Up @@ -12762,8 +12772,7 @@ This instruction requires several arguments:
#. The optional ``fast-math flags`` marker indicates that the call has one or more
:ref:`fast-math flags <fastmath>`, which are optimization hints to enable
otherwise unsafe floating-point optimizations. Fast-math flags are only valid
for calls that return a floating-point scalar or vector type, or an array
(nested to any depth) of floating-point scalar or vector types.
for calls that return :ref:`supported floating-point types <fastmath_return_types>`.

#. The optional "cconv" marker indicates which :ref:`calling
convention <callingconv>` the call should use. If none is
Expand Down Expand Up @@ -20527,8 +20536,8 @@ the explicit vector length.
#. The optional ``fast-math flags`` marker indicates that the select has one or
more :ref:`fast-math flags <fastmath>`. These are optimization hints to
enable otherwise unsafe floating-point optimizations. Fast-math flags are
only valid for selects that return a floating-point scalar or vector type,
or an array (nested to any depth) of floating-point scalar or vector types.
only valid for selects that return :ref:`supported floating-point types
<fastmath_return_types>`.

Semantics:
""""""""""
Expand Down Expand Up @@ -20585,8 +20594,8 @@ is the pivot.
#. The optional ``fast-math flags`` marker indicates that the merge has one or
more :ref:`fast-math flags <fastmath>`. These are optimization hints to
enable otherwise unsafe floating-point optimizations. Fast-math flags are
only valid for merges that return a floating-point scalar or vector type,
or an array (nested to any depth) of floating-point scalar or vector types.
only valid for merges that return :ref:`supported floating-point types
<fastmath_return_types>`.

Semantics:
""""""""""
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/DerivedTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ class StructType : public Type {
/// {<vscale x 2 x i32>, <vscale x 4 x i64>}}
bool containsHomogeneousScalableVectorTypes() const;

/// Return true if this struct is non-empty and all element types are the
/// same.
bool containsHomogeneousTypes() const;

/// Return true if this is a named struct that has a non-empty name.
bool hasName() const { return SymbolTableEntry != nullptr; }

Expand Down
27 changes: 23 additions & 4 deletions llvm/include/llvm/IR/Operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,21 @@ class FPMathOperator : public Operator {
SubclassOptionalData = FMF.Flags;
}

/// Returns true if `Ty` is composed of a single kind of float-poing type
/// (possibly repeated within an aggregate).
static bool isComposedOfHomogeneousFloatingPointTypes(Type *Ty) {
if (auto *StructTy = dyn_cast<StructType>(Ty)) {
if (!StructTy->isLiteral() || !StructTy->containsHomogeneousTypes())
return false;
Ty = StructTy->elements().front();
} else if (auto *ArrayTy = dyn_cast<ArrayType>(Ty)) {
do {
Ty = ArrayTy->getElementType();
} while ((ArrayTy = dyn_cast<ArrayType>(Ty)));
}
return Ty->isFPOrFPVectorTy();
};

public:
/// Test if this operation allows all non-strict floating-point transforms.
bool isFast() const {
Expand Down Expand Up @@ -326,6 +341,13 @@ class FPMathOperator : public Operator {
/// precision.
float getFPAccuracy() const;

/// Returns true if `Ty` is a supported floating-point type for phi, select,
/// or call FPMathOperators.
static bool isSupportedFloatingPointType(Type *Ty) {
return Ty->isFPOrFPVectorTy() ||
isComposedOfHomogeneousFloatingPointTypes(Ty);
}

static bool classof(const Value *V) {
unsigned Opcode;
if (auto *I = dyn_cast<Instruction>(V))
Expand All @@ -350,10 +372,7 @@ class FPMathOperator : public Operator {
case Instruction::PHI:
case Instruction::Select:
case Instruction::Call: {
Type *Ty = V->getType();
while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))
Ty = ArrTy->getElementType();
return Ty->isFPOrFPVectorTy();
return isSupportedFloatingPointType(V->getType());
}
default:
return false;
Expand Down
7 changes: 2 additions & 5 deletions llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "llvm/IR/ConstantRangeList.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -2091,12 +2092,8 @@ bool AttrBuilder::operator==(const AttrBuilder &B) const {

/// Returns true if this is a type legal for the 'nofpclass' attribute. This
/// follows the same type rules as FPMathOperator.
///
/// TODO: Consider relaxing to any FP type struct fields.
bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) {
while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))
Ty = ArrTy->getElementType();
return Ty->isFPOrFPVectorTy();
return FPMathOperator::isSupportedFloatingPointType(Ty);
}

/// Which attributes cannot be applied to a type.
Expand Down
13 changes: 7 additions & 6 deletions llvm/lib/IR/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,14 @@ bool StructType::containsScalableVectorType(
}

bool StructType::containsHomogeneousScalableVectorTypes() const {
Type *FirstTy = getNumElements() > 0 ? elements()[0] : nullptr;
if (!FirstTy || !isa<ScalableVectorType>(FirstTy))
if (getNumElements() <= 0 || !isa<ScalableVectorType>(elements().front()))
return false;
for (Type *Ty : elements())
if (Ty != FirstTy)
return false;
return true;
return containsHomogeneousTypes();
}

bool StructType::containsHomogeneousTypes() const {
ArrayRef<Type *> ElementTys = elements();
return !ElementTys.empty() && all_equal(ElementTys);
}

void StructType::setBody(ArrayRef<Type*> Elements, bool isPacked) {
Expand Down
31 changes: 30 additions & 1 deletion llvm/test/Bitcode/compatibility.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,26 @@ define void @fastMathFlagsForArrayCalls([2 x float] %f, [2 x double] %d1, [2 x <
ret void
}

declare { float, float } @fmf_struct_f32()
declare { double, double, double } @fmf_struct_f64()
declare { <4 x double> } @fmf_struct_v4f64()

; CHECK-LABEL: fastMathFlagsForStructCalls(
define void @fastMathFlagsForStructCalls() {
%call.fast = call fast { float, float } @fmf_struct_f32()
; CHECK: %call.fast = call fast { float, float } @fmf_struct_f32()

; Throw in some other attributes to make sure those stay in the right places.

%call.nsz.arcp = notail call nsz arcp { double, double, double } @fmf_struct_f64()
; CHECK: %call.nsz.arcp = notail call nsz arcp { double, double, double } @fmf_struct_f64()

%call.nnan.ninf = tail call nnan ninf fastcc { <4 x double> } @fmf_struct_v4f64()
; CHECK: %call.nnan.ninf = tail call nnan ninf fastcc { <4 x double> } @fmf_struct_v4f64()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about struct of array?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add a test, but it's not a supported case (as I don't currently see a need for it).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a test with nofpclass attributes on the return / argument? The intent was it would be allowed for the same types as FPMathOperator

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nofpclass used a separate check, so I had to update it to support struct types (in the last commit). Not sure if it should be part of this PR, or moved to a later PR though?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way

ret void
}

;; Type System
%opaquety = type opaque
define void @typesystem() {
Expand Down Expand Up @@ -2077,9 +2097,14 @@ declare nofpclass(sub zero) float @nofpclass_sub_zero(float nofpclass(sub zero))
; CHECK: declare nofpclass(inf sub) float @nofpclass_sub_inf(float nofpclass(inf sub))
declare nofpclass(sub inf) float @nofpclass_sub_inf(float nofpclass(sub inf))

; CHECK: declare nofpclass(nan) { float, float } @nofpclass_struct({ double } nofpclass(nan))
declare nofpclass(nan) { float, float } @nofpclass_struct({ double } nofpclass(nan))

declare float @unknown_fpclass_func(float)

define float @nofpclass_callsites(float %arg) {
declare { <4 x double>, <4 x double>, <4 x double> } @unknown_fpclass_struct_func({ float })

define float @nofpclass_callsites(float %arg, { float } %arg1) {
; CHECK: %call0 = call nofpclass(nan) float @unknown_fpclass_func(float nofpclass(ninf) %arg)
%call0 = call nofpclass(nan) float @unknown_fpclass_func(float nofpclass(ninf) %arg)

Expand All @@ -2088,6 +2113,10 @@ define float @nofpclass_callsites(float %arg) {

; CHECK: %call2 = call nofpclass(zero) float @unknown_fpclass_func(float nofpclass(norm) %arg)
%call2 = call nofpclass(zero) float @unknown_fpclass_func(float nofpclass(norm) %arg)

; CHECK: %call3 = call nofpclass(pinf) { <4 x double>, <4 x double>, <4 x double> } @unknown_fpclass_struct_func({ float } nofpclass(all) %arg1)
%call3 = call nofpclass(pinf) { <4 x double>, <4 x double>, <4 x double> } @unknown_fpclass_struct_func({ float } nofpclass(all) %arg1)

%add0 = fadd float %call0, %call1
%add1 = fadd float %add0, %call2
ret float %add1
Expand Down
Loading
Loading