From: Joey Gouly Date: Wed, 23 Jan 2013 11:56:20 +0000 (+0000) Subject: Add a new LangOpt NativeHalfType. This option allows for native half/fp16 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dd7f4566b1a8b4d8e8321d2bca2385841a0b0130;p=platform%2Fupstream%2Fllvm.git Add a new LangOpt NativeHalfType. This option allows for native half/fp16 operations (as opposed to storage only half/fp16). Also add some semantic checks for OpenCL half types. llvm-svn: 173254 --- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 053f392..2683ac0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -417,6 +417,18 @@ def err_object_cannot_be_passed_returned_by_value : Error< "; did you forget * in %1?">; def err_parameters_retval_cannot_have_fp16_type : Error< "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">; +def err_opencl_half_dereferencing : Error< + "dereferencing pointer of type %0 is not allowed">; +def err_opencl_half_subscript : Error< + "subscript to array of type %0 is not allowed">; +def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">; +def err_opencl_cast_from_half : Error<"casting from type %0 is not allowed">; +def err_opencl_half_declaration : Error< + "declaring variable of type %0 is not allowed">; +def err_opencl_half_argument : Error< + "declaring function argument of type %0 is not allowed; did you forget * ?">; +def err_opencl_half_return : Error< + "declaring function return value of type %0 is not allowed; did you forget * ?">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; def warn_pragma_options_align_reset_failed : Warning< "#pragma options align=reset failed: %0">; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 4957272..60a7e83 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -116,6 +116,7 @@ LANGOPT(ShortEnums , 1, 0, "short enum types") LANGOPT(OpenCL , 1, 0, "OpenCL") LANGOPT(OpenCLVersion , 32, 0, "OpenCL version") +LANGOPT(NativeHalfType , 1, 0, "Native half type support") LANGOPT(CUDA , 1, 0, "CUDA") LANGOPT(OpenMP , 1, 0, "OpenMP support") diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b18fa67..fff2f82 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4091,7 +4091,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, assert(Domain->isRealFloatingType() && "Unknown domain!"); switch (EltRank) { - case HalfRank: llvm_unreachable("Half ranks are not valid here"); + case HalfRank: return HalfTy; case FloatRank: return FloatTy; case DoubleRank: return DoubleTy; case LongDoubleRank: return LongDoubleTy; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 80ab2ed..4344f94 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1140,7 +1140,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, } case APValue::Float: { const llvm::APFloat &Init = Value.getFloat(); - if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf) + if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf && + !Context.getLangOpts().NativeHalfType) return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); else return llvm::ConstantFP::get(VMContext, Init); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index ed927e2..7f0eda8 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -664,9 +664,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, QualType OrigSrcType = SrcType; llvm::Type *SrcTy = Src->getType(); - // Floating casts might be a bit special: if we're doing casts to / from half - // FP, we should go via special intrinsics. - if (SrcType->isHalfType()) { + // If casting to/from storage-only half FP, use special intrinsics. + if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) { Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src); SrcType = CGF.getContext().FloatTy; SrcTy = CGF.FloatTy; @@ -735,7 +734,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, DstTy); // Cast to half via float - if (DstType->isHalfType()) + if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) DstTy = CGF.FloatTy; if (isa(SrcTy)) { @@ -1536,7 +1535,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // Add the inc/dec to the real part. llvm::Value *amt; - if (type->isHalfType()) { + if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) { // Another special case: half FP increment should be done via float value = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), @@ -1558,7 +1557,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); - if (type->isHalfType()) + if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) value = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), value); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index c186ebf..e78cbab 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -263,9 +263,14 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { } static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext, - const llvm::fltSemantics &format) { - if (&format == &llvm::APFloat::IEEEhalf) - return llvm::Type::getInt16Ty(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); + } if (&format == &llvm::APFloat::IEEEsingle) return llvm::Type::getFloatTy(VMContext); if (&format == &llvm::APFloat::IEEEdouble) @@ -344,18 +349,17 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { break; case BuiltinType::Half: - // Half is special: it might be lowered to i16 (and will be storage-only - // type),. or can be represented as a set of native operations. - - // FIXME: Ask target which kind of half FP it prefers (storage only vs - // native). - ResultType = llvm::Type::getInt16Ty(getLLVMContext()); + // Half FP can either be storage-only (lowered to i16) or native. + ResultType = getTypeForFormat(getLLVMContext(), + Context.getFloatTypeSemantics(T), + Context.getLangOpts().NativeHalfType); break; case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: ResultType = getTypeForFormat(getLLVMContext(), - Context.getFloatTypeSemantics(T)); + Context.getFloatTypeSemantics(T), + /* UseNativeHalf = */ false); break; case BuiltinType::NullPtr: diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 90ace3f..eab9cc3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -989,6 +989,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.CXXOperatorNames = 1; Opts.LaxVectorConversions = 0; Opts.DefaultFPContract = 1; + Opts.NativeHalfType = 1; } if (LangStd == LangStandard::lang_cuda) diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 676db46..d1e95d7 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2104,6 +2104,21 @@ void CastOperation::CheckCStyleCast() { } } + if (Self.getLangOpts().OpenCL && !Self.getOpenCLOptions().cl_khr_fp16) { + if (DestType->isHalfType()) { + Self.Diag(SrcExpr.get()->getLocStart(), diag::err_opencl_cast_to_half) + << DestType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + if (SrcExpr.get()->getType()->isHalfType()) { + Self.Diag(SrcExpr.get()->getLocStart(), diag::err_opencl_cast_from_half) + << SrcType << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } + // ARC imposes extra restrictions on casts. if (Self.getLangOpts().ObjCAutoRefCount) { checkObjCARCConversion(Sema::CCK_CStyleCast); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f73ea98..2a18946 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4359,6 +4359,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, assert(SCSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); + + if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) + { + // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and + // half array type (unless the cl_khr_fp16 extension is enabled). + if (Context.getBaseElementType(R)->isHalfType()) { + Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; + D.setInvalidType(); + } + } + if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3cca25a..2e11881 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -545,9 +545,8 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - // Half FP is a bit different: it's a storage-only type, meaning that any - // "use" of it should be promoted to float. - if (Ty->isHalfType()) + // Half FP have to be promoted to float unless it is natively supported + if (Ty->isHalfType() && !getLangOpts().NativeHalfType) return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast); // Try to perform integral promotions if the object has a theoretically @@ -3470,6 +3469,13 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, diag::err_subscript_incomplete_type, BaseExpr)) return ExprError(); + if (ResultType->isHalfType() && getLangOpts().OpenCL && + !getOpenCLOptions().cl_khr_fp16) { + Diag(BaseExpr->getLocStart(), diag::err_opencl_half_subscript) << ResultType + << BaseExpr->getType() << BaseExpr->getSourceRange(); + return ExprError(); + } + assert(VK == VK_RValue || LangOpts.CPlusPlus || !ResultType.isCForbiddenLValueType()); @@ -8210,6 +8216,13 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, return QualType(); } + if (Result->isHalfType() && S.getLangOpts().OpenCL && + !S.getOpenCLOptions().cl_khr_fp16) { + S.Diag(OpLoc, diag::err_opencl_half_dereferencing) + << OpTy << Op->getSourceRange(); + return QualType(); + } + // Dereferences are usually l-values... VK = VK_LValue; @@ -8831,7 +8844,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType = Input.get()->getType(); // Though we still have to promote half FP to float... - if (resultType->isHalfType()) { + if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) { Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take(); resultType = Context.FloatTy; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d3d027b..b91b027 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1840,7 +1840,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { return true; // Half can be promoted to float. - if (FromBuiltin->getKind() == BuiltinType::Half && + if (!getLangOpts().NativeHalfType && + FromBuiltin->getKind() == BuiltinType::Half && ToBuiltin->getKind() == BuiltinType::Float) return true; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a3b0c45..dbee50a 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2441,10 +2441,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Do not allow returning half FP value. // FIXME: This really should be in BuildFunctionType. if (T->isHalfType()) { - S.Diag(D.getIdentifierLoc(), - diag::err_parameters_retval_cannot_have_fp16_type) << 1 - << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); - D.setInvalidType(true); + if (S.getLangOpts().OpenCL) { + if (!S.getOpenCLOptions().cl_khr_fp16) { + S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T; + D.setInvalidType(true); + } + } else { + S.Diag(D.getIdentifierLoc(), + diag::err_parameters_retval_cannot_have_fp16_type) << 1; + D.setInvalidType(true); + } } // cv-qualifiers on return types are pointless except when the type is a @@ -2617,10 +2623,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } else if (ArgTy->isHalfType()) { // Disallow half FP arguments. // FIXME: This really should be in BuildFunctionType. - S.Diag(Param->getLocation(), - diag::err_parameters_retval_cannot_have_fp16_type) << 0 - << FixItHint::CreateInsertion(Param->getLocation(), "*"); - D.setInvalidType(); + if (S.getLangOpts().OpenCL) { + if (!S.getOpenCLOptions().cl_khr_fp16) { + S.Diag(Param->getLocation(), + diag::err_opencl_half_argument) << ArgTy; + D.setInvalidType(); + } + } else { + S.Diag(Param->getLocation(), + diag::err_parameters_retval_cannot_have_fp16_type) << 0; + D.setInvalidType(); + } } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.getPromotedIntegerType(ArgTy); diff --git a/clang/test/CodeGenOpenCL/half.cl b/clang/test/CodeGenOpenCL/half.cl new file mode 100644 index 0000000..7ecae89 --- /dev/null +++ b/clang/test/CodeGenOpenCL/half.cl @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + + +half test() +{ + half x = 0.1f; + x+=2.0f; + x-=2.0f; + half y = x + x; + half z = y * 1.0f; + return z; +// CHECK: half 0xH3260 +} diff --git a/clang/test/SemaOpenCL/half.cl b/clang/test/SemaOpenCL/half.cl new file mode 100644 index 0000000..830d178 --- /dev/null +++ b/clang/test/SemaOpenCL/half.cl @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only + +#pragma OPENCL EXTENSION cl_khr_fp16 : disable + +half half_disabled(half *p, // expected-error{{declaring function return value of type 'half' is not allowed}} + half h) // expected-error{{declaring function argument of type 'half' is not allowed}} +{ + half a[2]; // expected-error{{declaring variable of type 'half [2]' is not allowed}} + half b; // expected-error{{declaring variable of type 'half' is not allowed}} + + b = *p; // expected-error{{dereferencing pointer of type 'half *' is not allowed}} + *p = b; // expected-error{{dereferencing pointer of type 'half *' is not allowed}} + + b = p[1]; // expected-error {{subscript to array of type 'half' is not allowed}} + p[1] = b; // expected-error {{subscript to array of type 'half' is not allowed}} + + float c = 1.0f; + b = (half) c; // expected-error{{casting to type 'half' is not allowed}} + c = (float) h; // expected-error{{casting from type 'half' is not allowed}} + + return h; +} + +// Exactly the same as above but with the cl_khr_fp16 extension enabled. +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +half half_enabled(half *p, half h) +{ + half a[2]; + half b; + + b = *p; + *p = b; + + b = p[1]; + p[1] = b; + + float c = 1.0f; + b = (half) c; + c = (float) h; + + return h; +}