[clang] clang: Remove useFP16ConversionIntrinsics target option (PR #207212)
Matt Arsenault via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 6 08:03:39 PDT 2026
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/207212
>From bd8db3a3738ad5026eab0fb62075726f0581e111 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Mon, 5 Jan 2026 23:15:43 +0100
Subject: [PATCH] clang: Remove useFP16ConversionIntrinsics target option
Follow up to #174494. Remove the remnants of the control to
use llvm.convert.to.fp16/llvm.convert.from.fp16. Prefer
directly using the IR half type, unless the value is used
in an ABI context where it needs to remain as i16.
I did the first 80% of this a long time ago, and AI finished
the last bit and handled the recent rebases and test updates.
Co-authored-by: Claude (Opus 4.8) <noreply at anthropic.com>
---
clang/include/clang/Basic/TargetInfo.h | 10 ---
clang/lib/Basic/Targets/AArch64.h | 4 -
clang/lib/Basic/Targets/AMDGPU.h | 2 -
clang/lib/Basic/Targets/ARM.h | 4 -
clang/lib/Basic/Targets/DirectX.h | 1 -
clang/lib/Basic/Targets/LoongArch.h | 2 -
clang/lib/Basic/Targets/NVPTX.h | 2 -
clang/lib/Basic/Targets/RISCV.h | 4 -
clang/lib/Basic/Targets/SPIR.h | 4 -
clang/lib/Basic/Targets/SystemZ.h | 2 -
clang/lib/Basic/Targets/WebAssembly.h | 1 -
clang/lib/Basic/Targets/X86.h | 4 -
clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 10 +--
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 22 +-----
clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 8 +-
clang/lib/CodeGen/CGExprConstant.cpp | 12 +--
clang/lib/CodeGen/CGExprScalar.cpp | 54 ++++----------
clang/lib/CodeGen/CodeGenTypes.cpp | 28 +++----
clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp | 22 +-----
clang/lib/Sema/SemaChecking.cpp | 20 ++---
clang/lib/Sema/SemaExpr.cpp | 3 +-
clang/test/CIR/CodeGen/fp16-native-args.c | 44 +++++++++++
clang/test/CIR/CodeGen/fp16.c | 70 ++++++++++++++++++
clang/test/CodeGen/builtin_float.c | 7 +-
clang/test/CodeGen/builtin_float_strictfp.c | 8 +-
clang/test/CodeGen/wasm-fp16.c | 77 ++++++++------------
26 files changed, 193 insertions(+), 232 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/fp16-native-args.c
create mode 100644 clang/test/CIR/CodeGen/fp16.c
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index ad735d7b0b0e5..b7c0428dc2b2b 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1017,16 +1017,6 @@ class TargetInfo : public TransferrableTargetInfo,
return ComplexLongDoubleUsesFP2Ret;
}
- /// Check whether conversions to and from __fp16 should go through an integer
- /// bitcast with i16.
- ///
- /// FIXME: This function should be removed. The intrinsics / no longer exist,
- /// and are emulated with bitcast + fp cast. This only exists because of
- /// misuse in ABI determining contexts.
- virtual bool useFP16ConversionIntrinsics() const {
- return true;
- }
-
/// Specify if mangling based on address space map should be used or
/// not for language specific address spaces
bool useAddressSpaceMapMangling() const {
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index fc8e0e6071711..d619e24d82cb2 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -177,10 +177,6 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
llvm::APInt getFMVPriority(ArrayRef<StringRef> Features) const override;
- bool useFP16ConversionIntrinsics() const override {
- return false;
- }
-
void getTargetDefinesARMV81A(const LangOptions &Opts,
MacroBuilder &Builder) const;
void getTargetDefinesARMV82A(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index b13e9008b67a4..7bd34526105d3 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -263,8 +263,6 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
- bool useFP16ConversionIntrinsics() const override { return false; }
-
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h
index 8bd56c8855fe3..976e1e06ae9b2 100644
--- a/clang/lib/Basic/Targets/ARM.h
+++ b/clang/lib/Basic/Targets/ARM.h
@@ -177,10 +177,6 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
bool setFPMath(StringRef Name) override;
- bool useFP16ConversionIntrinsics() const override {
- return false;
- }
-
void getTargetDefinesARMV81A(const LangOptions &Opts,
MacroBuilder &Builder) const;
void getTargetDefinesARMV82A(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index 8b21b86bac264..64e5533bbffeb 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -70,7 +70,6 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
resetDataLayout();
TheCXXABI.set(TargetCXXABI::GenericItanium);
}
- bool useFP16ConversionIntrinsics() const override { return false; }
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h
index 16124a87d4955..4c98f9d0e40ae 100644
--- a/clang/lib/Basic/Targets/LoongArch.h
+++ b/clang/lib/Basic/Targets/LoongArch.h
@@ -107,8 +107,6 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool hasBFloat16Type() const override { return true; }
- bool useFP16ConversionIntrinsics() const override { return false; }
-
bool handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) override;
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 8af9cb91c47ab..00be0fe54c1bd 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -82,8 +82,6 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
- bool useFP16ConversionIntrinsics() const override { return false; }
-
bool isCLZForZeroUndef() const override { return false; }
bool
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index 193f77fe68a0b..73287c5d2d58d 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -117,10 +117,6 @@ class RISCVTargetInfo : public TargetInfo {
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
- bool useFP16ConversionIntrinsics() const override {
- return false;
- }
-
bool isValidCPUName(StringRef Name) const override;
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool isValidTuneCPUName(StringRef Name) const override;
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 389cc075a3a0b..42256920f353e 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -173,10 +173,6 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
}
public:
- // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is
- // memcpy as per section 3 of the SPIR spec.
- bool useFP16ConversionIntrinsics() const override { return false; }
-
llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
return {};
}
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index 70b529e8ca854..d56306c7c4a88 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -107,8 +107,6 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
unsigned getMinGlobalAlign(uint64_t Size, bool HasNonWeakDef) const override;
- bool useFP16ConversionIntrinsics() const override { return false; }
-
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 88192a756cc4f..0b0266a48469a 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -120,7 +120,6 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
StringRef getABI() const override;
bool setABI(const std::string &Name) override;
- bool useFP16ConversionIntrinsics() const override { return !HasFP16; }
protected:
void getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index b0daffbea4576..641bb78906610 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -338,10 +338,6 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
return "";
}
- bool useFP16ConversionIntrinsics() const override {
- return false;
- }
-
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 384b975b3f422..ffb0f9148c876 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1304,18 +1304,10 @@ mlir::Attribute ConstantEmitter::tryEmitPrivate(const APValue &value,
return cir::IntAttr::get(ty, value.getInt());
}
case APValue::Float: {
- const llvm::APFloat &init = value.getFloat();
- if (&init.getSemantics() == &llvm::APFloat::IEEEhalf() &&
- !cgm.getASTContext().getLangOpts().NativeHalfType &&
- cgm.getASTContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- cgm.errorNYI("ConstExprEmitter::tryEmitPrivate half");
- return {};
- }
-
mlir::Type ty = cgm.convertType(destType);
assert(mlir::isa<cir::FPTypeInterface>(ty) &&
"expected floating-point type");
- return cir::FPAttr::get(ty, init);
+ return cir::FPAttr::get(ty, value.getFloat());
}
case APValue::Array: {
const ArrayType *arrayTy = cgm.getASTContext().getAsArrayType(destType);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 3c2d2726ac9fa..645cca9fe16eb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -969,19 +969,10 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
if (srcType->isHalfType() &&
!cgf.getContext().getLangOpts().NativeHalfType) {
// Cast to FP using the intrinsic if the half type itself isn't supported.
- if (mlir::isa<cir::FPTypeInterface>(mlirDstType)) {
- if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
- cgf.getCIRGenModule().errorNYI(loc,
- "cast via llvm.convert.from.fp16");
- } else {
- // Cast to other types through float, using either the intrinsic or
- // FPExt, depending on whether the half type itself is supported (as
- // opposed to operations on half, available with NativeHalfType).
- if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics())
- cgf.getCIRGenModule().errorNYI(loc,
- "cast via llvm.convert.from.fp16");
- // FIXME(cir): For now lets pretend we shouldn't use the conversion
- // intrinsics and insert a cast here unconditionally.
+ if (!mlir::isa<cir::FPTypeInterface>(mlirDstType)) {
+ // Cast to other types through float, using FPExt, depending on whether
+ // the half type itself is supported (as opposed to operations on half,
+ // available with NativeHalfType).
src = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, src,
cgf.floatTy);
srcType = cgf.getContext().FloatTy;
@@ -1039,11 +1030,6 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
res = emitScalarCast(src, srcType, dstType, mlirSrcType, mlirDstType, opts);
if (mlirDstType != resTy) {
- if (cgf.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- cgf.getCIRGenModule().errorNYI(loc, "cast via llvm.convert.to.fp16");
- }
- // FIXME(cir): For now we never use FP16 conversion intrinsics even if
- // required by the target. Change that once this is implemented
res = builder.createCast(cgf.getLoc(loc), cir::CastKind::floating, res,
resTy);
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 3170666304a06..298c44d849782 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -449,13 +449,7 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
resultType = cgm.fP16Ty;
break;
case BuiltinType::Half:
- if (astContext.getLangOpts().NativeHalfType ||
- !astContext.getTargetInfo().useFP16ConversionIntrinsics()) {
- resultType = cgm.fP16Ty;
- } else {
- cgm.errorNYI(SourceLocation(), "processing of built-in type", type);
- resultType = cgm.sInt32Ty;
- }
+ resultType = cgm.fP16Ty;
break;
case BuiltinType::BFloat16:
resultType = cgm.bFloat16Ty;
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index 7a2b00647f189..27b7423a42f98 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2598,16 +2598,8 @@ ConstantEmitter::tryEmitPrivate(const APValue &Value, QualType DestType,
llvm::StructType::get(Complex[0]->getType(), Complex[1]->getType());
return llvm::ConstantStruct::get(STy, Complex);
}
- case APValue::Float: {
- const llvm::APFloat &Init = Value.getFloat();
- if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf() &&
- !CGM.getContext().getLangOpts().NativeHalfType &&
- CGM.getContext().getTargetInfo().useFP16ConversionIntrinsics())
- return llvm::ConstantInt::get(CGM.getLLVMContext(),
- Init.bitcastToAPInt());
- else
- return llvm::ConstantFP::get(CGM.getLLVMContext(), Init);
- }
+ case APValue::Float:
+ return llvm::ConstantFP::get(CGM.getLLVMContext(), Value.getFloat());
case APValue::ComplexFloat: {
llvm::Constant *Complex[2];
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 18ed6570730f4..6f7b7e7d6840e 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1690,28 +1690,17 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
bool OBWrapInvolved =
(DstOBT && DstOBT->isWrapKind()) || (SrcOBT && SrcOBT->isWrapKind());
- // Cast from half through float if half isn't a native type.
- if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
- // Cast to FP using the intrinsic if the half type itself isn't supported.
- if (DstTy->isFloatingPointTy()) {
- if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
- Value *BitCast = Builder.CreateBitCast(Src, CGF.CGM.HalfTy);
- return Builder.CreateFPExt(BitCast, DstTy, "conv");
- }
- } else {
- // Cast to other types through float, using either the intrinsic or FPExt,
- // depending on whether the half type itself is supported
- // (as opposed to operations on half, available with NativeHalfType).
+ // If half isn't a native type, cast to float for evaluation.
+ if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
+ SrcTy == CGF.CGM.HalfTy && DstTy != CGF.CGM.HalfTy) {
+ if (DstTy->isFloatingPointTy())
+ return Builder.CreateFPExt(Src, DstTy, "conv");
- if (Src->getType() != CGF.CGM.HalfTy) {
- assert(CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics());
- Src = Builder.CreateBitCast(Src, CGF.CGM.HalfTy);
- }
-
- Src = Builder.CreateFPExt(Src, CGF.CGM.FloatTy, "conv");
- SrcType = CGF.getContext().FloatTy;
- SrcTy = CGF.FloatTy;
- }
+ // Cast to other types through float (as opposed to operations on half,
+ // available with NativeHalfType).
+ Src = Builder.CreateFPExt(Src, CGF.CGM.FloatTy, "conv");
+ SrcType = CGF.getContext().FloatTy;
+ SrcTy = CGF.FloatTy;
}
// Ignore conversions like int -> uint.
@@ -1816,23 +1805,13 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy,
Loc);
- // Cast to half through float if half isn't a native type.
- if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
+ // Cast to half from float if half isn't a native type. When __fp16 isn't
+ // native, arithmetic is evaluated as float.
+ if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType &&
+ DstTy == CGF.CGM.HalfTy) {
// Make sure we cast in a single step if from another FP type.
- if (SrcTy->isFloatingPointTy()) {
- // Handle the case where the half type is represented as an integer (as
- // opposed to operations on half, available with NativeHalfType).
-
- // If the half type is supported, just use an fptrunc.
- Value *Res = Builder.CreateFPTrunc(Src, CGF.CGM.HalfTy, "conv");
- if (DstTy == CGF.CGM.HalfTy)
- return Res;
-
- assert(DstTy->isIntegerTy(16) &&
- CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics() &&
- "Only half FP requires extra conversion");
- return Builder.CreateBitCast(Res, DstTy);
- }
+ if (SrcTy->isFloatingPointTy())
+ return Builder.CreateFPTrunc(Src, CGF.CGM.HalfTy, "conv");
DstTy = CGF.FloatTy;
}
@@ -1844,7 +1823,6 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (ResTy != CGF.CGM.HalfTy) {
assert(ResTy->isIntegerTy(16) &&
- CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics() &&
"Only half FP requires extra conversion");
Res = Builder.CreateBitCast(Res, ResTy);
}
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index 3de3bad6affb5..c68a24ca045bc 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -300,14 +300,9 @@ void CodeGenTypes::RefreshTypeCacheForClass(const CXXRecordDecl *RD) {
}
static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
- const llvm::fltSemantics &format,
- bool UseNativeHalf = false) {
- if (&format == &llvm::APFloat::IEEEhalf()) {
- if (UseNativeHalf)
- return llvm::Type::getHalfTy(VMContext);
- else
- return llvm::Type::getInt16Ty(VMContext);
- }
+ const llvm::fltSemantics &format) {
+ if (&format == &llvm::APFloat::IEEEhalf())
+ return llvm::Type::getHalfTy(VMContext);
if (&format == &llvm::APFloat::BFloat())
return llvm::Type::getBFloatTy(VMContext);
if (&format == &llvm::APFloat::IEEEsingle())
@@ -485,16 +480,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
case BuiltinType::Float16:
ResultType =
- getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T),
- /* UseNativeHalf = */ true);
+ getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T));
break;
case BuiltinType::Half:
- // Half FP can either be storage-only (lowered to i16) or native.
- ResultType = getTypeForFormat(
- getLLVMContext(), Context.getFloatTypeSemantics(T),
- Context.getLangOpts().NativeHalfType ||
- !Context.getTargetInfo().useFP16ConversionIntrinsics());
+ // Half FP can either be storage-only (lowered to i16 for ABI purposes) or
+ // native.
+ ResultType =
+ getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T));
break;
case BuiltinType::LongDouble:
LongDoubleReferenced = true;
@@ -504,9 +497,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
case BuiltinType::Double:
case BuiltinType::Float128:
case BuiltinType::Ibm128:
- ResultType = getTypeForFormat(getLLVMContext(),
- Context.getFloatTypeSemantics(T),
- /* UseNativeHalf = */ false);
+ ResultType =
+ getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T));
break;
case BuiltinType::NullPtr:
diff --git a/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp b/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
index 0be166ce7bb38..48b6866147281 100644
--- a/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
@@ -393,23 +393,8 @@ static Value *MakeCpAsync(unsigned IntrinsicID, unsigned IntrinsicIDS,
CGF.EmitScalarExpr(E->getArg(1))});
}
-static bool EnsureNativeHalfSupport(unsigned BuiltinID, const CallExpr *E,
- CodeGenFunction &CGF) {
- auto &C = CGF.CGM.getContext();
- if (!C.getLangOpts().NativeHalfType &&
- C.getTargetInfo().useFP16ConversionIntrinsics()) {
- CGF.CGM.Error(E->getExprLoc(), C.BuiltinInfo.getQuotedName(BuiltinID) +
- " requires native half type support.");
- return false;
- }
- return true;
-}
-
static Value *MakeHalfType(Function *Intrinsic, unsigned BuiltinID,
const CallExpr *E, CodeGenFunction &CGF) {
- if (!EnsureNativeHalfSupport(BuiltinID, E, CGF))
- return nullptr;
-
SmallVector<Value *, 16> Args;
auto *FTy = Intrinsic->getFunctionType();
unsigned ICEArguments = 0;
@@ -1128,13 +1113,10 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
EmitScalarExpr(E->getArg(0)));
case NVPTX::BI__nvvm_ldg_h:
case NVPTX::BI__nvvm_ldg_h2:
- return EnsureNativeHalfSupport(BuiltinID, E, *this) ? MakeLdg(*this, E)
- : nullptr;
+ return MakeLdg(*this, E);
case NVPTX::BI__nvvm_ldu_h:
case NVPTX::BI__nvvm_ldu_h2:
- return EnsureNativeHalfSupport(BuiltinID, E, *this)
- ? MakeLdu(Intrinsic::nvvm_ldu_global_f, *this, E)
- : nullptr;
+ return MakeLdu(Intrinsic::nvvm_ldu_global_f, *this, E);
case NVPTX::BI__nvvm_cp_async_ca_shared_global_4:
return MakeCpAsync(Intrinsic::nvvm_cp_async_ca_shared_global_4,
Intrinsic::nvvm_cp_async_ca_shared_global_4_s, *this, E,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 965b92a2b5874..c3b3c15415442 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6416,22 +6416,12 @@ bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
if (OrigArg->isTypeDependent())
return false;
- // Usual Unary Conversions will convert half to float, which we want for
- // machines that use fp16 conversion intrinsics. Else, we wnat to leave the
- // type how it is, but do normal L->Rvalue conversions.
- if (Context.getTargetInfo().useFP16ConversionIntrinsics()) {
- ExprResult Res = UsualUnaryConversions(OrigArg);
-
- if (!Res.isUsable())
- return true;
- OrigArg = Res.get();
- } else {
- ExprResult Res = DefaultFunctionArrayLvalueConversion(OrigArg);
+ // We want to leave the type how it is, but do normal L->Rvalue conversions.
+ ExprResult Res = DefaultFunctionArrayLvalueConversion(OrigArg);
+ if (!Res.isUsable())
+ return true;
+ OrigArg = Res.get();
- if (!Res.isUsable())
- return true;
- OrigArg = Res.get();
- }
TheCall->setArg(FPArgNo, OrigArg);
QualType VectorResultTy;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 592cb1d588370..274973c78da81 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -15527,8 +15527,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
/// is needed.
static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
Expr *E0, Expr *E1 = nullptr) {
- if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType ||
- Ctx.getTargetInfo().useFP16ConversionIntrinsics())
+ if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType)
return false;
auto HasVectorOfHalfType = [&Ctx](Expr *E) {
diff --git a/clang/test/CIR/CodeGen/fp16-native-args.c b/clang/test/CIR/CodeGen/fp16-native-args.c
new file mode 100644
index 0000000000000..75e076f633190
--- /dev/null
+++ b/clang/test/CIR/CodeGen/fp16-native-args.c
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+
+// On AArch64 __fp16 may be passed and returned directly (the type is not
+// legalized to i16). Even though the value crosses the ABI as a half,
+// arithmetic on __fp16 is still performed by promoting to float and
+// truncating back, whereas _Float16 uses native half arithmetic.
+
+__fp16 ret_half(__fp16 a) { return a; }
+
+// CIR-LABEL: cir.func {{.*}}@ret_half(%arg0: !cir.f16 {{.*}}) -> !cir.f16
+// LLVM-LABEL: define {{.*}}half @ret_half(half {{.*}}%{{.*}})
+
+// __fp16: storage-only semantics, arithmetic promoted through float.
+__fp16 add_halves(__fp16 a, __fp16 b) { return a + b; }
+
+// CIR-LABEL: cir.func {{.*}}@add_halves(%arg0: !cir.f16 {{.*}}, %arg1: !cir.f16 {{.*}}) -> !cir.f16
+// CIR: %[[A:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %[[AF:.*]] = cir.cast floating %[[A]] : !cir.f16 -> !cir.float
+// CIR: %[[B:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %[[BF:.*]] = cir.cast floating %[[B]] : !cir.f16 -> !cir.float
+// CIR: %[[SUM:.*]] = cir.fadd %[[AF]], %[[BF]] : !cir.float
+// CIR: %{{.*}} = cir.cast floating %[[SUM]] : !cir.float -> !cir.f16
+
+// LLVM-LABEL: define {{.*}}half @add_halves(half {{.*}}%{{.*}}, half {{.*}}%{{.*}})
+// LLVM: %[[EA:.*]] = fpext half %{{.*}} to float
+// LLVM: %[[EB:.*]] = fpext half %{{.*}} to float
+// LLVM: %[[ADD:.*]] = fadd float %[[EA]], %[[EB]]
+// LLVM: %{{.*}} = fptrunc float %[[ADD]] to half
+
+// _Float16: native half arithmetic, no promotion to float.
+_Float16 native_add(_Float16 a, _Float16 b) { return a + b; }
+
+// CIR-LABEL: cir.func {{.*}}@native_add(%arg0: !cir.f16 {{.*}}, %arg1: !cir.f16 {{.*}}) -> !cir.f16
+// CIR: %[[A:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %[[B:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %{{.*}} = cir.fadd %[[A]], %[[B]] : !cir.f16
+// CIR-NOT: cir.cast floating {{.*}}!cir.f16 -> !cir.float
+
+// LLVM-LABEL: define {{.*}}half @native_add(half {{.*}}%{{.*}}, half {{.*}}%{{.*}})
+// LLVM: %{{.*}} = fadd half %{{.*}}, %{{.*}}
+// LLVM-NOT: fpext half
diff --git a/clang/test/CIR/CodeGen/fp16.c b/clang/test/CIR/CodeGen/fp16.c
new file mode 100644
index 0000000000000..748baae0cd6ea
--- /dev/null
+++ b/clang/test/CIR/CodeGen/fp16.c
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+
+// On x86_64 __fp16 is a storage-only type: it is stored as a half, but all
+// arithmetic is performed by promoting to float and truncating back. Verify
+// that ClangIR emits the half storage type directly and routes conversions
+// through float (as opposed to the removed llvm.convert.to/from.fp16
+// intrinsics).
+
+__fp16 g;
+__fp16 gi = 1.5;
+
+// CIR-DAG: cir.global external @g = #cir.fp<0.000000e+00> : !cir.f16
+// CIR-DAG: cir.global external @gi = #cir.fp<1.500000e+00> : !cir.f16
+
+// LLVM-DAG: @g = global half 0.000000e+00
+// LLVM-DAG: @gi = global half 1.500000e+00
+
+float load_to_float(__fp16 *p) { return *p; }
+
+// CIR-LABEL: cir.func {{.*}}@load_to_float(%arg0: !cir.ptr<!cir.f16> {{.*}}) -> !cir.float
+// CIR: %[[VAL:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %{{.*}} = cir.cast floating %[[VAL]] : !cir.f16 -> !cir.float
+
+// LLVM-LABEL: define {{.*}}float @load_to_float(ptr {{.*}}%{{.*}})
+// LLVM: %[[LD:.*]] = load half, ptr %{{.*}}
+// LLVM: %{{.*}} = fpext half %[[LD]] to float
+
+void store_from_float(__fp16 *p, float f) { *p = f; }
+
+// CIR-LABEL: cir.func {{.*}}@store_from_float(%arg0: !cir.ptr<!cir.f16> {{.*}}, %arg1: !cir.float {{.*}})
+// CIR: %[[F:.*]] = cir.load {{.*}} : !cir.ptr<!cir.float>, !cir.float
+// CIR: %[[H:.*]] = cir.cast floating %[[F]] : !cir.float -> !cir.f16
+// CIR: cir.store {{.*}} %[[H]], %{{.*}} : !cir.f16, !cir.ptr<!cir.f16>
+
+// LLVM-LABEL: define {{.*}}void @store_from_float(ptr {{.*}}%{{.*}}, float {{.*}}%{{.*}})
+// LLVM: %[[TR:.*]] = fptrunc float %{{.*}} to half
+// LLVM: store half %[[TR]], ptr %{{.*}}
+
+int half_to_int(__fp16 *p) { return (int)*p; }
+
+// CIR-LABEL: cir.func {{.*}}@half_to_int(%arg0: !cir.ptr<!cir.f16> {{.*}}) -> !s32i
+// CIR: %[[VAL:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %[[FP:.*]] = cir.cast floating %[[VAL]] : !cir.f16 -> !cir.float
+// CIR: %{{.*}} = cir.cast float_to_int %[[FP]] : !cir.float -> !s32i
+
+// LLVM-LABEL: define {{.*}}i32 @half_to_int(ptr {{.*}}%{{.*}})
+// LLVM: %[[LD:.*]] = load half, ptr %{{.*}}
+// LLVM: %[[EXT:.*]] = fpext half %[[LD]] to float
+// LLVM: %{{.*}} = fptosi float %[[EXT]] to i32
+
+void add_halves(__fp16 *r, __fp16 *a, __fp16 *b) { *r = *a + *b; }
+
+// CIR-LABEL: cir.func {{.*}}@add_halves(%arg0: !cir.ptr<!cir.f16> {{.*}}, %arg1: !cir.ptr<!cir.f16> {{.*}}, %arg2: !cir.ptr<!cir.f16> {{.*}})
+// CIR: %[[A:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %[[AF:.*]] = cir.cast floating %[[A]] : !cir.f16 -> !cir.float
+// CIR: %[[B:.*]] = cir.load {{.*}} : !cir.ptr<!cir.f16>, !cir.f16
+// CIR: %[[BF:.*]] = cir.cast floating %[[B]] : !cir.f16 -> !cir.float
+// CIR: %[[SUM:.*]] = cir.fadd %[[AF]], %[[BF]] : !cir.float
+// CIR: %{{.*}} = cir.cast floating %[[SUM]] : !cir.float -> !cir.f16
+
+// LLVM-LABEL: define {{.*}}void @add_halves(ptr {{.*}}%{{.*}}, ptr {{.*}}%{{.*}}, ptr {{.*}}%{{.*}})
+// LLVM: %[[EA:.*]] = fpext half %{{.*}} to float
+// LLVM: %[[EB:.*]] = fpext half %{{.*}} to float
+// LLVM: %[[ADD:.*]] = fadd float %[[EA]], %[[EB]]
+// LLVM: %{{.*}} = fptrunc float %[[ADD]] to half
diff --git a/clang/test/CodeGen/builtin_float.c b/clang/test/CodeGen/builtin_float.c
index f79b6bd4ff5e0..1c1ce6195b4be 100644
--- a/clang/test/CodeGen/builtin_float.c
+++ b/clang/test/CodeGen/builtin_float.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-pc -o - %s | FileCheck %s --check-prefixes=CHECK,FP16
-// RUN: %clang_cc1 -emit-llvm -triple ppc64-be -o - %s -DNO_FP16 | FileCheck %s --check-prefixes=CHECK,NOFP16
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-pc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple ppc64-be -o - %s -DNO_FP16 | FileCheck %s
// test to ensure that these builtins don't do the variadic promotion of float->double.
void test_floats(float f1, float f2) {
@@ -49,8 +49,7 @@ void test_half(__fp16 *H, __fp16 *H2) {
// CHECK: fcmp ogt float
// CHECK-NEXT: zext i1
(void)__builtin_isinf(*H);
- // FP16: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 516)
- // NOFP16: call i1 @llvm.is.fpclass.f32(float %{{.*}}, i32 516)
+ // CHECK: call i1 @llvm.is.fpclass.f16(half %{{.*}}, i32 516)
}
void test_mixed(double d1, float f2) {
diff --git a/clang/test/CodeGen/builtin_float_strictfp.c b/clang/test/CodeGen/builtin_float_strictfp.c
index 81bf89228f59c..7966110ddfcd1 100644
--- a/clang/test/CodeGen/builtin_float_strictfp.c
+++ b/clang/test/CodeGen/builtin_float_strictfp.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-pc -ffp-exception-behavior=maytrap -o - %s | FileCheck %s --check-prefixes=CHECK,FP16
-// RUN: %clang_cc1 -emit-llvm -triple ppc64-be -ffp-exception-behavior=maytrap -o - %s | FileCheck %s --check-prefixes=CHECK,NOFP16
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-pc -ffp-exception-behavior=maytrap -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple ppc64-be -ffp-exception-behavior=maytrap -o - %s | FileCheck %s
// test to ensure that these builtins don't do the variadic promotion of float->double.
@@ -11,8 +11,8 @@
// CHECK-LABEL: @test_half
void test_half(__fp16 *H, __fp16 *H2) {
(void)__builtin_isgreater(*H, *H2);
- // FP16: call float @llvm.experimental.constrained.fpext.f32.f16(half %{{.*}}, metadata !"fpexcept.strict")
- // FP16: call float @llvm.experimental.constrained.fpext.f32.f16(half %{{.*}}, metadata !"fpexcept.strict")
+ // CHECK: call float @llvm.experimental.constrained.fpext.f32.f16(half %{{.*}}, metadata !"fpexcept.strict")
+ // CHECK: call float @llvm.experimental.constrained.fpext.f32.f16(half %{{.*}}, metadata !"fpexcept.strict")
// CHECK: call i1 @llvm.experimental.constrained.fcmp.f32(float %{{.*}}, float %{{.*}}, metadata !"ogt", metadata !"fpexcept.strict")
// CHECK-NEXT: zext i1
(void)__builtin_isinf(*H);
diff --git a/clang/test/CodeGen/wasm-fp16.c b/clang/test/CodeGen/wasm-fp16.c
index 8fa35b975ab97..1649a6396baa7 100644
--- a/clang/test/CodeGen/wasm-fp16.c
+++ b/clang/test/CodeGen/wasm-fp16.c
@@ -4,7 +4,7 @@
__fp16 g = 2.0f;
//.
-// CHECK: @g = global i16 16384, align 2
+// CHECK: @g = global half 2.000000e+00, align 2
//.
// CHECK-LABEL: define float @test_memory_fp16_to_float(
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
@@ -12,9 +12,8 @@ __fp16 g = 2.0f;
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
-// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9:![0-9]+]]
-// CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP2]] to float
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9:![0-9]+]]
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: ret float [[CONV]]
//
float test_memory_fp16_to_float(__fp16 *ptr) {
@@ -30,9 +29,8 @@ float test_memory_fp16_to_float(__fp16 *ptr) {
// CHECK-NEXT: store float [[VAL]], ptr [[VAL_ADDR]], align 4, !tbaa [[FLOAT_TBAA11:![0-9]+]]
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[VAL_ADDR]], align 4, !tbaa [[FLOAT_TBAA11]]
// CHECK-NEXT: [[CONV:%.*]] = fptrunc float [[TMP0]] to half
-// CHECK-NEXT: [[TMP1:%.*]] = bitcast half [[CONV]] to i16
-// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
-// CHECK-NEXT: store i16 [[TMP1]], ptr [[TMP2]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
+// CHECK-NEXT: store half [[CONV]], ptr [[TMP1]], align 2, !tbaa [[__FP16_TBAA9]]
// CHECK-NEXT: ret void
//
void test_memory_float_from_fp16(__fp16* ptr, float val) {
@@ -45,15 +43,12 @@ void test_memory_float_from_fp16(__fp16* ptr, float val) {
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
-// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: [[INC:%.*]] = fadd float [[INCDEC_CONV]], 1.000000e+00
// CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[INC]] to half
-// CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
-// CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP3]] to half
-// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float
+// CHECK-NEXT: store half [[INCDEC_CONV1]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[INCDEC_CONV1]] to float
// CHECK-NEXT: ret float [[CONV]]
//
float test_memory_fp16_preinc(__fp16 *ptr) {
@@ -66,15 +61,12 @@ float test_memory_fp16_preinc(__fp16 *ptr) {
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
-// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: [[INC:%.*]] = fadd float [[INCDEC_CONV]], 1.000000e+00
// CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[INC]] to half
-// CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
-// CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float
+// CHECK-NEXT: store half [[INCDEC_CONV1]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: ret float [[CONV]]
//
float test_memory_fp16_postinc(__fp16 *ptr) {
@@ -87,15 +79,12 @@ float test_memory_fp16_postinc(__fp16 *ptr) {
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
-// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: [[DEC:%.*]] = fadd float [[INCDEC_CONV]], -1.000000e+00
// CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[DEC]] to half
-// CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
-// CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP3]] to half
-// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float
+// CHECK-NEXT: store half [[INCDEC_CONV1]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[INCDEC_CONV1]] to float
// CHECK-NEXT: ret float [[CONV]]
//
float test_memory_fp16_predec(__fp16 *ptr) {
@@ -108,36 +97,30 @@ float test_memory_fp16_predec(__fp16 *ptr) {
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[__FP16PTR_TBAA6]]
-// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP2:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP2]] to float
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[INCDEC_CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: [[DEC:%.*]] = fadd float [[INCDEC_CONV]], -1.000000e+00
// CHECK-NEXT: [[INCDEC_CONV1:%.*]] = fptrunc float [[DEC]] to half
-// CHECK-NEXT: [[TMP3:%.*]] = bitcast half [[INCDEC_CONV1]] to i16
-// CHECK-NEXT: store i16 [[TMP3]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP4:%.*]] = bitcast i16 [[TMP1]] to half
-// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP4]] to float
+// CHECK-NEXT: store half [[INCDEC_CONV1]], ptr [[TMP0]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: ret float [[CONV]]
//
float test_memory_fp16_postdec(__fp16 *ptr) {
return (*ptr)--;
}
-// CHECK-LABEL: define i16 @test_arg_return(
-// CHECK-SAME: i16 noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-LABEL: define half @test_arg_return(
+// CHECK-SAME: half noundef [[X:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2
-// CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP1:%.*]] = bitcast i16 [[TMP0]] to half
-// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP1]] to float
-// CHECK-NEXT: [[TMP2:%.*]] = load i16, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA9]]
-// CHECK-NEXT: [[TMP3:%.*]] = bitcast i16 [[TMP2]] to half
-// CHECK-NEXT: [[CONV1:%.*]] = fpext half [[TMP3]] to float
+// CHECK-NEXT: [[X_ADDR:%.*]] = alloca half, align 2
+// CHECK-NEXT: store half [[X]], ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[TMP0:%.*]] = load half, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to float
+// CHECK-NEXT: [[TMP1:%.*]] = load half, ptr [[X_ADDR]], align 2, !tbaa [[__FP16_TBAA9]]
+// CHECK-NEXT: [[CONV1:%.*]] = fpext half [[TMP1]] to float
// CHECK-NEXT: [[ADD:%.*]] = fadd float [[CONV]], [[CONV1]]
// CHECK-NEXT: [[CONV2:%.*]] = fptrunc float [[ADD]] to half
-// CHECK-NEXT: [[TMP4:%.*]] = bitcast half [[CONV2]] to i16
-// CHECK-NEXT: ret i16 [[TMP4]]
+// CHECK-NEXT: ret half [[CONV2]]
//
__fp16 test_arg_return(__fp16 x) {
return x + x;
More information about the cfe-commits
mailing list