brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.0 KiB · c727ee3 Raw
343 lines · cpp
1//===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the parsing logic for HLSL language features.10//11//===----------------------------------------------------------------------===//12 13#include "clang/AST/Attr.h"14#include "clang/Basic/AttributeCommonInfo.h"15#include "clang/Basic/DiagnosticParse.h"16#include "clang/Parse/Parser.h"17#include "clang/Parse/RAIIObjectsForParser.h"18#include "clang/Sema/SemaHLSL.h"19 20using namespace clang;21 22static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG,23                                          SourceLocation BufferLoc,24                                          bool IsCBuffer, Parser &P) {25  // The parse is failed, just return false.26  if (!DG)27    return false;28  DeclGroupRef Decls = DG.get();29  bool IsValid = true;30  // Only allow function, variable, record, and empty decls inside HLSLBuffer.31  for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {32    Decl *D = *I;33    if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl, EmptyDecl>(D))34      continue;35 36    // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.37    if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {38      P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)39          << IsCBuffer;40      IsValid = false;41      continue;42    }43 44    IsValid = false;45    P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)46        << IsCBuffer;47  }48  return IsValid;49}50 51Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd,52                              ParsedAttributes &Attrs) {53  assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&54         "Not a cbuffer or tbuffer!");55  bool IsCBuffer = Tok.is(tok::kw_cbuffer);56  SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.57 58  if (!Tok.is(tok::identifier)) {59    Diag(Tok, diag::err_expected) << tok::identifier;60    return nullptr;61  }62 63  IdentifierInfo *Identifier = Tok.getIdentifierInfo();64  SourceLocation IdentifierLoc = ConsumeToken();65 66  MaybeParseHLSLAnnotations(Attrs, nullptr);67 68  ParseScope BufferScope(this, Scope::DeclScope);69  BalancedDelimiterTracker T(*this, tok::l_brace);70  if (T.consumeOpen()) {71    Diag(Tok, diag::err_expected) << tok::l_brace;72    return nullptr;73  }74 75  Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc,76                                            Identifier, IdentifierLoc,77                                            T.getOpenLocation());78  Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);79 80  while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {81    // FIXME: support attribute on constants inside cbuffer/tbuffer.82    ParsedAttributes DeclAttrs(AttrFactory);83    ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);84 85    DeclGroupPtrTy Result =86        ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);87    if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,88                                       *this)) {89      T.skipToEnd();90      DeclEnd = T.getCloseLocation();91      BufferScope.Exit();92      Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);93      return nullptr;94    }95  }96 97  T.consumeClose();98  DeclEnd = T.getCloseLocation();99  BufferScope.Exit();100  Actions.HLSL().ActOnFinishBuffer(D, DeclEnd);101 102  return D;103}104 105static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,106                                        Token Tok, ArgsVector &ArgExprs,107                                        Parser &P, ASTContext &Ctx,108                                        Preprocessor &PP) {109  StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());110  SourceLocation EndNumLoc = Tok.getEndLoc();111 112  P.ConsumeToken(); // consume constant.113  std::string FixedArg = ArgStr.str() + Num.str();114  P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)115      << FixedArg116      << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);117  ArgsUnion &Slot = ArgExprs.back();118  Slot = new (Ctx) IdentifierLoc(ArgLoc, PP.getIdentifierInfo(FixedArg));119}120 121Parser::ParsedSemantic Parser::ParseHLSLSemantic() {122  assert(Tok.is(tok::identifier) && "Not a HLSL Annotation");123 124  // Semantic pattern: [A-Za-z_]([A-Za-z_0-9]*[A-Za-z_])?[0-9]*125  // The first part is the semantic name, the second is the optional126  // semantic index. The semantic index is the number at the end of127  // the semantic, including leading zeroes. Digits located before128  // the last letter are part of the semantic name.129  SmallString<256> Buffer;130  Buffer.resize(Tok.getLength() + 1);131  StringRef Identifier = PP.getSpelling(Tok, Buffer);132  assert(Identifier.size() > 0);133  // Determine the start of the semantic index.134  unsigned IndexIndex = Identifier.find_last_not_of("0123456789") + 1;135 136  // ParseHLSLSemantic being called on an indentifier, the first137  // character cannot be a digit. This error should be handled by138  // the caller. We can assert here.139  StringRef SemanticName = Identifier.take_front(IndexIndex);140  assert(SemanticName.size() > 0);141 142  unsigned Index = 0;143  bool Explicit = false;144  if (IndexIndex != Identifier.size()) {145    Explicit = true;146    [[maybe_unused]] bool Failure =147        Identifier.substr(IndexIndex).getAsInteger(10, Index);148    // Given the logic above, this should never fail.149    assert(!Failure);150  }151 152  return {SemanticName, Index, Explicit};153}154 155void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,156                                  SourceLocation *EndLoc,157                                  bool CouldBeBitField) {158 159  assert(Tok.is(tok::colon) && "Not a HLSL Annotation");160  Token OldToken = Tok;161  ConsumeToken();162 163  IdentifierInfo *II = nullptr;164  if (Tok.is(tok::kw_register))165    II = PP.getIdentifierInfo("register");166  else if (Tok.is(tok::identifier))167    II = Tok.getIdentifierInfo();168 169  if (!II) {170    if (CouldBeBitField) {171      UnconsumeToken(OldToken);172      return;173    }174    Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);175    return;176  }177 178  ParsedAttr::Kind AttrKind =179      ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation);180  Parser::ParsedSemantic Semantic;181  if (AttrKind == ParsedAttr::AT_HLSLUnparsedSemantic)182    Semantic = ParseHLSLSemantic();183 184  SourceLocation Loc = ConsumeToken();185  if (EndLoc)186    *EndLoc = Tok.getLocation();187 188  ArgsVector ArgExprs;189  switch (AttrKind) {190  case ParsedAttr::AT_HLSLResourceBinding: {191    if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {192      SkipUntil(tok::r_paren, StopAtSemi); // skip through )193      return;194    }195    if (!Tok.is(tok::identifier)) {196      Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;197      SkipUntil(tok::r_paren, StopAtSemi); // skip through )198      return;199    }200    StringRef SlotStr = Tok.getIdentifierInfo()->getName();201    SourceLocation SlotLoc = Tok.getLocation();202    ArgExprs.push_back(ParseIdentifierLoc());203 204    if (SlotStr.size() == 1) {205      if (!Tok.is(tok::numeric_constant)) {206        Diag(Tok.getLocation(), diag::err_expected) << tok::numeric_constant;207        SkipUntil(tok::r_paren, StopAtSemi); // skip through )208        return;209      }210      // Add numeric_constant for fix-it.211      fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,212                                  Actions.Context, PP);213    }214    if (Tok.is(tok::comma)) {215      ConsumeToken(); // consume comma216      if (!Tok.is(tok::identifier)) {217        Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;218        SkipUntil(tok::r_paren, StopAtSemi); // skip through )219        return;220      }221      StringRef SpaceStr = Tok.getIdentifierInfo()->getName();222      SourceLocation SpaceLoc = Tok.getLocation();223      ArgExprs.push_back(ParseIdentifierLoc());224 225      // Add numeric_constant for fix-it.226      if (SpaceStr == "space" && Tok.is(tok::numeric_constant))227        fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,228                                    Actions.Context, PP);229    }230    if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {231      SkipUntil(tok::r_paren, StopAtSemi); // skip through )232      return;233    }234  } break;235  case ParsedAttr::AT_HLSLPackOffset: {236    // Parse 'packoffset( c[Subcomponent][.component] )'.237    // Check '('.238    if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {239      SkipUntil(tok::r_paren, StopAtSemi); // skip through )240      return;241    }242    // Check c[Subcomponent] as an identifier.243    if (!Tok.is(tok::identifier)) {244      Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;245      SkipUntil(tok::r_paren, StopAtSemi); // skip through )246      return;247    }248    StringRef OffsetStr = Tok.getIdentifierInfo()->getName();249    SourceLocation SubComponentLoc = Tok.getLocation();250    if (OffsetStr[0] != 'c') {251      Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg)252          << OffsetStr;253      SkipUntil(tok::r_paren, StopAtSemi); // skip through )254      return;255    }256    OffsetStr = OffsetStr.substr(1);257    unsigned SubComponent = 0;258    if (!OffsetStr.empty()) {259      // Make sure SubComponent is a number.260      if (OffsetStr.getAsInteger(10, SubComponent)) {261        Diag(SubComponentLoc.getLocWithOffset(1),262             diag::err_hlsl_unsupported_register_number);263        SkipUntil(tok::r_paren, StopAtSemi); // skip through )264        return;265      }266    }267    unsigned Component = 0;268    ConsumeToken(); // consume identifier.269    SourceLocation ComponentLoc;270    if (Tok.is(tok::period)) {271      ConsumeToken(); // consume period.272      if (!Tok.is(tok::identifier)) {273        Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;274        SkipUntil(tok::r_paren, StopAtSemi); // skip through )275        return;276      }277      StringRef ComponentStr = Tok.getIdentifierInfo()->getName();278      ComponentLoc = Tok.getLocation();279      ConsumeToken(); // consume identifier.280      // Make sure Component is a single character.281      if (ComponentStr.size() != 1) {282        Diag(ComponentLoc, diag::err_hlsl_unsupported_component)283            << ComponentStr;284        SkipUntil(tok::r_paren, StopAtSemi); // skip through )285        return;286      }287      switch (ComponentStr[0]) {288      case 'x':289      case 'r':290        Component = 0;291        break;292      case 'y':293      case 'g':294        Component = 1;295        break;296      case 'z':297      case 'b':298        Component = 2;299        break;300      case 'w':301      case 'a':302        Component = 3;303        break;304      default:305        Diag(ComponentLoc, diag::err_hlsl_unsupported_component)306            << ComponentStr;307        SkipUntil(tok::r_paren, StopAtSemi); // skip through )308        return;309      }310    }311    ASTContext &Ctx = Actions.getASTContext();312    QualType SizeTy = Ctx.getSizeType();313    uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);314    ArgExprs.push_back(IntegerLiteral::Create(315        Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc));316    ArgExprs.push_back(IntegerLiteral::Create(317        Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc));318    if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {319      SkipUntil(tok::r_paren, StopAtSemi); // skip through )320      return;321    }322  } break;323  case ParsedAttr::AT_HLSLUnparsedSemantic: {324    ASTContext &Ctx = Actions.getASTContext();325    ArgExprs.push_back(IntegerLiteral::Create(326        Ctx, llvm::APInt(Ctx.getTypeSize(Ctx.IntTy), Semantic.Index), Ctx.IntTy,327        SourceLocation()));328    ArgExprs.push_back(IntegerLiteral::Create(329        Ctx, llvm::APInt(1, Semantic.Explicit), Ctx.BoolTy, SourceLocation()));330    II = PP.getIdentifierInfo(Semantic.Name);331    break;332  }333  case ParsedAttr::UnknownAttribute: // FIXME: maybe this is obsolete?334    break;335  default:336    llvm_unreachable("invalid HLSL Annotation");337    break;338  }339 340  Attrs.addNew(II, Loc, AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(),341               ParsedAttr::Form::HLSLAnnotation());342}343