//===- SemaSPIRV.cpp - Semantic Analysis for SPIRV constructs--------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // This implements Semantic Analysis for SPIRV constructs. //===----------------------------------------------------------------------===// #include "clang/Sema/SemaSPIRV.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Sema/Sema.h" namespace clang { SemaSPIRV::SemaSPIRV(Sema &S) : SemaBase(S) {} bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { case SPIRV::BI__builtin_spirv_distance: { if (SemaRef.checkArgCount(TheCall, 2)) return true; ExprResult A = TheCall->getArg(0); QualType ArgTyA = A.get()->getType(); auto *VTyA = ArgTyA->getAs(); if (VTyA == nullptr) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_convert_incompatible) << ArgTyA << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 << 0 << 0; return true; } ExprResult B = TheCall->getArg(1); QualType ArgTyB = B.get()->getType(); auto *VTyB = ArgTyB->getAs(); if (VTyB == nullptr) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_convert_incompatible) << ArgTyB << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1 << 0 << 0; return true; } QualType RetTy = VTyA->getElementType(); TheCall->setType(RetTy); break; } case SPIRV::BI__builtin_spirv_length: { if (SemaRef.checkArgCount(TheCall, 1)) return true; ExprResult A = TheCall->getArg(0); QualType ArgTyA = A.get()->getType(); auto *VTy = ArgTyA->getAs(); if (VTy == nullptr) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_convert_incompatible) << ArgTyA << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 << 0 << 0; return true; } QualType RetTy = VTy->getElementType(); TheCall->setType(RetTy); break; } case SPIRV::BI__builtin_spirv_reflect: { if (SemaRef.checkArgCount(TheCall, 2)) return true; ExprResult A = TheCall->getArg(0); QualType ArgTyA = A.get()->getType(); auto *VTyA = ArgTyA->getAs(); if (VTyA == nullptr) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_convert_incompatible) << ArgTyA << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1 << 0 << 0; return true; } ExprResult B = TheCall->getArg(1); QualType ArgTyB = B.get()->getType(); auto *VTyB = ArgTyB->getAs(); if (VTyB == nullptr) { SemaRef.Diag(A.get()->getBeginLoc(), diag::err_typecheck_convert_incompatible) << ArgTyB << SemaRef.Context.getVectorType(ArgTyB, 2, VectorKind::Generic) << 1 << 0 << 0; return true; } QualType RetTy = ArgTyA; TheCall->setType(RetTy); break; } case SPIRV::BI__builtin_spirv_smoothstep: { if (SemaRef.checkArgCount(TheCall, 3)) return true; // check if the all arguments have floating representation for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) { ExprResult Arg = TheCall->getArg(i); QualType ArgTy = Arg.get()->getType(); if (!ArgTy->hasFloatingRepresentation()) { SemaRef.Diag(Arg.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type) << i + 1 << /* scalar or vector */ 5 << /* no int */ 0 << /* fp */ 1 << ArgTy; return true; } } // check if all arguments are of the same type ExprResult A = TheCall->getArg(0); ExprResult B = TheCall->getArg(1); ExprResult C = TheCall->getArg(2); if (!(SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(), B.get()->getType()) && SemaRef.getASTContext().hasSameUnqualifiedType(A.get()->getType(), C.get()->getType()))) { SemaRef.Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() << /*useAllTerminology*/ true << SourceRange(A.get()->getBeginLoc(), C.get()->getEndLoc()); return true; } QualType RetTy = A.get()->getType(); TheCall->setType(RetTy); break; } } return false; } } // namespace clang