diff --git a/clang/include/clang/Basic/HLSLRuntime.h b/clang/include/clang/Basic/HLSLRuntime.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/HLSLRuntime.h @@ -0,0 +1,34 @@ +//===- HLSLRuntime.h - HLSL Runtime -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the clang::IdentifierInfo, clang::IdentifierTable, and +/// clang::Selector interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_BASIC_HLSLRUNTIME_H +#define CLANG_BASIC_HLSLRUNTIME_H + +#include + +namespace clang { +namespace hlsl { + +enum class ResourceClass : uint8_t { + SRV = 0, + UAV, + CBuffer, + Sampler, + NumClasses +}; + +} // namespace hlsl +} // namespace clang + +#endif // CLANG_BASIC_HLSLRUNTIME_H diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -11,13 +11,17 @@ #include "clang/Sema/HLSLExternalSemaSource.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/Basic/AttrKinds.h" +#include "clang/Basic/HLSLRuntime.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include using namespace clang; +using namespace hlsl; namespace { @@ -27,6 +31,7 @@ CXXRecordDecl *Record = nullptr; ClassTemplateDecl *Template = nullptr; NamespaceDecl *HLSLNamespace = nullptr; + llvm::StringMap Fields; BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) { Record->startDefinition(); @@ -93,6 +98,7 @@ Field->setAccess(Access); Field->setImplicit(true); Record->addDecl(Field); + Fields[Name] = Field; return *this; } @@ -101,6 +107,71 @@ return addMemberVariable("h", Record->getASTContext().VoidPtrTy, Access); } + static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, + StringRef Name) { + CXXScopeSpec SS; + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + DeclarationNameInfo NameInfo = + DeclarationNameInfo(DeclarationName(&II), SourceLocation()); + LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); + S.LookupParsedName(R, S.getCurScope(), &SS, false); + assert(R.isSingleResult() && + "Since this is a builtin it should always resolve!"); + auto *VD = cast(R.getFoundDecl()); + QualType Ty = VD->getType(); + return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(), + VD, false, NameInfo, Ty, VK_PRValue); + } + + static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) { + return IntegerLiteral::Create( + AST, + llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy), + static_cast(RC)), + AST.UnsignedCharTy, SourceLocation()); + } + + BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S, + ResourceClass RC) { + ASTContext &AST = Record->getASTContext(); + + QualType ConstructorType = + AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo()); + + CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); + DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy); + CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( + AST, Record, SourceLocation(), + DeclarationNameInfo(Name, SourceLocation()), ConstructorType, + AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()), + ExplicitSpecifier(), false, true, false, + ConstexprSpecKind::Unspecified); + + DeclRefExpr *Fn = + lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle"); + + Expr *RCExpr = emitResourceClassExpr(AST, RC); + CallExpr *Call = + CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, + SourceLocation(), FPOptionsOverride()); + + CXXThisExpr *This = new (AST) + CXXThisExpr(SourceLocation(), Constructor->getThisType(), true); + MemberExpr *Handle = MemberExpr::CreateImplicit( + AST, This, true, Fields["h"], Fields["h"]->getType(), VK_LValue, + OK_Ordinary); + BinaryOperator *Assign = BinaryOperator::Create( + AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary, + SourceLocation(), FPOptionsOverride()); + + Constructor->setBody( + CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(), + SourceLocation(), SourceLocation())); + Constructor->setAccess(AccessSpecifier::AS_public); + Record->addDecl(Constructor); + return *this; + } + BuiltinTypeDeclBuilder &startDefinition() { Record->startDefinition(); return *this; @@ -287,5 +358,8 @@ } void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) { - BuiltinTypeDeclBuilder(Record).addHandleMember().completeDefinition(); + BuiltinTypeDeclBuilder(Record) + .addHandleMember() + .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV) + .completeDefinition(); } diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl --- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl +++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl @@ -44,4 +44,4 @@ // CHECK: TemplateArgument type 'float' // CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float' // CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <> Implicit final -// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit h 'void *' +// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <> implicit referenced h 'void *' diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s + +RWBuffer Buf; + +// CHECK: define linkonce_odr noundef ptr @"??0?$RWBuffer@M@hlsl@@QAA@XZ" +// CHECK-NEXT: entry: + +// CHECK: %[[HandleRes:[0-9]+]] = call ptr @llvm.dx.create.handle(i8 1) +// CHECK: store ptr %[[HandleRes]], ptr %h, align 4