-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[IR] Add FPOperation intrinsic property #122313
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
base: users/spavloff/trunc-with-bundles
Are you sure you want to change the base?
Conversation
Currently floating-point operations in general form (beyond the default mode) are always represented by calls to constrained intrinsics. In addition to the side effect, they carry additional information in the form of metadata arguments. This scheme is not efficient in the case of intrinsic function calls, as was noted in https://discourse.llvm.org/t/thought-on-strictfp-support/71453, because it requires defining a separate intrinsic for the same operation but used in non-default FP environment. The solution proposed in the discussion was "to move the complexity about the environment tracking from the intrinsics themselves to the call instruction". The way implemented in this change is to use operand bundles (https://llvm.org/docs/LangRef.html#operand-bundles). This way was tried previously (https://reviews.llvm.org/D93455), but was not finished. This change does not add any new functionality, it only adds the new way of keeping FP related information in LLVM IR. Metadata arguments of constrained functions are preserved, but they are not used in the queries like `getRoundingMode` or `getExceptionBehavior`.
- Fix Doxygen error, - Fix clang-format error, - remove unused function declaration, - remove setting MD_fpmath, it is made by copyMetadata.
Previously the function 'trunc' in non-default floating-point environment was implemented with a special LLVM intrinsic 'experimental.constrained.trunc'. Introduction of floating-point operand bundles allows expressing the interaction with the FP environment using the same intrinsic as for the default mode. This changes removes 'llvm.experimental.constrained.trunc' and use 'llvm.trunc' in all cases.
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-lto Author: Serge Pavlov (spavloff) ChangesThe new intrinsic property marks functions that may have floating-point bundles. It is used in verification of FP bundles. Patch is 24.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122313.diff 24 Files Affected:
diff --git a/clang/test/CodeGen/builtin-sqrt.c b/clang/test/CodeGen/builtin-sqrt.c
index 2313a68d2d0e20..c2056556f61566 100644
--- a/clang/test/CodeGen/builtin-sqrt.c
+++ b/clang/test/CodeGen/builtin-sqrt.c
@@ -11,5 +11,5 @@ float foo(float X) {
// HAS_ERRNO-NOT: attributes [[ATTR]] = {{{.*}} memory(none)
// NO_ERRNO: declare float @llvm.sqrt.f32(float) [[ATTR:#[0-9]+]]
-// NO_ERRNO: attributes [[ATTR]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+// NO_ERRNO: attributes [[ATTR]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/clang/test/CodeGen/libcalls.c b/clang/test/CodeGen/libcalls.c
index 1e4b06e34aaf92..49a80f2d6ee051 100644
--- a/clang/test/CodeGen/libcalls.c
+++ b/clang/test/CodeGen/libcalls.c
@@ -124,4 +124,4 @@ void test_builtins(double d, float f, long double ld) {
}
// CHECK-YES: attributes [[NUW]] = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+x87" }
-// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+// CHECK-NO-DAG: attributes [[NUW_RNI]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl b/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl
index 31f1aa60780b9e..233acd3f0bd729 100644
--- a/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl
+++ b/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl
@@ -165,7 +165,7 @@ kernel void device_side_enqueue(global float *a, global float *b, int i) {
// SPIR32: attributes #[[ATTR0]] = { convergent noinline norecurse nounwind optnone "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "uniform-work-group-size"="true" }
// SPIR32: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
// SPIR32: attributes #[[ATTR2]] = { convergent noinline nounwind optnone "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
-// SPIR32: attributes #[[ATTR3:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+// SPIR32: attributes #[[ATTR3:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
// SPIR32: attributes #[[ATTR4]] = { convergent nounwind "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
//.
// STRICTFP: attributes #[[ATTR0]] = { convergent noinline norecurse nounwind optnone strictfp "stack-protector-buffer-size"="8" "uniform-work-group-size"="false" }
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 41909a8fc1d590..76c9161242e113 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -787,6 +787,7 @@ enum AttributeKindCodes {
ATTR_KIND_CORO_ELIDE_SAFE = 98,
ATTR_KIND_NO_EXT = 99,
ATTR_KIND_NO_DIVERGENCE_SOURCE = 100,
+ ATTR_KIND_FPOPERATION = 101,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 49f4527bde66e7..5515951aff32f1 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -308,6 +308,9 @@ def StackProtectStrong : EnumAttr<"sspstrong", IntersectPreserve, [FnAttr]>;
/// Function was called in a scope requiring strict floating point semantics.
def StrictFP : EnumAttr<"strictfp", IntersectPreserve, [FnAttr]>;
+/// Function is a floating point operation.
+def FPOperation : EnumAttr<"fpoperation", IntersectPreserve, [FnAttr]>;
+
/// Hidden pointer to structure to return.
def StructRet : TypeAttr<"sret", IntersectPreserve, [ParamAttr]>;
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 8d192b0d5cfe00..6b11badf3775f7 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -178,6 +178,10 @@ def IntrSpeculatable : IntrinsicProperty;
// defined by the hasSideEffects property of the TableGen Instruction class.
def IntrHasSideEffects : IntrinsicProperty;
+/// This property indicates that the intrinsic represents a floating-point
+/// operation, and it may have floating-point operand bundles.
+def IntrFPOperation : IntrinsicProperty;
+
//===----------------------------------------------------------------------===//
// IIT constants and utils
//===----------------------------------------------------------------------===//
@@ -1020,7 +1024,7 @@ def int_experimental_memset_pattern
// FIXME: Add version of these floating point intrinsics which allow non-default
// rounding modes and FP exception handling.
-let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
+let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn, IntrFPOperation] in {
def int_fma : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>,
LLVMMatchType<0>]>;
@@ -1089,27 +1093,27 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
def int_minnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_maxnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_minimum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_maximum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_minimumnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_maximumnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
// Internal interface for object size checking
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 02fbb38548d6b9..344c2592f4c039 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2076,6 +2076,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ElementType;
case bitc::ATTR_KIND_FNRETTHUNK_EXTERN:
return Attribute::FnRetThunkExtern;
+ case bitc::ATTR_KIND_FPOPERATION:
+ return Attribute::FPOperation;
case bitc::ATTR_KIND_INLINE_HINT:
return Attribute::InlineHint;
case bitc::ATTR_KIND_IN_REG:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 63f4e34074e06b..932c80895b4771 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -733,6 +733,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION;
case Attribute::FnRetThunkExtern:
return bitc::ATTR_KIND_FNRETTHUNK_EXTERN;
+ case Attribute::FPOperation:
+ return bitc::ATTR_KIND_FPOPERATION;
case Attribute::Hot:
return bitc::ATTR_KIND_HOT;
case Attribute::ElementType:
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index e3fafecacdd2a8..672c61503de4d3 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3799,6 +3799,10 @@ void Verifier::visitCallBase(CallBase &Call) {
"Value of fpe.round bundle operand is not a correct rounding mode",
Call);
FoundFpeRoundBundle = true;
+ Check(!Callee || isa<ConstrainedFPIntrinsic>(Call) ||
+ Callee->hasFnAttribute(Attribute::FPOperation) ||
+ !Callee->isIntrinsic(),
+ "This function call may not have fpe.control bundle", Call);
} else if (Tag == LLVMContext::OB_fpe_except) {
Check(!FoundFpeExceptBundle, "Multiple fpe.except operand bundles", Call);
Check(BU.Inputs.size() == 1,
@@ -3813,6 +3817,10 @@ void Verifier::visitCallBase(CallBase &Call) {
"behavior",
Call);
FoundFpeExceptBundle = true;
+ Check(!Callee || isa<ConstrainedFPIntrinsic>(Call) ||
+ Callee->hasFnAttribute(Attribute::FPOperation) ||
+ !Callee->isIntrinsic(),
+ "This function call may not have fpe.except bundle", Call);
}
}
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 6539f924c2edf4..a0b2e0b32d69e0 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -903,6 +903,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
case Attribute::CoroDestroyOnlyWhenComplete:
case Attribute::CoroElideSafe:
case Attribute::NoDivergenceSource:
+ case Attribute::FPOperation:
continue;
// Those attributes should be safe to propagate to the extracted function.
case Attribute::AlwaysInline:
diff --git a/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll b/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll
index 71c6380177b3a4..d2adb892271290 100644
--- a/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll
+++ b/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll
@@ -780,6 +780,6 @@ define <vscale x 4 x float> @llvm_tanh_vscale_f32(<vscale x 4 x float> %in) #0 {
attributes #0 = { "target-features"="+sve" }
;.
-; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR1]] = { "target-features"="+sve" }
;.
diff --git a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll
index 1d429ece6f8101..e3cbb3592194d1 100644
--- a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll
+++ b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll
@@ -575,5 +575,5 @@ declare <vscale x 2 x double> @llvm.trunc.nxv2f64(<vscale x 2 x double>)
declare <vscale x 4 x float> @llvm.trunc.nxv4f32(<vscale x 4 x float>)
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { "target-features"="+sve" }
-; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+sve" }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+sve" }
;.
diff --git a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll
index ebe5e78667680d..a84a009faa782a 100644
--- a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll
+++ b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll
@@ -573,5 +573,5 @@ declare <4 x float> @llvm.tan.v4f32(<4 x float>)
declare <2 x double> @llvm.trunc.v2f64(<2 x double>)
declare <4 x float> @llvm.trunc.v4f32(<4 x float>)
;.
-; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
;.
diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll
index a2d5ce2d658b57..7b36b3bc9f0a3c 100644
--- a/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll
+++ b/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll
@@ -1491,7 +1491,7 @@ attributes #2 = { noinline }
!0 = !{float 3.0}
;.
; CHECK: attributes #[[ATTR0]] = { strictfp }
-; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR2:[0-9]+]] = { nounwind memory(read) }
; CHECK: attributes #[[ATTR3]] = { noinline }
; CHECK: attributes #[[ATTR4]] = { nobuiltin }
diff --git a/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll b/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll
index 134c2b8932003f..f0752a7fa94692 100644
--- a/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll
+++ b/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll
@@ -488,5 +488,5 @@ declare <vscale x 2 x double> @llvm.trunc.nxv2f64(<vscale x 2 x double>)
declare <vscale x 4 x float> @llvm.trunc.nxv4f32(<vscale x 4 x float>)
;.
; CHECK: attributes #[[ATTR0]] = { "target-features"="+v" }
-; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+v" }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+v" }
;.
diff --git a/llvm/test/Feature/intrinsics.ll b/llvm/test/Feature/intrinsics.ll
index 49fed0981bd766..de0c776ecd9d90 100644
--- a/llvm/test/Feature/intrinsics.ll
+++ b/llvm/test/Feature/intrinsics.ll
@@ -61,7 +61,7 @@ define void @libm() {
; FIXME: test ALL the intrinsics in this file.
; rdar://11542750
-; CHECK: declare void @llvm.trap() #1
+; CHECK: declare void @llvm.trap() #2
declare void @llvm.trap()
define void @trap() {
@@ -70,4 +70,5 @@ define void @trap() {
}
; CHECK: attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-; CHECK: attributes #1 = { cold noreturn nounwind memory(inaccessiblemem: write) }
+; CHECK: attributes #1 = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #2 = { cold noreturn nounwind memory(inaccessiblemem: write) }
diff --git a/llvm/test/Linker/drop-attribute.ll b/llvm/test/Linker/drop-attribute.ll
index 9be95a89109b4e..1208a94e45f870 100644
--- a/llvm/test/Linker/drop-attribute.ll
+++ b/llvm/test/Linker/drop-attribute.ll
@@ -39,7 +39,7 @@ define void @test_nocallback_definition() nocallback {
declare void @test_nocallback_call_site()
; Test that checks that nocallback attribute on an intrinsic is NOT dropped.
-; CHECK: ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn
+; CHECK: ; Function Attrs: fpoperation nocallback nofree nosync nounwind speculatable willreturn
; CHECK-NEXT: declare float @llvm.sqrt.f32(float) #0
declare float @llvm.sqrt.f32(float) nocallback
diff --git a/llvm/test/Transforms/Attributor/nofree.ll b/llvm/test/Transforms/Attributor/nofree.ll
index 10753916dabc60..daafa0443f1eda 100644
--- a/llvm/test/Transforms/Attributor/nofree.ll
+++ b/llvm/test/Transforms/Attributor/nofree.ll
@@ -238,7 +238,7 @@ define void @call_both() #0 {
; TEST 10 (positive case)
; Call intrinsic function
-; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+; CHECK: Function Attrs: fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.floor.f32(float)
define void @call_floor(float %a) #0 {
@@ -489,7 +489,7 @@ attributes #2 = { nobuiltin nounwind }
; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
; TUNIT: attributes #[[ATTR5:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
-; TUNIT: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; TUNIT: attributes #[[ATTR6:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; TUNIT: attributes #[[ATTR7]] = { nofree nounwind }
; TUNIT: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
; TUNIT: attributes #[[ATTR9]] = { nosync memory(none) }
@@ -506,7 +506,7 @@ attributes #2 = { nobuiltin nounwind }
; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
; CGSCC: attributes #[[ATTR4:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CGSCC: attributes #[[ATTR6:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CGSCC: attributes #[[ATTR7]] = { nofree nounwind }
; CGSCC: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
; CGSCC: attributes #[[ATTR9]] = { nosync memory(none) }
diff --git a/llvm/test/Transforms/Attributor/nosync.ll b/llvm/test/Transforms/Attributor/nosync.ll
index 1fbb334b9e47c7..1d82fd59d04971 100644
--- a/llvm/test/Transforms/Attributor/nosync.ll
+++ b/llvm/test/Transforms/Attributor/nosync.ll
@@ -454,7 +454,7 @@ define void @nosync_convergent_callee_test() {
; CHECK: attributes #[[ATTR14:[0-9]+]] = { convergent memory(none) }
; CHECK: attributes #[[ATTR15]] = { memory(none) }
; CHECK: attributes #[[ATTR16]] = { nounwind }
-; CHECK: attributes #[[ATTR17:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR17:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR18]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR19]] = { nosync memory(none) }
; CHECK: attributes #[[ATTR20]] = { nofree nounwind }
diff --git a/llvm/test/Transforms/Attributor/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll
index 4a1f8788a60a55..a03019da4672cf 100644
--- a/llvm/test/Transforms/Attributor/willreturn.ll
+++ b/llvm/test/Transforms/Attributor/willreturn.ll
@@ -276,7 +276,7 @@ define void @conditional_exit(i32 %0, ptr nocapture readonly %1) local_unnamed_a
; TEST 6 (positive case)
; Call intrinsic function
-; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+; CHECK: Function Attrs: fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.floor.f32(float)
define void @call_floor(float %a) #0 {
@@ -1294,7 +1294,7 @@ attributes #1 = { uwtable noinline }
; TUNIT: attributes #[[ATTR5]] = { noreturn }
; TUNIT: attributes #[[ATTR6]] = { noinline noreturn nounwind uwtable }
; TUNIT: attributes #[[ATTR7]] = { noinline nounwind uwtable }
-; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; TUNIT: attributes #[[ATTR8:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; TUNIT: attributes #[[ATTR9:[0-9]+]] = { norecurse willreturn }
; TUNIT: attributes #[[ATTR10]] = { mustprogress noinline nounwind willreturn uwtable }
; TUNIT: attributes #[[ATTR11:[0-9]+]] = { noinline willreturn uwtable }
@@ -1332,7 +1332,7 @@ attributes #1 = { uwtable noinline }
; CGSCC: attributes #[[ATTR5]] = { noreturn }
; CGSCC: attributes #[[ATTR6]] = { noinline noreturn nounwind uwtable }
; CGSCC: attributes #[[ATTR7]] = { noinline nounwind uwtable }
-; CGSCC: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nosync nounwind specula...
[truncated]
|
@llvm/pr-subscribers-clang Author: Serge Pavlov (spavloff) ChangesThe new intrinsic property marks functions that may have floating-point bundles. It is used in verification of FP bundles. Patch is 24.15 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122313.diff 24 Files Affected:
diff --git a/clang/test/CodeGen/builtin-sqrt.c b/clang/test/CodeGen/builtin-sqrt.c
index 2313a68d2d0e20..c2056556f61566 100644
--- a/clang/test/CodeGen/builtin-sqrt.c
+++ b/clang/test/CodeGen/builtin-sqrt.c
@@ -11,5 +11,5 @@ float foo(float X) {
// HAS_ERRNO-NOT: attributes [[ATTR]] = {{{.*}} memory(none)
// NO_ERRNO: declare float @llvm.sqrt.f32(float) [[ATTR:#[0-9]+]]
-// NO_ERRNO: attributes [[ATTR]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+// NO_ERRNO: attributes [[ATTR]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/clang/test/CodeGen/libcalls.c b/clang/test/CodeGen/libcalls.c
index 1e4b06e34aaf92..49a80f2d6ee051 100644
--- a/clang/test/CodeGen/libcalls.c
+++ b/clang/test/CodeGen/libcalls.c
@@ -124,4 +124,4 @@ void test_builtins(double d, float f, long double ld) {
}
// CHECK-YES: attributes [[NUW]] = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+x87" }
-// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+// CHECK-NO-DAG: attributes [[NUW_RNI]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl b/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl
index 31f1aa60780b9e..233acd3f0bd729 100644
--- a/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl
+++ b/clang/test/CodeGenOpenCL/cl20-device-side-enqueue-attributes.cl
@@ -165,7 +165,7 @@ kernel void device_side_enqueue(global float *a, global float *b, int i) {
// SPIR32: attributes #[[ATTR0]] = { convergent noinline norecurse nounwind optnone "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "uniform-work-group-size"="true" }
// SPIR32: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
// SPIR32: attributes #[[ATTR2]] = { convergent noinline nounwind optnone "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
-// SPIR32: attributes #[[ATTR3:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+// SPIR32: attributes #[[ATTR3:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
// SPIR32: attributes #[[ATTR4]] = { convergent nounwind "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
//.
// STRICTFP: attributes #[[ATTR0]] = { convergent noinline norecurse nounwind optnone strictfp "stack-protector-buffer-size"="8" "uniform-work-group-size"="false" }
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 41909a8fc1d590..76c9161242e113 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -787,6 +787,7 @@ enum AttributeKindCodes {
ATTR_KIND_CORO_ELIDE_SAFE = 98,
ATTR_KIND_NO_EXT = 99,
ATTR_KIND_NO_DIVERGENCE_SOURCE = 100,
+ ATTR_KIND_FPOPERATION = 101,
};
enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 49f4527bde66e7..5515951aff32f1 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -308,6 +308,9 @@ def StackProtectStrong : EnumAttr<"sspstrong", IntersectPreserve, [FnAttr]>;
/// Function was called in a scope requiring strict floating point semantics.
def StrictFP : EnumAttr<"strictfp", IntersectPreserve, [FnAttr]>;
+/// Function is a floating point operation.
+def FPOperation : EnumAttr<"fpoperation", IntersectPreserve, [FnAttr]>;
+
/// Hidden pointer to structure to return.
def StructRet : TypeAttr<"sret", IntersectPreserve, [ParamAttr]>;
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 8d192b0d5cfe00..6b11badf3775f7 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -178,6 +178,10 @@ def IntrSpeculatable : IntrinsicProperty;
// defined by the hasSideEffects property of the TableGen Instruction class.
def IntrHasSideEffects : IntrinsicProperty;
+/// This property indicates that the intrinsic represents a floating-point
+/// operation, and it may have floating-point operand bundles.
+def IntrFPOperation : IntrinsicProperty;
+
//===----------------------------------------------------------------------===//
// IIT constants and utils
//===----------------------------------------------------------------------===//
@@ -1020,7 +1024,7 @@ def int_experimental_memset_pattern
// FIXME: Add version of these floating point intrinsics which allow non-default
// rounding modes and FP exception handling.
-let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
+let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn, IntrFPOperation] in {
def int_fma : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>,
LLVMMatchType<0>]>;
@@ -1089,27 +1093,27 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
def int_minnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_maxnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_minimum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_maximum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_minimumnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
def int_maximumnum : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>],
- [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative]
+ [IntrNoMem, IntrSpeculatable, IntrWillReturn, Commutative, IntrFPOperation]
>;
// Internal interface for object size checking
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index 02fbb38548d6b9..344c2592f4c039 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2076,6 +2076,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ElementType;
case bitc::ATTR_KIND_FNRETTHUNK_EXTERN:
return Attribute::FnRetThunkExtern;
+ case bitc::ATTR_KIND_FPOPERATION:
+ return Attribute::FPOperation;
case bitc::ATTR_KIND_INLINE_HINT:
return Attribute::InlineHint;
case bitc::ATTR_KIND_IN_REG:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 63f4e34074e06b..932c80895b4771 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -733,6 +733,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_DISABLE_SANITIZER_INSTRUMENTATION;
case Attribute::FnRetThunkExtern:
return bitc::ATTR_KIND_FNRETTHUNK_EXTERN;
+ case Attribute::FPOperation:
+ return bitc::ATTR_KIND_FPOPERATION;
case Attribute::Hot:
return bitc::ATTR_KIND_HOT;
case Attribute::ElementType:
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index e3fafecacdd2a8..672c61503de4d3 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3799,6 +3799,10 @@ void Verifier::visitCallBase(CallBase &Call) {
"Value of fpe.round bundle operand is not a correct rounding mode",
Call);
FoundFpeRoundBundle = true;
+ Check(!Callee || isa<ConstrainedFPIntrinsic>(Call) ||
+ Callee->hasFnAttribute(Attribute::FPOperation) ||
+ !Callee->isIntrinsic(),
+ "This function call may not have fpe.control bundle", Call);
} else if (Tag == LLVMContext::OB_fpe_except) {
Check(!FoundFpeExceptBundle, "Multiple fpe.except operand bundles", Call);
Check(BU.Inputs.size() == 1,
@@ -3813,6 +3817,10 @@ void Verifier::visitCallBase(CallBase &Call) {
"behavior",
Call);
FoundFpeExceptBundle = true;
+ Check(!Callee || isa<ConstrainedFPIntrinsic>(Call) ||
+ Callee->hasFnAttribute(Attribute::FPOperation) ||
+ !Callee->isIntrinsic(),
+ "This function call may not have fpe.except bundle", Call);
}
}
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index 6539f924c2edf4..a0b2e0b32d69e0 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -903,6 +903,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
case Attribute::CoroDestroyOnlyWhenComplete:
case Attribute::CoroElideSafe:
case Attribute::NoDivergenceSource:
+ case Attribute::FPOperation:
continue;
// Those attributes should be safe to propagate to the extracted function.
case Attribute::AlwaysInline:
diff --git a/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll b/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll
index 71c6380177b3a4..d2adb892271290 100644
--- a/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll
+++ b/llvm/test/CodeGen/AArch64/replace-with-veclib-armpl.ll
@@ -780,6 +780,6 @@ define <vscale x 4 x float> @llvm_tanh_vscale_f32(<vscale x 4 x float> %in) #0 {
attributes #0 = { "target-features"="+sve" }
;.
-; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR1]] = { "target-features"="+sve" }
;.
diff --git a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll
index 1d429ece6f8101..e3cbb3592194d1 100644
--- a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll
+++ b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef-scalable.ll
@@ -575,5 +575,5 @@ declare <vscale x 2 x double> @llvm.trunc.nxv2f64(<vscale x 2 x double>)
declare <vscale x 4 x float> @llvm.trunc.nxv4f32(<vscale x 4 x float>)
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { "target-features"="+sve" }
-; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+sve" }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+sve" }
;.
diff --git a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll
index ebe5e78667680d..a84a009faa782a 100644
--- a/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll
+++ b/llvm/test/CodeGen/AArch64/replace-with-veclib-sleef.ll
@@ -573,5 +573,5 @@ declare <4 x float> @llvm.tan.v4f32(<4 x float>)
declare <2 x double> @llvm.trunc.v2f64(<2 x double>)
declare <4 x float> @llvm.trunc.v4f32(<4 x float>)
;.
-; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
;.
diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll
index a2d5ce2d658b57..7b36b3bc9f0a3c 100644
--- a/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll
+++ b/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-rootn.ll
@@ -1491,7 +1491,7 @@ attributes #2 = { noinline }
!0 = !{float 3.0}
;.
; CHECK: attributes #[[ATTR0]] = { strictfp }
-; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR2:[0-9]+]] = { nounwind memory(read) }
; CHECK: attributes #[[ATTR3]] = { noinline }
; CHECK: attributes #[[ATTR4]] = { nobuiltin }
diff --git a/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll b/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll
index 134c2b8932003f..f0752a7fa94692 100644
--- a/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll
+++ b/llvm/test/CodeGen/RISCV/replace-with-veclib-sleef-scalable.ll
@@ -488,5 +488,5 @@ declare <vscale x 2 x double> @llvm.trunc.nxv2f64(<vscale x 2 x double>)
declare <vscale x 4 x float> @llvm.trunc.nxv4f32(<vscale x 4 x float>)
;.
; CHECK: attributes #[[ATTR0]] = { "target-features"="+v" }
-; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+v" }
+; CHECK: attributes #[[ATTR1:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) "target-features"="+v" }
;.
diff --git a/llvm/test/Feature/intrinsics.ll b/llvm/test/Feature/intrinsics.ll
index 49fed0981bd766..de0c776ecd9d90 100644
--- a/llvm/test/Feature/intrinsics.ll
+++ b/llvm/test/Feature/intrinsics.ll
@@ -61,7 +61,7 @@ define void @libm() {
; FIXME: test ALL the intrinsics in this file.
; rdar://11542750
-; CHECK: declare void @llvm.trap() #1
+; CHECK: declare void @llvm.trap() #2
declare void @llvm.trap()
define void @trap() {
@@ -70,4 +70,5 @@ define void @trap() {
}
; CHECK: attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
-; CHECK: attributes #1 = { cold noreturn nounwind memory(inaccessiblemem: write) }
+; CHECK: attributes #1 = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #2 = { cold noreturn nounwind memory(inaccessiblemem: write) }
diff --git a/llvm/test/Linker/drop-attribute.ll b/llvm/test/Linker/drop-attribute.ll
index 9be95a89109b4e..1208a94e45f870 100644
--- a/llvm/test/Linker/drop-attribute.ll
+++ b/llvm/test/Linker/drop-attribute.ll
@@ -39,7 +39,7 @@ define void @test_nocallback_definition() nocallback {
declare void @test_nocallback_call_site()
; Test that checks that nocallback attribute on an intrinsic is NOT dropped.
-; CHECK: ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn
+; CHECK: ; Function Attrs: fpoperation nocallback nofree nosync nounwind speculatable willreturn
; CHECK-NEXT: declare float @llvm.sqrt.f32(float) #0
declare float @llvm.sqrt.f32(float) nocallback
diff --git a/llvm/test/Transforms/Attributor/nofree.ll b/llvm/test/Transforms/Attributor/nofree.ll
index 10753916dabc60..daafa0443f1eda 100644
--- a/llvm/test/Transforms/Attributor/nofree.ll
+++ b/llvm/test/Transforms/Attributor/nofree.ll
@@ -238,7 +238,7 @@ define void @call_both() #0 {
; TEST 10 (positive case)
; Call intrinsic function
-; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+; CHECK: Function Attrs: fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.floor.f32(float)
define void @call_floor(float %a) #0 {
@@ -489,7 +489,7 @@ attributes #2 = { nobuiltin nounwind }
; TUNIT: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
; TUNIT: attributes #[[ATTR5:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
-; TUNIT: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; TUNIT: attributes #[[ATTR6:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; TUNIT: attributes #[[ATTR7]] = { nofree nounwind }
; TUNIT: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
; TUNIT: attributes #[[ATTR9]] = { nosync memory(none) }
@@ -506,7 +506,7 @@ attributes #2 = { nobuiltin nounwind }
; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable }
; CGSCC: attributes #[[ATTR4:[0-9]+]] = { nofree noinline nounwind memory(none) uwtable }
; CGSCC: attributes #[[ATTR5]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable }
-; CGSCC: attributes #[[ATTR6:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CGSCC: attributes #[[ATTR6:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CGSCC: attributes #[[ATTR7]] = { nofree nounwind }
; CGSCC: attributes #[[ATTR8]] = { nobuiltin nofree nounwind }
; CGSCC: attributes #[[ATTR9]] = { nosync memory(none) }
diff --git a/llvm/test/Transforms/Attributor/nosync.ll b/llvm/test/Transforms/Attributor/nosync.ll
index 1fbb334b9e47c7..1d82fd59d04971 100644
--- a/llvm/test/Transforms/Attributor/nosync.ll
+++ b/llvm/test/Transforms/Attributor/nosync.ll
@@ -454,7 +454,7 @@ define void @nosync_convergent_callee_test() {
; CHECK: attributes #[[ATTR14:[0-9]+]] = { convergent memory(none) }
; CHECK: attributes #[[ATTR15]] = { memory(none) }
; CHECK: attributes #[[ATTR16]] = { nounwind }
-; CHECK: attributes #[[ATTR17:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; CHECK: attributes #[[ATTR17:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR18]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR19]] = { nosync memory(none) }
; CHECK: attributes #[[ATTR20]] = { nofree nounwind }
diff --git a/llvm/test/Transforms/Attributor/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll
index 4a1f8788a60a55..a03019da4672cf 100644
--- a/llvm/test/Transforms/Attributor/willreturn.ll
+++ b/llvm/test/Transforms/Attributor/willreturn.ll
@@ -276,7 +276,7 @@ define void @conditional_exit(i32 %0, ptr nocapture readonly %1) local_unnamed_a
; TEST 6 (positive case)
; Call intrinsic function
-; CHECK: Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
+; CHECK: Function Attrs: fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare float @llvm.floor.f32(float)
define void @call_floor(float %a) #0 {
@@ -1294,7 +1294,7 @@ attributes #1 = { uwtable noinline }
; TUNIT: attributes #[[ATTR5]] = { noreturn }
; TUNIT: attributes #[[ATTR6]] = { noinline noreturn nounwind uwtable }
; TUNIT: attributes #[[ATTR7]] = { noinline nounwind uwtable }
-; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+; TUNIT: attributes #[[ATTR8:[0-9]+]] = { fpoperation nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; TUNIT: attributes #[[ATTR9:[0-9]+]] = { norecurse willreturn }
; TUNIT: attributes #[[ATTR10]] = { mustprogress noinline nounwind willreturn uwtable }
; TUNIT: attributes #[[ATTR11:[0-9]+]] = { noinline willreturn uwtable }
@@ -1332,7 +1332,7 @@ attributes #1 = { uwtable noinline }
; CGSCC: attributes #[[ATTR5]] = { noreturn }
; CGSCC: attributes #[[ATTR6]] = { noinline noreturn nounwind uwtable }
; CGSCC: attributes #[[ATTR7]] = { noinline nounwind uwtable }
-; CGSCC: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nosync nounwind specula...
[truncated]
|
@@ -308,6 +308,9 @@ def StackProtectStrong : EnumAttr<"sspstrong", IntersectPreserve, [FnAttr]>; | |||
/// Function was called in a scope requiring strict floating point semantics. | |||
def StrictFP : EnumAttr<"strictfp", IntersectPreserve, [FnAttr]>; | |||
|
|||
/// Function is a floating point operation. | |||
def FPOperation : EnumAttr<"fpoperation", IntersectPreserve, [FnAttr]>; |
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.
Function attributes need documenting in LangRef
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.
At least based on your description, I don't think this intrinsic property should be implemented using an attribute.
I think this is aiming too low. I think this should be a general floating point environment access that is specific about what aspects of the floating point environment may be used. This includes read or write of the rounding mode, other FP env fields, and errno |
The previous implementation of constrained functions passed floating-point parameters as metadata function arguments. They represented a part of the function signature and were mandatory. Passing such parameters to irrelevant functions were not possible. The new implementation passes the floating-point parameters in operand bundles. This is an optional call component and technically such bundles can be attached to any call. To keep IR cleaner, some mechanism is required to avoid setting FP bundles on irrelevant functions. This change implements such mechanism by introducing a new function attribute, "fpoperation". It should be set for built-in functions that operate floating-point values in some way and thus the parameters, represented by FP bundles, make sense for them. Verifier can check if FP bundles are attached to call to such functions only.
Sorry, I didn't provide enough documentation. Now the attribute is documented in LangRef and the motivation for this change is presented in the PR description.
It would be profitable to extend the set of FP parameters beyond FP environment. For example, static rounding mode, strictly speaking, is not a part of FP environment, it is just a parameter. But passing it in FP operand bundles allows us to obtain a more consistent representation, because in many cases it does not matter if rounding mode comes from a register or encoded as a part of instruction. |
Should this be part of the "memory" attribute, instead of an independent thing? In my head, the model I have is the following: the current fp state is a bit of thread-local state, and transforms that use generic reasoning about memory reads/writes should be able to conservatively handle fp state without knowing anything about it. Then we have some additional markings that allow fp-aware transforms to be more precise: they can see if the operation reads the status flags, or whether the rounding mode is known. I don't think attributes specific to intrinsics make sense in this context; anything that makes sense to assert about an intrinsic call, equally makes sense to assert about a non-intrinsic call. |
This attribute is needed only for validation of FP operand bundles, to check if a call may have such bundles. It addresses the concern that a call should have FP bundles only when they make sense for the called function (e.g. #118253 (comment)). If we decide that irrelevant bundles are just ignored, this attribute is likely to be unneeded.
Essentially you are right. We can introduce new kinds of "memory" to represent FP environment and check if FP bundles are attached only to the calls of functions that access these memory kinds. But the case of static rounding remains unsupported. If an operation makes FP operation using static rounding and does not have other interaction with FP environment (or it is ignored), such operation does not have side effect at all. |
Do we actually want to represent static rounding modes using the same representation as the other FP bits? It doesn't seem to fit. All the other bits are just descriptions of how an operation interacts with the known FP state, which code generation could just ignore. A static rounding mode modifies the operation being performed: it's as if you set the rounding mode, perform the operation, then reset the rounding mode afterwards. I'm not sure what the right representation for static rounding modes looks like (whether it's an operand bundle, a metadata operand, or separate intrinsics). But I think we need to treat it separately: it's not just describing the behavior of a call, it modifies it, so grouping it together with the FP optimization bits is confusing. |
Rounding mode is a parameter of a floating-point operation, its effect does not depend on the fact that it comes from a register or is specified as an immediate value. Implementing them differently does not look like a good solution. Implementing static rounding using different intrinsic set would require four instrinsics to represent a single FP operation (constrained intrinsics also can use static rounding). It is the problem the operand bundles should solve. Now an FP operation may have two parameters attached to it - rounding mode and exception handling. They are of very different nature, - rounding mode is a part of FP environment but exception handling is just an instruction to the compiler, it contains no information about FP environment. Adding static rounding (and in future probably static denormal mode) hardly add a confusion to this solution. |
8e64ef3
to
2f0d1c5
Compare
The previous implementation of constrained functions passed
floating-point parameters as metadata function arguments. They
represented a part of the function signature and were mandatory. Passing
such parameters to irrelevant functions were not possible.
The new implementation passes the floating-point parameters in operand
bundles. This is an optional call component and technically such bundles
can be attached to any call. To keep IR cleaner, some mechanism is required
to avoid setting FP bundles on irrelevant functions.
This change implements such mechanism by introducing a new function
attribute, "fpoperation". It should be set for built-in functions that
operate floating-point values in some way and thus the parameters,
represented by FP bundles, make sense for them. Verifier can check if FP
bundles are attached to call to such functions only.