Skip to content
Merged
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ class LangOptions : public LangOptionsBase {
llvm::dxbc::RootSignatureVersion HLSLRootSigVer =
llvm::dxbc::RootSignatureVersion::V1_1;

/// The HLSL root signature that will be used to overide the root signature
/// used for the shader entry point.
std::string HLSLRootSigOverride;

// Indicates if the wasm-opt binary must be ignored in the case of a
// WebAssembly target.
bool NoWasmOpt = false;
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -9436,6 +9436,18 @@ def dxc_rootsig_ver :
Alias<fdx_rootsignature_version>,
Group<dxc_Group>,
Visibility<[DXCOption]>;
def fdx_rootsignature_define :
Joined<["-"], "fdx-rootsignature-define=">,
Group<dxc_Group>,
Visibility<[ClangOption, CC1Option]>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exposing this as a Clang option and not just a CC1 option is an interesting choice. I think I like it since I'd like us to someday move away from the DXC driver, but is this a conscious decision? I don't recall that in the proposal (https://github.com/llvm/wg-hlsl/blob/main/proposals/0029-root-signature-driver-options.md).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression that in general we were adding these to clang as well, see hlsl-entry, dxil-validator-version, dx_rootsignature_version, etc.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we have no tests that actually test that, I'm going to guess that's a copypasta mistake, not an intentional design decision. That said I'm okay leaving this as-is.

MarshallingInfoString<LangOpts<"HLSLRootSigOverride">, "\"\"">,
HelpText<"Override entry function root signature with root signature at "
"given macro name.">;
def dxc_rootsig_define :
Separate<["-"], "rootsig-define">,
Alias<fdx_rootsignature_define>,
Group<dxc_Group>,
Visibility<[DXCOption]>;
def hlsl_entrypoint : Option<["-"], "hlsl-entry", KIND_SEPARATE>,
Group<dxc_Group>,
Visibility<[ClangOption, CC1Option]>,
Expand Down
26 changes: 26 additions & 0 deletions clang/include/clang/HLSL/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===- HLSL/FrontendActions.h -----------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H
#define LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H

#include "clang/Frontend/FrontendAction.h"

namespace clang {

class HLSLFrontendAction : public WrapperFrontendAction {
protected:
void ExecuteAction() override;

public:
HLSLFrontendAction(std::unique_ptr<FrontendAction> WrappedAction);
};

} // namespace clang

#endif // LLVM_CLANG_HLSL_FRONTEND_ACTIONS_H
4 changes: 4 additions & 0 deletions clang/include/clang/Parse/ParseHLSLRootSignature.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ class RootSignatureParser {
RootSignatureToken CurToken;
};

IdentifierInfo *ParseHLSLRootSignature(Sema &Actions,
llvm::dxbc::RootSignatureVersion Version,
StringLiteral *Signature);

} // namespace hlsl
} // namespace clang

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ class SemaHLSL : public SemaBase {
ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent,
ArrayRef<hlsl::RootSignatureElement> Elements);

void SetRootSignatureOverride(IdentifierInfo *DeclIdent) {
RootSigOverrideIdent = DeclIdent;
}

// Returns true if any RootSignatureElement is invalid and a diagnostic was
// produced
bool
Expand Down Expand Up @@ -221,6 +225,8 @@ class SemaHLSL : public SemaBase {

uint32_t ImplicitBindingNextOrderID = 0;

IdentifierInfo *RootSigOverrideIdent = nullptr;

private:
void collectResourceBindingsOnVarDecl(VarDecl *D);
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7534,6 +7534,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
getContext().getCanonicalTagType(cast<EnumDecl>(D)));
break;

// Will be handled by attached function
case Decl::HLSLRootSignature:
break;
case Decl::HLSLBuffer:
getHLSLRuntime().addBuffer(cast<HLSLBufferDecl>(D));
break;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3801,6 +3801,7 @@ static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
options::OPT_disable_llvm_passes,
options::OPT_fnative_half_type,
options::OPT_hlsl_entrypoint,
options::OPT_fdx_rootsignature_define,
options::OPT_fdx_rootsignature_version};
if (!types::isHLSL(InputType))
return;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/HLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,13 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
A->claim();
continue;
}
if (A->getOption().getID() == options::OPT_dxc_rootsig_define) {
DAL->AddJoinedArg(nullptr,
Opts.getOption(options::OPT_fdx_rootsignature_define),
A->getValue());
A->claim();
continue;
}
if (A->getOption().getID() == options::OPT__SLASH_O) {
StringRef OStr = A->getValue();
if (OStr == "d") {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Frontend/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_subdirectory(Rewrite)
add_subdirectory(HLSL)

set(LLVM_LINK_COMPONENTS
BitReader
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
Diags.Report(diag::err_drv_argument_not_allowed_with)
<< "-fdx-rootsignature-version" << GetInputKindName(IK);

if (Args.hasArg(OPT_fdx_rootsignature_define) && !LangOpts.HLSL)
Diags.Report(diag::err_drv_argument_not_allowed_with)
<< "-fdx-rootsignature-define" << GetInputKindName(IK);

if (Args.hasArg(OPT_fgpu_allow_device_init) && !LangOpts.HIP)
Diags.Report(diag::warn_ignored_hip_only_option)
<< Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args);
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Frontend/HLSL/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set(LLVM_LINK_COMPONENTS
Support
)

add_clang_library(clangHLSLFrontend
FrontendActions.cpp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was feedback provided somewhere to put this in its own library? I don't expect that we'll have a lot of unique HLSL Frontend options and I'm unsure this is really necessary since it isn't really a separable component.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No feedback to, I had just been following Frontend/Rewrite/FrontendActions.

I will move this to clang/FrontendAction/FrontendActions.[h|cpp].


LINK_LIBS
clangAST
clangBasic
clangFrontend
clangParse
clangSema
)
93 changes: 93 additions & 0 deletions clang/lib/Frontend/HLSL/FrontendActions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===--- FrontendActions.cpp ----------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "clang/HLSL/Frontend/FrontendActions.h"
#include "clang/Parse/ParseHLSLRootSignature.h"
#include "clang/Sema/Sema.h"

namespace clang {

class InjectRootSignatureCallback : public PPCallbacks {
private:
Sema &Actions;
StringRef RootSigName;
llvm::dxbc::RootSignatureVersion Version;

std::optional<StringLiteral *> processStringLiteral(ArrayRef<Token> Tokens) {
for (Token Tok : Tokens)
if (!tok::isStringLiteral(Tok.getKind()))
return std::nullopt;

ExprResult StringResult = Actions.ActOnUnevaluatedStringLiteral(Tokens);
if (StringResult.isInvalid())
return std::nullopt;

if (auto Signature = dyn_cast<StringLiteral>(StringResult.get()))
return Signature;

return std::nullopt;
}

public:
void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
if (RootSigName != MacroNameTok.getIdentifierInfo()->getName())
return;

const MacroInfo *MI = MD->getMacroInfo();
auto Signature = processStringLiteral(MI->tokens());
if (!Signature.has_value()) {
Actions.getDiagnostics().Report(MI->getDefinitionLoc(),
diag::err_expected_string_literal)
<< /*in attributes...*/ 4 << "RootSignature";
return;
}

IdentifierInfo *DeclIdent =
hlsl::ParseHLSLRootSignature(Actions, Version, *Signature);
Actions.HLSL().SetRootSignatureOverride(DeclIdent);
}

InjectRootSignatureCallback(Sema &Actions, StringRef RootSigName,
llvm::dxbc::RootSignatureVersion Version)
: PPCallbacks(), Actions(Actions), RootSigName(RootSigName),
Version(Version) {}
};

void HLSLFrontendAction::ExecuteAction() {
// Pre-requisites to invoke
CompilerInstance &CI = getCompilerInstance();
if (!CI.hasASTContext() || !CI.hasPreprocessor())
return WrapperFrontendAction::ExecuteAction();

// InjectRootSignatureCallback requires access to invoke Sema to lookup/
// register a root signature declaration. The wrapped action is required to
// account for this by only creating a Sema if one doesn't already exist
// (like we have done, and, ASTFrontendAction::ExecuteAction)
if (!CI.hasSema())
CI.createSema(getTranslationUnitKind(),
/*CodeCompleteConsumer=*/nullptr);
Sema &S = CI.getSema();

// Register HLSL specific callbacks
auto LangOpts = CI.getLangOpts();
auto MacroCallback = std::make_unique<InjectRootSignatureCallback>(
S, LangOpts.HLSLRootSigOverride, LangOpts.HLSLRootSigVer);

Preprocessor &PP = CI.getPreprocessor();
PP.addPPCallbacks(std::move(MacroCallback));

// Invoke as normal
WrapperFrontendAction::ExecuteAction();
}

HLSLFrontendAction::HLSLFrontendAction(
std::unique_ptr<FrontendAction> WrappedAction)
: WrapperFrontendAction(std::move(WrappedAction)) {}

} // namespace clang
1 change: 1 addition & 0 deletions clang/lib/FrontendTool/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(link_libs
clangExtractAPI
clangFrontend
clangRewriteFrontend
clangHLSLFrontend
)

set(deps)
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/Utils.h"
#include "clang/FrontendTool/Utils.h"
#include "clang/HLSL/Frontend/FrontendActions.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
Expand Down Expand Up @@ -181,6 +182,10 @@ CreateFrontendAction(CompilerInstance &CI) {

const FrontendOptions &FEOpts = CI.getFrontendOpts();

if (CI.getLangOpts().HLSL) {
Act = std::make_unique<HLSLFrontendAction>(std::move(Act));
}

if (FEOpts.FixAndRecompile) {
Act = std::make_unique<FixItRecompile>(std::move(Act));
}
Expand Down
31 changes: 9 additions & 22 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4923,33 +4923,20 @@ void Parser::ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
return std::nullopt;
};

auto StrLiteral = ProcessStringLiteral();
if (!StrLiteral.has_value()) {
auto Signature = ProcessStringLiteral();
if (!Signature.has_value()) {
Diag(Tok, diag::err_expected_string_literal)
<< /*in attributes...*/ 4 << RootSignatureIdent->getName();
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
T.consumeClose();
<< /*in attributes...*/ 4 << "RootSignature";
return;
}

// Construct our identifier
StringLiteral *Signature = StrLiteral.value();
auto [DeclIdent, Found] =
Actions.HLSL().ActOnStartRootSignatureDecl(Signature->getString());
// If we haven't found an already defined DeclIdent then parse the root
// signature string and construct the in-memory elements
if (!Found) {
// Invoke the root signature parser to construct the in-memory constructs
hlsl::RootSignatureParser Parser(getLangOpts().HLSLRootSigVer, Signature,
PP);
if (Parser.parse()) {
T.consumeClose();
return;
}

// Construct the declaration.
Actions.HLSL().ActOnFinishRootSignatureDecl(RootSignatureLoc, DeclIdent,
Parser.getElements());
IdentifierInfo *DeclIdent = hlsl::ParseHLSLRootSignature(
Actions, getLangOpts().HLSLRootSigVer, *Signature);
if (!DeclIdent) {
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
T.consumeClose();
return;
}

// Create the arg for the ParsedAttr
Expand Down
24 changes: 24 additions & 0 deletions clang/lib/Parse/ParseHLSLRootSignature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "clang/Parse/ParseHLSLRootSignature.h"

#include "clang/Lex/LiteralSupport.h"
#include "clang/Sema/Sema.h"

using namespace llvm::hlsl::rootsig;

Expand Down Expand Up @@ -1448,5 +1449,28 @@ SourceLocation RootSignatureParser::getTokenLocation(RootSignatureToken Tok) {
PP.getLangOpts(), PP.getTargetInfo());
}

IdentifierInfo *ParseHLSLRootSignature(Sema &Actions,
llvm::dxbc::RootSignatureVersion Version,
StringLiteral *Signature) {
// Construct our identifier
auto [DeclIdent, Found] =
Actions.HLSL().ActOnStartRootSignatureDecl(Signature->getString());
// If we haven't found an already defined DeclIdent then parse the root
// signature string and construct the in-memory elements
if (!Found) {
// Invoke the root signature parser to construct the in-memory constructs
hlsl::RootSignatureParser Parser(Version, Signature,
Actions.getPreprocessor());
if (Parser.parse())
return nullptr;

// Construct the declaration.
Actions.HLSL().ActOnFinishRootSignatureDecl(
Signature->getBeginLoc(), DeclIdent, Parser.getElements());
}

return DeclIdent;
}

} // namespace hlsl
} // namespace clang
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,23 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry)
return;

// If we have specified a root signature to override the entry function then
// attach it now
if (RootSigOverrideIdent) {
LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(),
Sema::LookupOrdinaryName);
if (SemaRef.LookupQualifiedName(R, FD->getDeclContext()))
if (auto *SignatureDecl =
dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
FD->dropAttr<RootSignatureAttr>();
// We could look up the SourceRange of the macro here as well
AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(),
SourceRange(), ParsedAttr::Form::Microsoft());
FD->addAttr(::new (getASTContext()) RootSignatureAttr(
getASTContext(), AL, RootSigOverrideIdent, SignatureDecl));
}
}

llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
Expand Down
Loading