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();
#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"
#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
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 {
#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"
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.
///
--- /dev/null
+// 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);
+}
+