[clang] e57bd1f - [CFE, SystemZ] New target hook testFPKind() for checks of FP values.
Jonas Paulsson via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 18 10:38:51 PST 2021
Author: Jonas Paulsson
Date: 2021-02-18T12:36:46-06:00
New Revision: e57bd1ff4fb65208cb3060b62e1c48aa0aac623f
URL: https://github.com/llvm/llvm-project/commit/e57bd1ff4fb65208cb3060b62e1c48aa0aac623f
DIFF: https://github.com/llvm/llvm-project/commit/e57bd1ff4fb65208cb3060b62e1c48aa0aac623f.diff
LOG: [CFE, SystemZ] New target hook testFPKind() for checks of FP values.
The recent commit 00a6254 "Stop traping on sNaN in builtin_isnan" changed the
lowering in constrained FP mode of builtin_isnan from an FP comparison to
integer operations to avoid trapping.
SystemZ has a special instruction "Test Data Class" which is the preferred
way to do this check. This patch adds a new target hook "testFPKind()" that
lets SystemZ emit the s390_tdc intrinsic instead.
testFPKind() takes the BuiltinID as an argument and is expected to soon
handle more opcodes than just 'builtin_isnan'.
Review: Thomas Preud'homme, Ulrich Weigand
Differential Revision: https://reviews.llvm.org/D96568
Added:
clang/test/CodeGen/SystemZ/strictfp_builtins.c
Modified:
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/CodeGen/TargetInfo.cpp
clang/lib/CodeGen/TargetInfo.h
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index ed59a1e3161e..3ab5d2a5b684 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2997,6 +2997,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType())));
}
+ if (Value *Result = getTargetHooks().testFPKind(V, BuiltinID, Builder, CGM))
+ return RValue::get(Result);
+
// NaN has all exp bits set and a non zero significand. Therefore:
// isnan(V) == ((exp mask - (abs(V) & exp mask)) < 0)
unsigned bitsize = Ty->getScalarSizeInBits();
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index d42541282aea..a11768d3807b 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/Builtins.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/SwiftCallingConv.h"
#include "llvm/ADT/SmallBitVector.h"
@@ -30,6 +31,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IntrinsicsNVPTX.h"
+#include "llvm/IR/IntrinsicsS390.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm> // std::sort
@@ -7200,8 +7202,37 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI)
: TargetCodeGenInfo(
std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)) {}
-};
+ llvm::Value *testFPKind(llvm::Value *V, unsigned BuiltinID,
+ CGBuilderTy &Builder,
+ CodeGenModule &CGM) const override {
+ assert(V->getType()->isFloatingPointTy() && "V should have an FP type.");
+ // Only use TDC in constrained FP mode.
+ if (!Builder.getIsFPConstrained())
+ return nullptr;
+
+ llvm::Type *Ty = V->getType();
+ if (Ty->isFloatTy() || Ty->isDoubleTy() || Ty->isFP128Ty()) {
+ llvm::Module &M = CGM.getModule();
+ auto &Ctx = M.getContext();
+ llvm::Function *TDCFunc =
+ llvm::Intrinsic::getDeclaration(&M, llvm::Intrinsic::s390_tdc, Ty);
+ unsigned TDCBits = 0;
+ switch (BuiltinID) {
+ case Builtin::BI__builtin_isnan:
+ TDCBits = 0xf;
+ break;
+ default:
+ break;
+ }
+ if (TDCBits)
+ return Builder.CreateCall(
+ TDCFunc,
+ {V, llvm::ConstantInt::get(llvm::Type::getInt64Ty(Ctx), TDCBits)});
+ }
+ return nullptr;
+ }
+};
}
bool SystemZABIInfo::isPromotableIntegerTypeForABI(QualType Ty) const {
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 0df9667e91e1..e6e474544fc4 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
#define LLVM_CLANG_LIB_CODEGEN_TARGETINFO_H
+#include "CGBuilder.h"
#include "CodeGenModule.h"
#include "CGValue.h"
#include "clang/AST/Type.h"
@@ -126,6 +127,16 @@ class TargetCodeGenInfo {
return Address;
}
+ /// Performs a target specific test of a floating point value for things
+ /// like IsNaN, Infinity, ... Nullptr is returned if no implementation
+ /// exists.
+ virtual llvm::Value *
+ testFPKind(llvm::Value *V, unsigned BuiltinID, CGBuilderTy &Builder,
+ CodeGenModule &CGM) const {
+ assert(V->getType()->isFloatingPointTy() && "V should have an FP type.");
+ return nullptr;
+ }
+
/// Corrects the low-level LLVM type for a given constraint and "usual"
/// type.
///
diff --git a/clang/test/CodeGen/SystemZ/strictfp_builtins.c b/clang/test/CodeGen/SystemZ/strictfp_builtins.c
new file mode 100644
index 000000000000..2181da9b8637
--- /dev/null
+++ b/clang/test/CodeGen/SystemZ/strictfp_builtins.c
@@ -0,0 +1,43 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 %s -emit-llvm -ffp-exception-behavior=maytrap -o - -triple s390x-linux-gnu | FileCheck %s
+
+#pragma float_control(except, on)
+
+// CHECK-LABEL: @test_isnan_float(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[F_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT: store float [[F:%.*]], float* [[F_ADDR]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = load float, float* [[F_ADDR]], align 4
+// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.s390.tdc.f32(float [[TMP0]], i64 15) [[ATTR2:#.*]]
+// CHECK-NEXT: ret i32 [[TMP1]]
+//
+int test_isnan_float(float f) {
+ return __builtin_isnan(f);
+}
+
+// CHECK-LABEL: @test_isnan_double(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[D_ADDR:%.*]] = alloca double, align 8
+// CHECK-NEXT: store double [[D:%.*]], double* [[D_ADDR]], align 8
+// CHECK-NEXT: [[TMP0:%.*]] = load double, double* [[D_ADDR]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.s390.tdc.f64(double [[TMP0]], i64 15) [[ATTR2]]
+// CHECK-NEXT: ret i32 [[TMP1]]
+//
+int test_isnan_double(double d) {
+ return __builtin_isnan(d);
+}
+
+// CHECK-LABEL: @test_isnan_long_double(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[LD_ADDR:%.*]] = alloca fp128, align 8
+// CHECK-NEXT: [[LD:%.*]] = load fp128, fp128* [[TMP0:%.*]], align 8
+// CHECK-NEXT: store fp128 [[LD]], fp128* [[LD_ADDR]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = load fp128, fp128* [[LD_ADDR]], align 8
+// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.s390.tdc.f128(fp128 [[TMP1]], i64 15) [[ATTR2]]
+// CHECK-NEXT: ret i32 [[TMP2]]
+//
+int test_isnan_long_double(long double ld) {
+ return __builtin_isnan(ld);
+}
+
More information about the cfe-commits
mailing list