From 7d00f00f1d1761585d9a2ef14a2bab34613e4b6f Mon Sep 17 00:00:00 2001 From: Joey Gouly Date: Thu, 21 Feb 2013 11:49:56 +0000 Subject: [PATCH] Add support to Sema and CodeGen for floating point vector types in OpenCL. llvm-svn: 175734 --- clang/lib/CodeGen/CGExprScalar.cpp | 31 ++++++++----- clang/lib/Sema/SemaExpr.cpp | 51 ++++++++++++++++++--- clang/test/CodeGenOpenCL/logical-ops.cl | 56 +++++++++++++++++++++++ clang/test/SemaOpenCL/invalid-logical-ops-1.1.cl | 57 ++++++++++++++++++++++++ clang/test/SemaOpenCL/invalid-logical-ops-1.2.cl | 57 ++++++++++++++++++++++++ 5 files changed, 236 insertions(+), 16 deletions(-) create mode 100644 clang/test/CodeGenOpenCL/logical-ops.cl create mode 100644 clang/test/SemaOpenCL/invalid-logical-ops-1.1.cl create mode 100644 clang/test/SemaOpenCL/invalid-logical-ops-1.2.cl diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 7b86c04..69aa7e8 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1636,12 +1636,15 @@ Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) { } Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { - // Perform vector logical not on comparison with zero vector. if (E->getType()->isExtVectorType()) { Value *Oper = Visit(E->getSubExpr()); Value *Zero = llvm::Constant::getNullValue(Oper->getType()); - Value *Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp"); + Value *Result; + if (Oper->getType()->isFPOrFPVectorTy()) + Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp"); + else + Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp"); return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext"); } @@ -2668,16 +2671,20 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { } Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { - // Perform vector logical and on comparisons with zero vectors. if (E->getType()->isVectorType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); - LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp"); - RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp"); + if (LHS->getType()->isFPOrFPVectorTy()) { + LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); + RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); + } else { + LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp"); + RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp"); + } Value *And = Builder.CreateAnd(LHS, RHS); - return Builder.CreateSExt(And, Zero->getType(), "sext"); + return Builder.CreateSExt(And, ConvertType(E->getType()), "sext"); } llvm::Type *ResTy = ConvertType(E->getType()); @@ -2735,16 +2742,20 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { } Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { - // Perform vector logical or on comparisons with zero vectors. if (E->getType()->isVectorType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); - LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp"); - RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp"); + if (LHS->getType()->isFPOrFPVectorTy()) { + LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); + RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); + } else { + LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp"); + RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp"); + } Value *Or = Builder.CreateOr(LHS, RHS); - return Builder.CreateSExt(Or, Zero->getType(), "sext"); + return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext"); } llvm::Type *ResTy = ConvertType(E->getType()); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ec16efd..2858f36 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7446,7 +7446,10 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false); - if (vType.isNull() || vType->isFloatingType()) + if (vType.isNull()) + return InvalidOperands(Loc, LHS, RHS); + if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && + vType->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); return GetSignedVectorType(LHS.get()->getType()); @@ -7522,8 +7525,17 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] RHS.get()->getLocEnd())); } } - + if (!Context.getLangOpts().CPlusPlus) { + // OpenCL v1.1 s6.3.g: The logical operators and (&&), or (||) do + // not operate on the built-in scalar and vector float types. + if (Context.getLangOpts().OpenCL && + Context.getLangOpts().OpenCLVersion < 120) { + if (LHS.get()->getType()->isFloatingType() || + RHS.get()->getType()->isFloatingType()) + return InvalidOperands(Loc, LHS, RHS); + } + LHS = UsualUnaryConversions(LHS.take()); if (LHS.isInvalid()) return QualType(); @@ -8849,7 +8861,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Not: // bitwise complement Input = UsualUnaryConversions(Input.take()); - if (Input.isInvalid()) return ExprError(); + if (Input.isInvalid()) + return ExprError(); resultType = Input.get()->getType(); if (resultType->isDependentType()) break; @@ -8857,12 +8870,22 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (resultType->isComplexType() || resultType->isComplexIntegerType()) // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) - << resultType << Input.get()->getSourceRange(); + << resultType << Input.get()->getSourceRange(); else if (resultType->hasIntegerRepresentation()) break; - else { + else if (resultType->isExtVectorType()) { + if (Context.getLangOpts().OpenCL) { + // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate + // on vector float types. + QualType T = resultType->getAs()->getElementType(); + if (!T->isIntegerType()) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); + } + break; + } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) - << resultType << Input.get()->getSourceRange()); + << resultType << Input.get()->getSourceRange()); } break; @@ -8887,8 +8910,24 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // operand contextually converted to bool. Input = ImpCastExprToType(Input.take(), Context.BoolTy, ScalarTypeToBooleanCastKind(resultType)); + } else if (Context.getLangOpts().OpenCL && + Context.getLangOpts().OpenCLVersion < 120) { + // OpenCL v1.1 6.3.h: The logical operator not (!) does not + // operate on scalar float types. + if (!resultType->isIntegerType()) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); } } else if (resultType->isExtVectorType()) { + if (Context.getLangOpts().OpenCL && + Context.getLangOpts().OpenCLVersion < 120) { + // OpenCL v1.1 6.3.h: The logical operator not (!) does not + // operate on vector float types. + QualType T = resultType->getAs()->getElementType(); + if (!T->isIntegerType()) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); + } // Vector logical not returns the signed variant of the operand type. resultType = GetSignedVectorType(resultType); break; diff --git a/clang/test/CodeGenOpenCL/logical-ops.cl b/clang/test/CodeGenOpenCL/logical-ops.cl new file mode 100644 index 0000000..5530200 --- /dev/null +++ b/clang/test/CodeGenOpenCL/logical-ops.cl @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL1.2 -O1 | FileCheck %s + +#pragma OPENCL EXTENSION cl_khr_fp64 : enable + +typedef int int4 __attribute((ext_vector_type(4))); +typedef long long4 __attribute((ext_vector_type(4))); +typedef float float4 __attribute((ext_vector_type(4))); +typedef double double4 __attribute((ext_vector_type(4))); + +// CHECK: floatops +kernel void floatops(global int4 *out, global float4 *fout) { + // CHECK: store <4 x i32> + out[0] = (float4)(1, 1, 1, 1) && 1.0f; + // CHECK: store <4 x i32> zeroinitializer + out[1] = (float4)(0, 0, 0, 0) && (float4)(0, 0, 0, 0); + + // CHECK: store <4 x i32> + out[2] = (float4)(0, 0, 0, 0) || (float4)(1, 1, 1, 1); + // CHECK: store <4 x i32> zeroinitializer + out[3] = (float4)(0, 0, 0, 0) || 0.0f; + + // CHECK: store <4 x i32> + out[4] = !(float4)(0, 0, 0, 0); + // CHECK: store <4 x i32> zeroinitializer + out[5] = !(float4)(1, 2, 3, 4); + // CHECK: store <4 x i32> + out[6] = !(float4)(0, 1, 0, 1); + // CHECK: store <4 x float> + fout[0] = (float4)(!0.0f); + // CHECK: store <4 x float> zeroinitializer + fout[1] = (float4)(!1.0f); +} + +// CHECK: doubleops +kernel void doubleops(global long4 *out, global double4 *dout) { + // CHECK: store <4 x i64> + out[0] = (double4)(1, 1, 1, 1) && 1.0; + // CHECK: store <4 x i64> zeroinitializer + out[1] = (double4)(0, 0, 0, 0) && (double4)(0, 0, 0, 0); + + // CHECK: store <4 x i64> + out[2] = (double4)(0, 0, 0, 0) || (double4)(1, 1, 1, 1); + // CHECK: store <4 x i64> zeroinitializer + out[3] = (double4)(0, 0, 0, 0) || 0.0f; + + // CHECK: store <4 x i64> + out[4] = !(double4)(0, 0, 0, 0); + // CHECK: store <4 x i64> zeroinitializer + out[5] = !(double4)(1, 2, 3, 4); + // CHECK: store <4 x i64> + out[6] = !(double4)(0, 1, 0, 1); + // CHECK: store <4 x double> + dout[0] = (double4)(!0.0f); + // CHECK: store <4 x double> zeroinitializer + dout[1] = (double4)(!1.0f); +} diff --git a/clang/test/SemaOpenCL/invalid-logical-ops-1.1.cl b/clang/test/SemaOpenCL/invalid-logical-ops-1.1.cl new file mode 100644 index 0000000..78b6a26 --- /dev/null +++ b/clang/test/SemaOpenCL/invalid-logical-ops-1.1.cl @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 %s -verify -cl-std=CL1.1 + +#pragma OPENCL EXTENSION cl_khr_fp64 : enable +typedef __attribute__((ext_vector_type(4))) float float4; +typedef __attribute__((ext_vector_type(4))) double double4; +typedef __attribute__((ext_vector_type(4))) int int4; +typedef __attribute__((ext_vector_type(4))) long long4; + +kernel void float_ops() { + int flaf = 0.0f && 0.0f; // expected-error {{invalid operands}} + int flof = 0.0f || 0.0f; // expected-error {{invalid operands}} + float fbaf = 0.0f & 0.0f; // expected-error {{invalid operands}} + float fbof = 0.0f | 0.0f; // expected-error {{invalid operands}} + float fbxf = 0.0f ^ 0.0f; // expected-error {{invalid operands}} + int flai = 0.0f && 0; // expected-error {{invalid operands}} + int floi = 0.0f || 0; // expected-error {{invalid operands}} + float ibaf = 0 & 0.0f; // expected-error {{invalid operands}} + float ibof = 0 | 0.0f; // expected-error {{invalid operands}} + float bnf = ~0.0f; // expected-error {{invalid argument type}} + float lnf = !0.0f; // expected-error {{invalid argument type}} +} + +kernel void vec_float_ops() { + float4 f4 = (float4)(0, 0, 0, 0); + int4 f4laf = f4 && 0.0f; // expected-error {{invalid operands}} + int4 f4lof = f4 || 0.0f; // expected-error {{invalid operands}} + float4 f4baf = f4 & 0.0f; // expected-error {{invalid operands}} + float4 f4bof = f4 | 0.0f; // expected-error {{invalid operands}} + float4 f4bxf = f4 ^ 0.0f; // expected-error {{invalid operands}} + float bnf4 = ~f4; // expected-error {{invalid argument type}} + int4 lnf4 = !f4; // expected-error {{invalid argument type}} +} + +kernel void double_ops() { + int flaf = 0.0 && 0.0; // expected-error {{invalid operands}} + int flof = 0.0 || 0.0; // expected-error {{invalid operands}} + double fbaf = 0.0 & 0.0; // expected-error {{invalid operands}} + double fbof = 0.0 | 0.0; // expected-error {{invalid operands}} + double fbxf = 0.0 ^ 0.0; // expected-error {{invalid operands}} + int flai = 0.0 && 0; // expected-error {{invalid operands}} + int floi = 0.0 || 0; // expected-error {{invalid operands}} + double ibaf = 0 & 0.0; // expected-error {{invalid operands}} + double ibof = 0 | 0.0; // expected-error {{invalid operands}} + double bnf = ~0.0; // expected-error {{invalid argument type}} + double lnf = !0.0; // expected-error {{invalid argument type}} +} + +kernel void vec_double_ops() { + double4 f4 = (double4)(0, 0, 0, 0); + long4 f4laf = f4 && 0.0; // expected-error {{invalid operands}} + long4 f4lof = f4 || 0.0; // expected-error {{invalid operands}} + double4 f4baf = f4 & 0.0; // expected-error {{invalid operands}} + double4 f4bof = f4 | 0.0; // expected-error {{invalid operands}} + double4 f4bxf = f4 ^ 0.0; // expected-error {{invalid operands}} + double bnf4 = ~f4; // expected-error {{invalid argument type}} + long4 lnf4 = !f4; // expected-error {{invalid argument type}} +} diff --git a/clang/test/SemaOpenCL/invalid-logical-ops-1.2.cl b/clang/test/SemaOpenCL/invalid-logical-ops-1.2.cl new file mode 100644 index 0000000..404beb2d --- /dev/null +++ b/clang/test/SemaOpenCL/invalid-logical-ops-1.2.cl @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 %s -verify -cl-std=CL1.2 + +#pragma OPENCL EXTENSION cl_khr_fp64 : enable +typedef __attribute__((ext_vector_type(4))) float float4; +typedef __attribute__((ext_vector_type(4))) double double4; +typedef __attribute__((ext_vector_type(4))) int int4; +typedef __attribute__((ext_vector_type(4))) long long4; + +kernel void float_ops() { + int flaf = 0.0f && 0.0f; + int flof = 0.0f || 0.0f; + float fbaf = 0.0f & 0.0f; // expected-error {{invalid operands}} + float fbof = 0.0f | 0.0f; // expected-error {{invalid operands}} + float fbxf = 0.0f ^ 0.0f; // expected-error {{invalid operands}} + int flai = 0.0f && 0; + int floi = 0.0f || 0; + float ibaf = 0 & 0.0f; // expected-error {{invalid operands}} + float ibof = 0 | 0.0f; // expected-error {{invalid operands}} + float bnf = ~0.0f;// expected-error {{invalid argument type}} + float lnf = !0.0f; +} + +kernel void vec_float_ops() { + float4 f4 = (float4)(0, 0, 0, 0); + int4 f4laf = f4 && 0.0f; + int4 f4lof = f4 || 0.0f; + float4 f4baf = f4 & 0.0f; // expected-error {{invalid operands}} + float4 f4bof = f4 | 0.0f; // expected-error {{invalid operands}} + float4 f4bxf = f4 ^ 0.0f; // expected-error {{invalid operands}} + float bnf4 = ~f4; // expected-error {{invalid argument type}} + int4 lnf4 = !f4; +} + +kernel void double_ops() { + int flaf = 0.0 && 0.0; + int flof = 0.0 || 0.0; + double fbaf = 0.0 & 0.0; // expected-error {{invalid operands}} + double fbof = 0.0 | 0.0; // expected-error {{invalid operands}} + double fbxf = 0.0 ^ 0.0; // expected-error {{invalid operands}} + int flai = 0.0 && 0; + int floi = 0.0 || 0; + double ibaf = 0 & 0.0; // expected-error {{invalid operands}} + double ibof = 0 | 0.0; // expected-error {{invalid operands}} + double bnf = ~0.0; // expected-error {{invalid argument type}} + double lnf = !0.0; +} + +kernel void vec_double_ops() { + double4 f4 = (double4)(0, 0, 0, 0); + long4 f4laf = f4 && 0.0; + long4 f4lof = f4 || 0.0; + double4 f4baf = f4 & 0.0; // expected-error {{invalid operands}} + double4 f4bof = f4 | 0.0; // expected-error {{invalid operands}} + double4 f4bxf = f4 ^ 0.0; // expected-error {{invalid operands}} + double bnf4 = ~f4; // expected-error {{invalid argument type}} + long4 lnf4 = !f4; +} -- 2.7.4