PIPE_OPERATOR(AAPotentialConstantValues)
PIPE_OPERATOR(AAPotentialValues)
PIPE_OPERATOR(AANoUndef)
+PIPE_OPERATOR(AANoFPClass)
PIPE_OPERATOR(AACallEdges)
PIPE_OPERATOR(AAInterFnReachability)
PIPE_OPERATOR(AAPointerInfo)
void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(noundef) }
};
+/// ------------------------ NoFPClass Attribute -------------------------------
+
+struct AANoFPClassImpl : AANoFPClass {
+ AANoFPClassImpl(const IRPosition &IRP, Attributor &A) : AANoFPClass(IRP, A) {}
+
+ void initialize(Attributor &A) override {
+ const IRPosition &IRP = getIRPosition();
+
+ Value &V = IRP.getAssociatedValue();
+ if (isa<UndefValue>(V)) {
+ indicateOptimisticFixpoint();
+ return;
+ }
+
+ SmallVector<Attribute> Attrs;
+ IRP.getAttrs({Attribute::NoFPClass}, Attrs, false, &A);
+ if (!Attrs.empty()) {
+ addKnownBits(Attrs[0].getNoFPClass());
+ return;
+ }
+
+ const DataLayout &DL = A.getDataLayout();
+ if (getPositionKind() != IRPosition::IRP_RETURNED) {
+ KnownFPClass KnownFPClass = computeKnownFPClass(&V, DL);
+ addKnownBits(~KnownFPClass.KnownFPClasses);
+ }
+ }
+
+ const std::string getAsStr() const override {
+ std::string Result = "nofpclass";
+ raw_string_ostream OS(Result);
+ OS << getAssumedNoFPClass();
+ return Result;
+ }
+
+ void getDeducedAttributes(LLVMContext &Ctx,
+ SmallVectorImpl<Attribute> &Attrs) const override {
+ Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));
+ }
+};
+
+struct AANoFPClassFloating : public AANoFPClassImpl {
+ AANoFPClassFloating(const IRPosition &IRP, Attributor &A)
+ : AANoFPClassImpl(IRP, A) {}
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ return indicatePessimisticFixpoint();
+ }
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_FNRET_ATTR(nofpclass)
+ }
+};
+
+struct AANoFPClassReturned final
+ : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl> {
+ AANoFPClassReturned(const IRPosition &IRP, Attributor &A)
+ : AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl>(IRP, A) {}
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_FNRET_ATTR(nofpclass)
+ }
+};
+
+struct AANoFPClassArgument final
+ : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {
+ AANoFPClassArgument(const IRPosition &IRP, Attributor &A)
+ : AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP, A) {}
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nofpclass) }
+};
+
+struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {
+ AANoFPClassCallSiteArgument(const IRPosition &IRP, Attributor &A)
+ : AANoFPClassFloating(IRP, A) {}
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_CSARG_ATTR(nofpclass)
+ }
+};
+
+struct AANoFPClassCallSiteReturned final
+ : AACallSiteReturnedFromReturned<AANoFPClass, AANoFPClassImpl> {
+ AANoFPClassCallSiteReturned(const IRPosition &IRP, Attributor &A)
+ : AACallSiteReturnedFromReturned<AANoFPClass, AANoFPClassImpl>(IRP, A) {}
+
+ /// See AbstractAttribute::trackStatistics()
+ void trackStatistics() const override {
+ STATS_DECLTRACK_CSRET_ATTR(nofpclass)
+ }
+};
+
struct AACallEdgesImpl : public AACallEdges {
AACallEdgesImpl(const IRPosition &IRP, Attributor &A) : AACallEdges(IRP, A) {}
const char AAPotentialConstantValues::ID = 0;
const char AAPotentialValues::ID = 0;
const char AANoUndef::ID = 0;
+const char AANoFPClass::ID = 0;
const char AACallEdges::ID = 0;
const char AAInterFnReachability::ID = 0;
const char AAPointerInfo::ID = 0;
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPotentialConstantValues)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPotentialValues)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUndef)
+CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFPClass)
CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPointerInfo)
CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify)
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --version 2
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --version 2
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
declare i1 @llvm.is.fpclass.f32(float, i32 immarg)
define float @returned_0() {
-; CHECK-LABEL: define noundef float @returned_0() {
+; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @returned_0() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret float 0.000000e+00
;
}
define float @returned_neg0() {
-; CHECK-LABEL: define noundef float @returned_neg0() {
+; CHECK-LABEL: define noundef nofpclass(nan inf pzero sub norm) float @returned_neg0() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret float -0.000000e+00
;
}
define float @returned_undef() {
-; CHECK-LABEL: define float @returned_undef() {
+; CHECK-LABEL: define nofpclass(all) float @returned_undef() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret float undef
;
}
define float @returned_poison() {
-; CHECK-LABEL: define float @returned_poison() {
+; CHECK-LABEL: define nofpclass(all) float @returned_poison() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret float poison
;
}
define double @returned_snan() {
-; CHECK-LABEL: define noundef double @returned_snan() {
+; CHECK-LABEL: define noundef nofpclass(qnan inf zero sub norm) double @returned_snan() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret double 0x7FF0000000000001
;
}
define double @returned_qnan() {
-; CHECK-LABEL: define noundef double @returned_qnan() {
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub norm) double @returned_qnan() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret double 0x7FF8000000000000
;
}
define <2 x double> @returned_zero_vector() {
-; CHECK-LABEL: define noundef <2 x double> @returned_zero_vector() {
+; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) <2 x double> @returned_zero_vector() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret <2 x double> zeroinitializer
;
}
define <2 x double> @returned_negzero_vector() {
-; CHECK-LABEL: define noundef <2 x double> @returned_negzero_vector() {
+; CHECK-LABEL: define noundef nofpclass(nan inf pzero sub norm) <2 x double> @returned_negzero_vector() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
;
; Return a float trivially nofpclass(nan) (call return attribute)
define float @return_nofpclass_nan_decl_return() {
-; CHECK-LABEL: define float @return_nofpclass_nan_decl_return() {
-; CHECK-NEXT: [[RET:%.*]] = call float @ret_nofpclass_nan()
+; CHECK-LABEL: define nofpclass(nan) float @return_nofpclass_nan_decl_return() {
+; CHECK-NEXT: [[RET:%.*]] = call nofpclass(nan) float @ret_nofpclass_nan()
; CHECK-NEXT: ret float [[RET]]
;
%ret = call float @ret_nofpclass_nan()
; Return a float trivially nofpclass(nan) (argument attribute)
define float @return_nofpclass_nan_arg(float returned nofpclass(nan) %p) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @return_nofpclass_nan_arg
+; CHECK-LABEL: define nofpclass(nan) float @return_nofpclass_nan_arg
; CHECK-SAME: (float returned nofpclass(nan) [[P:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: ret float [[P]]
;
}
define [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
-; CHECK-LABEL: define [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
+; CHECK-LABEL: define nofpclass(inf) [2 x [3 x float]] @return_nofpclass_inf_ret_array() {
; CHECK-NEXT: [[RET:%.*]] = call nofpclass(inf) [2 x [3 x float]] @ret_array()
; CHECK-NEXT: ret [2 x [3 x float]] [[RET]]
;
define float @returned_nnan_fadd(float %arg0, float %arg1) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CHECK-LABEL: define float @returned_nnan_fadd
+; CHECK-LABEL: define nofpclass(nan) float @returned_nnan_fadd
; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR2]] {
; CHECK-NEXT: [[FADD:%.*]] = fadd nnan float [[ARG0]], [[ARG1]]
; CHECK-NEXT: ret float [[FADD]]
}
define float @return_nofpclass_nan_callsite() {
-; CHECK-LABEL: define float @return_nofpclass_nan_callsite() {
+; CHECK-LABEL: define nofpclass(nan) float @return_nofpclass_nan_callsite() {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @extern()
; CHECK-NEXT: ret float [[CALL]]
;
; Can union the return classes
define nofpclass(inf) float @return_ninf_nofpclass_nan_callsite() {
-; CHECK-LABEL: define nofpclass(inf) float @return_ninf_nofpclass_nan_callsite() {
+; CHECK-LABEL: define nofpclass(nan inf) float @return_ninf_nofpclass_nan_callsite() {
; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan) float @extern()
; CHECK-NEXT: ret float [[CALL]]
;
define void @ninf_arg_used_by_callsite_array([2 x [3 x float]] nofpclass(inf) %arg) {
; CHECK-LABEL: define void @ninf_arg_used_by_callsite_array
; CHECK-SAME: ([2 x [3 x float]] nofpclass(inf) [[ARG:%.*]]) {
-; CHECK-NEXT: call void @extern.use.array([2 x [3 x float]] [[ARG]])
+; CHECK-NEXT: call void @extern.use.array([2 x [3 x float]] nofpclass(inf) [[ARG]])
; CHECK-NEXT: ret void
;
call void @extern.use.array([2 x [3 x float]] %arg)
define float @mutually_recursive0(float %arg) {
; TUNIT: Function Attrs: nofree nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define float @mutually_recursive0
+; TUNIT-LABEL: define nofpclass(all) float @mutually_recursive0
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR3:[0-9]+]] {
; TUNIT-NEXT: ret float undef
;
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define float @mutually_recursive0
+; CGSCC-LABEL: define nofpclass(all) float @mutually_recursive0
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: ret float undef
;
define float @mutually_recursive1(float %arg) {
; TUNIT: Function Attrs: nofree nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define float @mutually_recursive1
+; TUNIT-LABEL: define nofpclass(all) float @mutually_recursive1
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: ret float undef
;
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define float @mutually_recursive1
+; CGSCC-LABEL: define nofpclass(all) float @mutually_recursive1
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
; CGSCC-NEXT: ret float undef
;
}
define float @recursive_phi(ptr %ptr) {
-; CHECK-LABEL: define float @recursive_phi
+; CHECK-LABEL: define nofpclass(nan) float @recursive_phi
; CHECK-SAME: (ptr nofree [[PTR:%.*]]) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[RET:%.*]] = call float @ret_nofpclass_nan()
+; CHECK-NEXT: [[RET:%.*]] = call nofpclass(nan) float @ret_nofpclass_nan()
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[PHI:%.*]] = phi float [ [[RET]], [[ENTRY:%.*]] ], [ [[RET]], [[LOOP]] ]
}
define internal float @returned_dead() {
-; CHECK-LABEL: define internal float @returned_dead() {
+; CHECK-LABEL: define internal nofpclass(nan inf nzero sub norm) float @returned_dead() {
; CHECK-NEXT: call void @unknown()
; CHECK-NEXT: ret float undef
;
define internal float @only_nofpclass_inf_callers(float %arg) {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define internal float @only_nofpclass_inf_callers
-; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
+; CHECK-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR2]] {
; CHECK-NEXT: [[ADD:%.*]] = fadd float [[ARG]], [[ARG]]
; CHECK-NEXT: ret float [[ADD]]
;
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; TUNIT-LABEL: define float @call_noinf_0
; TUNIT-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR2]] {
-; TUNIT-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float [[ARG]]) #[[ATTR5:[0-9]+]]
+; TUNIT-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR5:[0-9]+]]
; TUNIT-NEXT: ret float [[RESULT]]
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define float @call_noinf_0
; CGSCC-SAME: (float nofpclass(inf) [[ARG:%.*]]) #[[ATTR3:[0-9]+]] {
-; CGSCC-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float [[ARG]]) #[[ATTR4]]
+; CGSCC-NEXT: [[RESULT:%.*]] = call float @only_nofpclass_inf_callers(float nofpclass(inf) [[ARG]]) #[[ATTR4]]
; CGSCC-NEXT: ret float [[RESULT]]
;
%result = call float @only_nofpclass_inf_callers(float %arg)
define float @call_noinf_return_0(float %arg) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define float @call_noinf_return_0
+; TUNIT-LABEL: define nofpclass(inf) float @call_noinf_return_0
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
; TUNIT-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR5]]
; TUNIT-NEXT: ret float [[RESULT]]
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define float @call_noinf_return_0
+; CGSCC-LABEL: define nofpclass(inf) float @call_noinf_return_0
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR4]]
; CGSCC-NEXT: ret float [[RESULT]]
define float @call_noinf_return_1(float %arg) {
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
-; TUNIT-LABEL: define float @call_noinf_return_1
+; TUNIT-LABEL: define nofpclass(inf) float @call_noinf_return_1
; TUNIT-SAME: (float [[ARG:%.*]]) #[[ATTR2]] {
; TUNIT-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR5]]
; TUNIT-NEXT: ret float [[RESULT]]
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
-; CGSCC-LABEL: define float @call_noinf_return_1
+; CGSCC-LABEL: define nofpclass(inf) float @call_noinf_return_1
; CGSCC-SAME: (float [[ARG:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[RESULT:%.*]] = call nofpclass(inf) float @only_nofpclass_inf_return_users(float [[ARG]]) #[[ATTR4]]
; CGSCC-NEXT: ret float [[RESULT]]
; CHECK-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
; CHECK: A:
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR4]] [ "nofpclass"(float [[RET]], i32 3) ]
-; CHECK-NEXT: call void @extern.use(float [[RET]])
+; CHECK-NEXT: call void @extern.use(float nofpclass(nan) [[RET]])
; CHECK-NEXT: ret float [[RET]]
; CHECK: B:
; CHECK-NEXT: call void @llvm.assume(i1 noundef true) [ "nofpclass"(float [[RET]], i32 12) ]
-; CHECK-NEXT: call void @extern.use(float [[RET]])
+; CHECK-NEXT: call void @extern.use(float nofpclass(ninf nnorm) [[RET]])
; CHECK-NEXT: ret float [[RET]]
;
entry: