SjoerdMeijer created this revision. SjoerdMeijer added reviewers: olista01, t.p.northover, rjmccall, aschwaighofer. Herald added subscribers: kristof.beyls, javed.absar, aemerson.
Pass and return _Float16 as if it were an int or float for ARM, but with the top 16 bits unspecified, similarly like we already do for __fp16. We will implement proper half-precision function argument lowering in the ARM backend soon, but want to use this workaround in the mean time. https://reviews.llvm.org/D42318 Files: include/clang/AST/Type.h lib/CodeGen/TargetInfo.cpp test/CodeGen/arm-float16-arguments.c Index: test/CodeGen/arm-float16-arguments.c =================================================================== --- /dev/null +++ test/CodeGen/arm-float16-arguments.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fallow-half-arguments-and-returns -emit-llvm -o - -O1 %s | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT +// RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi hard -fallow-half-arguments-and-returns -emit-llvm -o - -O1 %s | FileCheck %s --check-prefix=CHECK --check-prefix=HARD +// RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fnative-half-arguments-and-returns -emit-llvm -o - -O1 %s | FileCheck %s --check-prefix=NATIVE + +_Float16 g; + +void t1(_Float16 a) { g = a; } +// SOFT: define void @t1(i32 [[PARAM:%.*]]) +// SOFT: [[TRUNC:%.*]] = trunc i32 [[PARAM]] to i16 +// HARD: define arm_aapcs_vfpcc void @t1(float [[PARAM:%.*]]) +// HARD: [[BITCAST:%.*]] = bitcast float [[PARAM]] to i32 +// HARD: [[TRUNC:%.*]] = trunc i32 [[BITCAST]] to i16 +// CHECK: store i16 [[TRUNC]], i16* bitcast (half* @g to i16*) +// NATIVE: define void @t1(half [[PARAM:%.*]]) +// NATIVE: store half [[PARAM]], half* @g + +_Float16 t2() { return g; } +// SOFT: define i32 @t2() +// HARD: define arm_aapcs_vfpcc float @t2() +// NATIVE: define half @t2() +// CHECK: [[LOAD:%.*]] = load i16, i16* bitcast (half* @g to i16*) +// CHECK: [[ZEXT:%.*]] = zext i16 [[LOAD]] to i32 +// SOFT: ret i32 [[ZEXT]] +// HARD: [[BITCAST:%.*]] = bitcast i32 [[ZEXT]] to float +// HARD: ret float [[BITCAST]] +// NATIVE: [[LOAD:%.*]] = load half, half* @g +// NATIVE: ret half [[LOAD]] Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -5721,10 +5721,11 @@ return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } - // __fp16 gets passed as if it were an int or float, but with the top 16 bits - // unspecified. This is not done for OpenCL as it handles the half type - // natively, and does not need to interwork with AAPCS code. - if (Ty->isHalfType() && !getContext().getLangOpts().NativeHalfArgsAndReturns) { + // _Float16 and __fp16 get passed as if it were an int or float, but with + // the top 16 bits unspecified. This is not done for OpenCL as it handles the + // half type natively, and does not need to interwork with AAPCS code. + if ((Ty->isFloat16Type() || Ty->isHalfType()) && + !getContext().getLangOpts().NativeHalfArgsAndReturns) { llvm::Type *ResType = IsEffectivelyAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); @@ -5919,10 +5920,11 @@ return getNaturalAlignIndirect(RetTy); } - // __fp16 gets returned as if it were an int or float, but with the top 16 - // bits unspecified. This is not done for OpenCL as it handles the half type - // natively, and does not need to interwork with AAPCS code. - if (RetTy->isHalfType() && !getContext().getLangOpts().NativeHalfArgsAndReturns) { + // _Float16 and __fp16 get returned as if it were an int or float, but with + // the top 16 bits unspecified. This is not done for OpenCL as it handles the + // half type natively, and does not need to interwork with AAPCS code. + if ((RetTy->isFloat16Type() || RetTy->isHalfType()) && + !getContext().getLangOpts().NativeHalfArgsAndReturns) { llvm::Type *ResType = IsEffectivelyAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1728,6 +1728,7 @@ bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) + bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 @@ -6179,6 +6180,12 @@ return false; } +inline bool Type::isFloat16Type() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Float16; + return false; +} + inline bool Type::isNullPtrType() const { if (const BuiltinType *BT = getAs<BuiltinType>()) return BT->getKind() == BuiltinType::NullPtr;
Index: test/CodeGen/arm-float16-arguments.c =================================================================== --- /dev/null +++ test/CodeGen/arm-float16-arguments.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fallow-half-arguments-and-returns -emit-llvm -o - -O1 %s | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT +// RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi hard -fallow-half-arguments-and-returns -emit-llvm -o - -O1 %s | FileCheck %s --check-prefix=CHECK --check-prefix=HARD +// RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fnative-half-arguments-and-returns -emit-llvm -o - -O1 %s | FileCheck %s --check-prefix=NATIVE + +_Float16 g; + +void t1(_Float16 a) { g = a; } +// SOFT: define void @t1(i32 [[PARAM:%.*]]) +// SOFT: [[TRUNC:%.*]] = trunc i32 [[PARAM]] to i16 +// HARD: define arm_aapcs_vfpcc void @t1(float [[PARAM:%.*]]) +// HARD: [[BITCAST:%.*]] = bitcast float [[PARAM]] to i32 +// HARD: [[TRUNC:%.*]] = trunc i32 [[BITCAST]] to i16 +// CHECK: store i16 [[TRUNC]], i16* bitcast (half* @g to i16*) +// NATIVE: define void @t1(half [[PARAM:%.*]]) +// NATIVE: store half [[PARAM]], half* @g + +_Float16 t2() { return g; } +// SOFT: define i32 @t2() +// HARD: define arm_aapcs_vfpcc float @t2() +// NATIVE: define half @t2() +// CHECK: [[LOAD:%.*]] = load i16, i16* bitcast (half* @g to i16*) +// CHECK: [[ZEXT:%.*]] = zext i16 [[LOAD]] to i32 +// SOFT: ret i32 [[ZEXT]] +// HARD: [[BITCAST:%.*]] = bitcast i32 [[ZEXT]] to float +// HARD: ret float [[BITCAST]] +// NATIVE: [[LOAD:%.*]] = load half, half* @g +// NATIVE: ret half [[LOAD]] Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -5721,10 +5721,11 @@ return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } - // __fp16 gets passed as if it were an int or float, but with the top 16 bits - // unspecified. This is not done for OpenCL as it handles the half type - // natively, and does not need to interwork with AAPCS code. - if (Ty->isHalfType() && !getContext().getLangOpts().NativeHalfArgsAndReturns) { + // _Float16 and __fp16 get passed as if it were an int or float, but with + // the top 16 bits unspecified. This is not done for OpenCL as it handles the + // half type natively, and does not need to interwork with AAPCS code. + if ((Ty->isFloat16Type() || Ty->isHalfType()) && + !getContext().getLangOpts().NativeHalfArgsAndReturns) { llvm::Type *ResType = IsEffectivelyAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); @@ -5919,10 +5920,11 @@ return getNaturalAlignIndirect(RetTy); } - // __fp16 gets returned as if it were an int or float, but with the top 16 - // bits unspecified. This is not done for OpenCL as it handles the half type - // natively, and does not need to interwork with AAPCS code. - if (RetTy->isHalfType() && !getContext().getLangOpts().NativeHalfArgsAndReturns) { + // _Float16 and __fp16 get returned as if it were an int or float, but with + // the top 16 bits unspecified. This is not done for OpenCL as it handles the + // half type natively, and does not need to interwork with AAPCS code. + if ((RetTy->isFloat16Type() || RetTy->isHalfType()) && + !getContext().getLangOpts().NativeHalfArgsAndReturns) { llvm::Type *ResType = IsEffectivelyAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1728,6 +1728,7 @@ bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) + bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 @@ -6179,6 +6180,12 @@ return false; } +inline bool Type::isFloat16Type() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Float16; + return false; +} + inline bool Type::isNullPtrType() const { if (const BuiltinType *BT = getAs<BuiltinType>()) return BT->getKind() == BuiltinType::NullPtr;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits