Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaAMDGPU.cpp
35233 views
//===------ SemaAMDGPU.cpp ------- AMDGPU target-specific routines --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements semantic analysis functions specific to AMDGPU.9//10//===----------------------------------------------------------------------===//1112#include "clang/Sema/SemaAMDGPU.h"13#include "clang/Basic/DiagnosticSema.h"14#include "clang/Basic/TargetBuiltins.h"15#include "clang/Sema/Ownership.h"16#include "clang/Sema/Sema.h"17#include "llvm/Support/AtomicOrdering.h"18#include <cstdint>1920namespace clang {2122SemaAMDGPU::SemaAMDGPU(Sema &S) : SemaBase(S) {}2324bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,25CallExpr *TheCall) {26// position of memory order and scope arguments in the builtin27unsigned OrderIndex, ScopeIndex;28switch (BuiltinID) {29case AMDGPU::BI__builtin_amdgcn_global_load_lds: {30constexpr const int SizeIdx = 2;31llvm::APSInt Size;32Expr *ArgExpr = TheCall->getArg(SizeIdx);33[[maybe_unused]] ExprResult R =34SemaRef.VerifyIntegerConstantExpression(ArgExpr, &Size);35assert(!R.isInvalid());36switch (Size.getSExtValue()) {37case 1:38case 2:39case 4:40return false;41default:42Diag(ArgExpr->getExprLoc(),43diag::err_amdgcn_global_load_lds_size_invalid_value)44<< ArgExpr->getSourceRange();45Diag(ArgExpr->getExprLoc(),46diag::note_amdgcn_global_load_lds_size_valid_value)47<< ArgExpr->getSourceRange();48return true;49}50}51case AMDGPU::BI__builtin_amdgcn_get_fpenv:52case AMDGPU::BI__builtin_amdgcn_set_fpenv:53return false;54case AMDGPU::BI__builtin_amdgcn_atomic_inc32:55case AMDGPU::BI__builtin_amdgcn_atomic_inc64:56case AMDGPU::BI__builtin_amdgcn_atomic_dec32:57case AMDGPU::BI__builtin_amdgcn_atomic_dec64:58OrderIndex = 2;59ScopeIndex = 3;60break;61case AMDGPU::BI__builtin_amdgcn_fence:62OrderIndex = 0;63ScopeIndex = 1;64break;65default:66return false;67}6869ExprResult Arg = TheCall->getArg(OrderIndex);70auto ArgExpr = Arg.get();71Expr::EvalResult ArgResult;7273if (!ArgExpr->EvaluateAsInt(ArgResult, getASTContext()))74return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int)75<< ArgExpr->getType();76auto Ord = ArgResult.Val.getInt().getZExtValue();7778// Check validity of memory ordering as per C11 / C++11's memody model.79// Only fence needs check. Atomic dec/inc allow all memory orders.80if (!llvm::isValidAtomicOrderingCABI(Ord))81return Diag(ArgExpr->getBeginLoc(),82diag::warn_atomic_op_has_invalid_memory_order)83<< 0 << ArgExpr->getSourceRange();84switch (static_cast<llvm::AtomicOrderingCABI>(Ord)) {85case llvm::AtomicOrderingCABI::relaxed:86case llvm::AtomicOrderingCABI::consume:87if (BuiltinID == AMDGPU::BI__builtin_amdgcn_fence)88return Diag(ArgExpr->getBeginLoc(),89diag::warn_atomic_op_has_invalid_memory_order)90<< 0 << ArgExpr->getSourceRange();91break;92case llvm::AtomicOrderingCABI::acquire:93case llvm::AtomicOrderingCABI::release:94case llvm::AtomicOrderingCABI::acq_rel:95case llvm::AtomicOrderingCABI::seq_cst:96break;97}9899Arg = TheCall->getArg(ScopeIndex);100ArgExpr = Arg.get();101Expr::EvalResult ArgResult1;102// Check that sync scope is a constant literal103if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, getASTContext()))104return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal)105<< ArgExpr->getType();106107return false;108}109110static bool111checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,112const AMDGPUFlatWorkGroupSizeAttr &Attr) {113// Accept template arguments for now as they depend on something else.114// We'll get to check them when they eventually get instantiated.115if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())116return false;117118uint32_t Min = 0;119if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))120return true;121122uint32_t Max = 0;123if (!S.checkUInt32Argument(Attr, MaxExpr, Max, 1))124return true;125126if (Min == 0 && Max != 0) {127S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)128<< &Attr << 0;129return true;130}131if (Min > Max) {132S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)133<< &Attr << 1;134return true;135}136137return false;138}139140AMDGPUFlatWorkGroupSizeAttr *141SemaAMDGPU::CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI,142Expr *MinExpr, Expr *MaxExpr) {143ASTContext &Context = getASTContext();144AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);145146if (checkAMDGPUFlatWorkGroupSizeArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))147return nullptr;148return ::new (Context)149AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr);150}151152void SemaAMDGPU::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,153const AttributeCommonInfo &CI,154Expr *MinExpr, Expr *MaxExpr) {155if (auto *Attr = CreateAMDGPUFlatWorkGroupSizeAttr(CI, MinExpr, MaxExpr))156D->addAttr(Attr);157}158159void SemaAMDGPU::handleAMDGPUFlatWorkGroupSizeAttr(Decl *D,160const ParsedAttr &AL) {161Expr *MinExpr = AL.getArgAsExpr(0);162Expr *MaxExpr = AL.getArgAsExpr(1);163164addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);165}166167static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,168Expr *MaxExpr,169const AMDGPUWavesPerEUAttr &Attr) {170if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||171(MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))172return true;173174// Accept template arguments for now as they depend on something else.175// We'll get to check them when they eventually get instantiated.176if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))177return false;178179uint32_t Min = 0;180if (!S.checkUInt32Argument(Attr, MinExpr, Min, 0))181return true;182183uint32_t Max = 0;184if (MaxExpr && !S.checkUInt32Argument(Attr, MaxExpr, Max, 1))185return true;186187if (Min == 0 && Max != 0) {188S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)189<< &Attr << 0;190return true;191}192if (Max != 0 && Min > Max) {193S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)194<< &Attr << 1;195return true;196}197198return false;199}200201AMDGPUWavesPerEUAttr *202SemaAMDGPU::CreateAMDGPUWavesPerEUAttr(const AttributeCommonInfo &CI,203Expr *MinExpr, Expr *MaxExpr) {204ASTContext &Context = getASTContext();205AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);206207if (checkAMDGPUWavesPerEUArguments(SemaRef, MinExpr, MaxExpr, TmpAttr))208return nullptr;209210return ::new (Context) AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr);211}212213void SemaAMDGPU::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,214Expr *MinExpr, Expr *MaxExpr) {215if (auto *Attr = CreateAMDGPUWavesPerEUAttr(CI, MinExpr, MaxExpr))216D->addAttr(Attr);217}218219void SemaAMDGPU::handleAMDGPUWavesPerEUAttr(Decl *D, const ParsedAttr &AL) {220if (!AL.checkAtLeastNumArgs(SemaRef, 1) || !AL.checkAtMostNumArgs(SemaRef, 2))221return;222223Expr *MinExpr = AL.getArgAsExpr(0);224Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;225226addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);227}228229void SemaAMDGPU::handleAMDGPUNumSGPRAttr(Decl *D, const ParsedAttr &AL) {230uint32_t NumSGPR = 0;231Expr *NumSGPRExpr = AL.getArgAsExpr(0);232if (!SemaRef.checkUInt32Argument(AL, NumSGPRExpr, NumSGPR))233return;234235D->addAttr(::new (getASTContext())236AMDGPUNumSGPRAttr(getASTContext(), AL, NumSGPR));237}238239void SemaAMDGPU::handleAMDGPUNumVGPRAttr(Decl *D, const ParsedAttr &AL) {240uint32_t NumVGPR = 0;241Expr *NumVGPRExpr = AL.getArgAsExpr(0);242if (!SemaRef.checkUInt32Argument(AL, NumVGPRExpr, NumVGPR))243return;244245D->addAttr(::new (getASTContext())246AMDGPUNumVGPRAttr(getASTContext(), AL, NumVGPR));247}248249static bool250checkAMDGPUMaxNumWorkGroupsArguments(Sema &S, Expr *XExpr, Expr *YExpr,251Expr *ZExpr,252const AMDGPUMaxNumWorkGroupsAttr &Attr) {253if (S.DiagnoseUnexpandedParameterPack(XExpr) ||254(YExpr && S.DiagnoseUnexpandedParameterPack(YExpr)) ||255(ZExpr && S.DiagnoseUnexpandedParameterPack(ZExpr)))256return true;257258// Accept template arguments for now as they depend on something else.259// We'll get to check them when they eventually get instantiated.260if (XExpr->isValueDependent() || (YExpr && YExpr->isValueDependent()) ||261(ZExpr && ZExpr->isValueDependent()))262return false;263264uint32_t NumWG = 0;265Expr *Exprs[3] = {XExpr, YExpr, ZExpr};266for (int i = 0; i < 3; i++) {267if (Exprs[i]) {268if (!S.checkUInt32Argument(Attr, Exprs[i], NumWG, i,269/*StrictlyUnsigned=*/true))270return true;271if (NumWG == 0) {272S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)273<< &Attr << Exprs[i]->getSourceRange();274return true;275}276}277}278279return false;280}281282AMDGPUMaxNumWorkGroupsAttr *SemaAMDGPU::CreateAMDGPUMaxNumWorkGroupsAttr(283const AttributeCommonInfo &CI, Expr *XExpr, Expr *YExpr, Expr *ZExpr) {284ASTContext &Context = getASTContext();285AMDGPUMaxNumWorkGroupsAttr TmpAttr(Context, CI, XExpr, YExpr, ZExpr);286287if (checkAMDGPUMaxNumWorkGroupsArguments(SemaRef, XExpr, YExpr, ZExpr,288TmpAttr))289return nullptr;290291return ::new (Context)292AMDGPUMaxNumWorkGroupsAttr(Context, CI, XExpr, YExpr, ZExpr);293}294295void SemaAMDGPU::addAMDGPUMaxNumWorkGroupsAttr(Decl *D,296const AttributeCommonInfo &CI,297Expr *XExpr, Expr *YExpr,298Expr *ZExpr) {299if (auto *Attr = CreateAMDGPUMaxNumWorkGroupsAttr(CI, XExpr, YExpr, ZExpr))300D->addAttr(Attr);301}302303void SemaAMDGPU::handleAMDGPUMaxNumWorkGroupsAttr(Decl *D,304const ParsedAttr &AL) {305Expr *YExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;306Expr *ZExpr = (AL.getNumArgs() > 2) ? AL.getArgAsExpr(2) : nullptr;307addAMDGPUMaxNumWorkGroupsAttr(D, AL, AL.getArgAsExpr(0), YExpr, ZExpr);308}309310} // namespace clang311312313