Path: blob/main/contrib/llvm-project/clang/lib/Parse/ParseHLSL.cpp
35233 views
//===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//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 the parsing logic for HLSL language features.9//10//===----------------------------------------------------------------------===//1112#include "clang/AST/Attr.h"13#include "clang/Basic/AttributeCommonInfo.h"14#include "clang/Parse/ParseDiagnostic.h"15#include "clang/Parse/Parser.h"16#include "clang/Parse/RAIIObjectsForParser.h"17#include "clang/Sema/SemaHLSL.h"1819using namespace clang;2021static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG,22SourceLocation BufferLoc,23bool IsCBuffer, Parser &P) {24// The parse is failed, just return false.25if (!DG)26return false;27DeclGroupRef Decls = DG.get();28bool IsValid = true;29// Only allow function, variable, record decls inside HLSLBuffer.30for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {31Decl *D = *I;32if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))33continue;3435// FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.36if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {37P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)38<< IsCBuffer;39IsValid = false;40continue;41}4243IsValid = false;44P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)45<< IsCBuffer;46}47return IsValid;48}4950Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {51assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&52"Not a cbuffer or tbuffer!");53bool IsCBuffer = Tok.is(tok::kw_cbuffer);54SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.5556if (!Tok.is(tok::identifier)) {57Diag(Tok, diag::err_expected) << tok::identifier;58return nullptr;59}6061IdentifierInfo *Identifier = Tok.getIdentifierInfo();62SourceLocation IdentifierLoc = ConsumeToken();6364ParsedAttributes Attrs(AttrFactory);65MaybeParseHLSLAnnotations(Attrs, nullptr);6667ParseScope BufferScope(this, Scope::DeclScope);68BalancedDelimiterTracker T(*this, tok::l_brace);69if (T.consumeOpen()) {70Diag(Tok, diag::err_expected) << tok::l_brace;71return nullptr;72}7374Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc,75Identifier, IdentifierLoc,76T.getOpenLocation());7778while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {79// FIXME: support attribute on constants inside cbuffer/tbuffer.80ParsedAttributes DeclAttrs(AttrFactory);81ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);8283DeclGroupPtrTy Result =84ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);85if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,86*this)) {87T.skipToEnd();88DeclEnd = T.getCloseLocation();89BufferScope.Exit();90Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);91return nullptr;92}93}9495T.consumeClose();96DeclEnd = T.getCloseLocation();97BufferScope.Exit();98Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);99100Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);101return D;102}103104static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,105Token Tok, ArgsVector &ArgExprs,106Parser &P, ASTContext &Ctx,107Preprocessor &PP) {108StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());109SourceLocation EndNumLoc = Tok.getEndLoc();110111P.ConsumeToken(); // consume constant.112std::string FixedArg = ArgStr.str() + Num.str();113P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)114<< FixedArg115<< FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);116ArgsUnion &Slot = ArgExprs.back();117Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));118}119120void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,121SourceLocation *EndLoc,122bool CouldBeBitField) {123124assert(Tok.is(tok::colon) && "Not a HLSL Annotation");125Token OldToken = Tok;126ConsumeToken();127128IdentifierInfo *II = nullptr;129if (Tok.is(tok::kw_register))130II = PP.getIdentifierInfo("register");131else if (Tok.is(tok::identifier))132II = Tok.getIdentifierInfo();133134if (!II) {135if (CouldBeBitField) {136UnconsumeToken(OldToken);137return;138}139Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);140return;141}142143SourceLocation Loc = ConsumeToken();144if (EndLoc)145*EndLoc = Tok.getLocation();146ParsedAttr::Kind AttrKind =147ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation);148149ArgsVector ArgExprs;150switch (AttrKind) {151case ParsedAttr::AT_HLSLResourceBinding: {152if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {153SkipUntil(tok::r_paren, StopAtSemi); // skip through )154return;155}156if (!Tok.is(tok::identifier)) {157Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;158SkipUntil(tok::r_paren, StopAtSemi); // skip through )159return;160}161StringRef SlotStr = Tok.getIdentifierInfo()->getName();162SourceLocation SlotLoc = Tok.getLocation();163ArgExprs.push_back(ParseIdentifierLoc());164165// Add numeric_constant for fix-it.166if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))167fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,168Actions.Context, PP);169170if (Tok.is(tok::comma)) {171ConsumeToken(); // consume comma172if (!Tok.is(tok::identifier)) {173Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;174SkipUntil(tok::r_paren, StopAtSemi); // skip through )175return;176}177StringRef SpaceStr = Tok.getIdentifierInfo()->getName();178SourceLocation SpaceLoc = Tok.getLocation();179ArgExprs.push_back(ParseIdentifierLoc());180181// Add numeric_constant for fix-it.182if (SpaceStr == "space" && Tok.is(tok::numeric_constant))183fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,184Actions.Context, PP);185}186if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {187SkipUntil(tok::r_paren, StopAtSemi); // skip through )188return;189}190} break;191case ParsedAttr::AT_HLSLPackOffset: {192// Parse 'packoffset( c[Subcomponent][.component] )'.193// Check '('.194if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {195SkipUntil(tok::r_paren, StopAtSemi); // skip through )196return;197}198// Check c[Subcomponent] as an identifier.199if (!Tok.is(tok::identifier)) {200Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;201SkipUntil(tok::r_paren, StopAtSemi); // skip through )202return;203}204StringRef OffsetStr = Tok.getIdentifierInfo()->getName();205SourceLocation SubComponentLoc = Tok.getLocation();206if (OffsetStr[0] != 'c') {207Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg)208<< OffsetStr;209SkipUntil(tok::r_paren, StopAtSemi); // skip through )210return;211}212OffsetStr = OffsetStr.substr(1);213unsigned SubComponent = 0;214if (!OffsetStr.empty()) {215// Make sure SubComponent is a number.216if (OffsetStr.getAsInteger(10, SubComponent)) {217Diag(SubComponentLoc.getLocWithOffset(1),218diag::err_hlsl_unsupported_register_number);219SkipUntil(tok::r_paren, StopAtSemi); // skip through )220return;221}222}223unsigned Component = 0;224ConsumeToken(); // consume identifier.225SourceLocation ComponentLoc;226if (Tok.is(tok::period)) {227ConsumeToken(); // consume period.228if (!Tok.is(tok::identifier)) {229Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;230SkipUntil(tok::r_paren, StopAtSemi); // skip through )231return;232}233StringRef ComponentStr = Tok.getIdentifierInfo()->getName();234ComponentLoc = Tok.getLocation();235ConsumeToken(); // consume identifier.236// Make sure Component is a single character.237if (ComponentStr.size() != 1) {238Diag(ComponentLoc, diag::err_hlsl_unsupported_component)239<< ComponentStr;240SkipUntil(tok::r_paren, StopAtSemi); // skip through )241return;242}243switch (ComponentStr[0]) {244case 'x':245case 'r':246Component = 0;247break;248case 'y':249case 'g':250Component = 1;251break;252case 'z':253case 'b':254Component = 2;255break;256case 'w':257case 'a':258Component = 3;259break;260default:261Diag(ComponentLoc, diag::err_hlsl_unsupported_component)262<< ComponentStr;263SkipUntil(tok::r_paren, StopAtSemi); // skip through )264return;265}266}267ASTContext &Ctx = Actions.getASTContext();268QualType SizeTy = Ctx.getSizeType();269uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);270ArgExprs.push_back(IntegerLiteral::Create(271Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc));272ArgExprs.push_back(IntegerLiteral::Create(273Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc));274if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {275SkipUntil(tok::r_paren, StopAtSemi); // skip through )276return;277}278} break;279case ParsedAttr::UnknownAttribute:280Diag(Loc, diag::err_unknown_hlsl_semantic) << II;281return;282case ParsedAttr::AT_HLSLSV_GroupIndex:283case ParsedAttr::AT_HLSLSV_DispatchThreadID:284break;285default:286llvm_unreachable("invalid HLSL Annotation");287break;288}289290Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),291ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation());292}293294295