Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 38 additions & 22 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ struct TemplateParameterListBuilder {
//
// BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType)
// .addParam("param_name", Type, InOutModifier)
// .callBuiltin("buildin_name", { BuiltinParams })
// .callBuiltin("buildin_name", BuiltinParams... )
// .finalizeMethod();
//
// The builder needs to have all of the method parameters before it can create
Expand All @@ -465,9 +465,9 @@ struct TemplateParameterListBuilder {
// referenced from the body building methods. Destructor or an explicit call to
// finalizeMethod() will complete the method definition.
//
// The callBuiltin helper method passes in the resource handle as the first
// argument of the builtin call. If this is not desired it takes a bool flag to
// disable this.
// The callBuiltin helper method accepts constants via `Expr *` or placeholder
// value arguments to indicate which function arguments to forward to the
// builtin.
//
// If the method that is being built has a non-void return type the
// finalizeMethod will create a return statent with the value of the last
Expand All @@ -489,6 +489,24 @@ struct BuiltinTypeMethodBuilder {
llvm::SmallVector<MethodParam> Params;
llvm::SmallVector<Stmt *> StmtsList;

// Argument placeholders, inspired by std::placeholder. These are the indices
// of arguments to forward to `callBuiltin`, and additionally `Handle` which
// refers to the resource handle.
enum class PlaceHolder { _0, _1, _2, _3, Handle = 127 };

Expr *convertPlaceholder(PlaceHolder PH) {
if (PH == PlaceHolder::Handle)
return getResourceHandleExpr();

ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));
return DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
ParamDecl->getType(), VK_PRValue);
}
Expr *convertPlaceholder(Expr *E) { return E; }

public:
BuiltinTypeMethodBuilder(Sema &S, BuiltinTypeDeclBuilder &DB, StringRef Name,
QualType ReturnTy)
Expand All @@ -502,7 +520,10 @@ struct BuiltinTypeMethodBuilder {
HLSLParamModifierAttr::Spelling Modifier =
HLSLParamModifierAttr::Keyword_in) {
assert(Method == nullptr && "Cannot add param, method already created");
llvm_unreachable("not yet implemented");
const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(
Name, tok::TokenKind::identifier);
Params.emplace_back(II, Ty, Modifier);
return *this;
}

private:
Expand Down Expand Up @@ -564,9 +585,9 @@ struct BuiltinTypeMethodBuilder {
OK_Ordinary);
}

BuiltinTypeMethodBuilder &
callBuiltin(StringRef BuiltinName, ArrayRef<Expr *> CallParms,
bool AddResourceHandleAsFirstArg = true) {
template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, Ts... ArgSpecs) {
SmallVector<Expr *> Args{convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
Copy link
Contributor

Choose a reason for hiding this comment

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

Is SmallVector smart enough for this to evaporate into being a stack allocated array, or is there a chance that it might make a heap allocation to store the args?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, SmallVector will have stack allocated storage. Its size is derived from the initialization, which is dependent on the number of ArgSpecs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This raises a good point though - I'll change this to just use std::array here since we know the exact size at compile time.


// The first statement added to a method or access to 'this` creates the
// declaration.
Expand All @@ -579,16 +600,9 @@ struct BuiltinTypeMethodBuilder {
AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
FD->getNameInfo(), FD->getType(), VK_PRValue);

SmallVector<Expr *> NewCallParms;
if (AddResourceHandleAsFirstArg) {
NewCallParms.push_back(getResourceHandleExpr());
for (auto *P : CallParms)
NewCallParms.push_back(P);
}

Expr *Call = CallExpr::Create(
AST, DRE, AddResourceHandleAsFirstArg ? NewCallParms : CallParms,
FD->getReturnType(), VK_PRValue, SourceLocation(), FPOptionsOverride());
Expr *Call =
CallExpr::Create(AST, DRE, Args, FD->getReturnType(), VK_PRValue,
SourceLocation(), FPOptionsOverride());
StmtsList.push_back(Call);
return *this;
}
Expand Down Expand Up @@ -656,18 +670,20 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
return BuiltinTypeMethodBuilder(SemaRef, *this, "IncrementCounter",
SemaRef.getASTContext().UnsignedIntTy)
.callBuiltin("__builtin_hlsl_buffer_update_counter",
{getConstantIntExpr(1)})
.callBuiltin("__builtin_hlsl_buffer_update_counter", PH::Handle,
getConstantIntExpr(1))
Copy link
Contributor

Choose a reason for hiding this comment

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

How evil would it be to add a Expr *convertPlaceholder(int) that does the getConstantIntExpr for you, so this could be written as: .callBuiltin("__builtin_hlsl_buffer_update_conter", PH::Handle, 1)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This feels too magical to me (and also it introduces an annoying ambiguity with a literal zero - is it an int or a null Expr *?)

.finalizeMethod();
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
return BuiltinTypeMethodBuilder(SemaRef, *this, "DecrementCounter",
SemaRef.getASTContext().UnsignedIntTy)
.callBuiltin("__builtin_hlsl_buffer_update_counter",
{getConstantIntExpr(-1)})
.callBuiltin("__builtin_hlsl_buffer_update_counter", PH::Handle,
getConstantIntExpr(-1))
.finalizeMethod();
}

Expand Down