https://github.com/hekota created 
https://github.com/llvm/llvm-project/pull/132453

None

>From 47b41c88a60a7f376070b9ff779ec955eebf523a Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Wed, 12 Mar 2025 17:20:51 -0700
Subject: [PATCH 1/3] [HLSL] Create default resource constructor with
 BuiltinTypeMethodBuilder

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 126 ++++++++++--------
 1 file changed, 72 insertions(+), 54 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index db0ed3434d837..a52c6a49264c8 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -89,21 +89,24 @@ struct TemplateParameterListBuilder {
 // statement (unless the last statement is already a ReturnStmt).
 struct BuiltinTypeMethodBuilder {
 private:
-  struct MethodParam {
+  struct Param {
     const IdentifierInfo &NameII;
     QualType Ty;
     HLSLParamModifierAttr::Spelling Modifier;
-    MethodParam(const IdentifierInfo &NameII, QualType Ty,
-                HLSLParamModifierAttr::Spelling Modifier)
+    Param(const IdentifierInfo &NameII, QualType Ty,
+          HLSLParamModifierAttr::Spelling Modifier)
         : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
   };
 
   BuiltinTypeDeclBuilder &DeclBuilder;
-  DeclarationNameInfo NameInfo;
+  DeclarationName Name;
   QualType ReturnTy;
+  // method or constructor declaration (CXXConstructorDecl derives from
+  // CXXMethodDecl)
   CXXMethodDecl *Method;
   bool IsConst;
-  llvm::SmallVector<MethodParam> Params;
+  bool IsConstructor;
+  llvm::SmallVector<Param> Params;
   llvm::SmallVector<Stmt *> StmtsList;
 
   // Argument placeholders, inspired by std::placeholder. These are the indices
@@ -122,12 +125,14 @@ struct BuiltinTypeMethodBuilder {
   friend BuiltinTypeDeclBuilder;
 
   BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
-                           QualType ReturnTy, bool IsConst = false)
-      : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
-        ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}
-
-  BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
-                           QualType ReturnTy, bool IsConst = false);
+                           QualType ReturnTy, bool IsConst = false,
+                           bool IsConstructor = false)
+      : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
+        IsConst(IsConst), IsConstructor(IsConstructor) {}
+
+  BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
+                           QualType ReturnTy, bool IsConst = false,
+                           bool IsConstructor = false);
   BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
 
   ~BuiltinTypeMethodBuilder() { finalizeMethod(); }
@@ -148,7 +153,14 @@ struct BuiltinTypeMethodBuilder {
   Expr *getResourceHandleExpr();
 
 private:
-  void createMethodDecl();
+  void createDecl();
+
+  // Makes sure the declaration is created; should be called before any
+  // statement added or when access to 'this' is needed.
+  void ensureCompleteDecl() {
+    if (!Method)
+      createDecl();
+  }
 };
 
 TemplateParameterListBuilder::~TemplateParameterListBuilder() {
@@ -323,13 +335,26 @@ Expr 
*BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
 }
 
 BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
-                                                   StringRef Name,
+                                                   StringRef NameStr,
                                                    QualType ReturnTy,
-                                                   bool IsConst)
-    : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
-  const IdentifierInfo &II =
-      DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
-  NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+                                                   bool IsConst,
+                                                   bool IsConstructor)
+    : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
+      IsConstructor(IsConstructor) {
+
+  assert((!NameStr.empty() || IsConstructor) && "method needs a name");
+  assert(((IsConstructor && !IsConst) || !IsConstructor) &&
+         "constructor cannot be const");
+
+  ASTContext &AST = DB.SemaRef.getASTContext();
+  if (IsConstructor) {
+    Name = AST.DeclarationNames.getCXXConstructorName(
+        DB.Record->getTypeForDecl()->getCanonicalTypeUnqualified());
+  } else {
+    const IdentifierInfo &II =
+        AST.Idents.get(NameStr, tok::TokenKind::identifier);
+    Name = DeclarationName(&II);
+  }
 }
 
 BuiltinTypeMethodBuilder &
@@ -342,13 +367,13 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, 
QualType Ty,
   return *this;
 }
 
-void BuiltinTypeMethodBuilder::createMethodDecl() {
-  assert(Method == nullptr && "Method already created");
+void BuiltinTypeMethodBuilder::createDecl() {
+  assert(Method == nullptr && "Method or constructor is already created");
 
-  // create method type
+  // create method or constructor type
   ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
   SmallVector<QualType> ParamTypes;
-  for (MethodParam &MP : Params)
+  for (Param &MP : Params)
     ParamTypes.emplace_back(MP.Ty);
 
   FunctionProtoType::ExtProtoInfo ExtInfo;
@@ -357,18 +382,26 @@ void BuiltinTypeMethodBuilder::createMethodDecl() {
 
   QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
 
-  // create method decl
+  // create method or constructor decl
   auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
-  Method = CXXMethodDecl::Create(
-      AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo,
-      SC_None, false, false, ConstexprSpecKind::Unspecified, SourceLocation());
+  DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation());
+  if (IsConstructor)
+    Method = CXXConstructorDecl::Create(
+        AST, DeclBuilder.Record, SourceLocation(), NameInfo, MethodTy, TSInfo,
+        ExplicitSpecifier(), false, true, false,
+        ConstexprSpecKind::Unspecified);
+  else
+    Method =
+        CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
+                              NameInfo, MethodTy, TSInfo, SC_None, false, 
false,
+                              ConstexprSpecKind::Unspecified, 
SourceLocation());
 
   // create params & set them to the function prototype
   SmallVector<ParmVarDecl *> ParmDecls;
   auto FnProtoLoc =
       Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
   for (int I = 0, E = Params.size(); I != E; I++) {
-    MethodParam &MP = Params[I];
+    Param &MP = Params[I];
     ParmVarDecl *Parm = ParmVarDecl::Create(
         AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
         &MP.NameII, MP.Ty,
@@ -386,10 +419,7 @@ void BuiltinTypeMethodBuilder::createMethodDecl() {
 }
 
 Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
-  // The first statement added to a method or access to 'this' creates the
-  // declaration.
-  if (!Method)
-    createMethodDecl();
+  ensureCompleteDecl();
 
   ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
   CXXThisExpr *This = CXXThisExpr::Create(
@@ -407,10 +437,7 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef 
BuiltinName,
   std::array<Expr *, sizeof...(ArgSpecs)> Args{
       convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
 
-  // The first statement added to a method or access to 'this` creates the
-  // declaration.
-  if (!Method)
-    createMethodDecl();
+  ensureCompleteDecl();
 
   ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
   FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
@@ -454,8 +481,8 @@ BuiltinTypeMethodBuilder 
&BuiltinTypeMethodBuilder::dereference(T Ptr) {
 BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalizeMethod() {
   assert(!DeclBuilder.Record->isCompleteDefinition() &&
          "record is already complete");
-  assert(Method != nullptr &&
-         "method decl not created; are you missing a call to build the body?");
+
+  ensureCompleteDecl();
 
   if (!Method->hasBody()) {
     ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
@@ -600,27 +627,18 @@ BuiltinTypeDeclBuilder::addHandleMember(ResourceClass RC, 
ResourceKind RK,
   return *this;
 }
 
+// Adds default constructor to the resource class:
+// Resource::Resource()
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
   if (Record->isCompleteDefinition())
     return *this;
-  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);
-
-  Constructor->setBody(CompoundStmt::Create(
-      AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
-  Constructor->setAccess(AccessSpecifier::AS_public);
-  Record->addDecl(Constructor);
-  return *this;
+  // FIXME: initialize handle to poison value; this can be added after
+  // resource constructor from binding is implemented, otherwise the handle
+  // value will get overwritten.
+  return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
+                                  false, true)
+      .finalizeMethod();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {

>From 4301a06b4dc2f96de3ea76e23685fa8b4b99e534 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Wed, 12 Mar 2025 17:51:18 -0700
Subject: [PATCH 2/3] rename finalizeMethod to finalize

---
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 27 ++++++++++---------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index a52c6a49264c8..058525d77d99e 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -71,22 +71,23 @@ struct TemplateParameterListBuilder {
 //   BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
 //       .addParam("param_name", Type, InOutModifier)
 //       .callBuiltin("builtin_name", BuiltinParams...)
-//       .finalizeMethod();
+//       .finalize();
 //
 // The builder needs to have all of the method parameters before it can create
 // a CXXMethodDecl. It collects them in addParam calls and when a first
 // method that builds the body is called or when access to 'this` is needed it
 // creates the CXXMethodDecl and ParmVarDecls instances. These can then be
 // referenced from the body building methods. Destructor or an explicit call to
-// finalizeMethod() will complete the method definition.
+// finalize() will complete the method definition.
 //
 // 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
-// statement (unless the last statement is already a ReturnStmt).
+// finalize() will create a return statement with the value of the last
+// statement (unless the last statement is already a ReturnStmt or the return
+// value is void).
 struct BuiltinTypeMethodBuilder {
 private:
   struct Param {
@@ -135,7 +136,7 @@ struct BuiltinTypeMethodBuilder {
                            bool IsConstructor = false);
   BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
 
-  ~BuiltinTypeMethodBuilder() { finalizeMethod(); }
+  ~BuiltinTypeMethodBuilder() { finalize(); }
 
   BuiltinTypeMethodBuilder &
   operator=(const BuiltinTypeMethodBuilder &Other) = delete;
@@ -149,7 +150,7 @@ struct BuiltinTypeMethodBuilder {
   template <typename TLHS, typename TRHS>
   BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
   template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
-  BuiltinTypeDeclBuilder &finalizeMethod();
+  BuiltinTypeDeclBuilder &finalize();
   Expr *getResourceHandleExpr();
 
 private:
@@ -478,7 +479,7 @@ BuiltinTypeMethodBuilder 
&BuiltinTypeMethodBuilder::dereference(T Ptr) {
   return *this;
 }
 
-BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalizeMethod() {
+BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
   assert(!DeclBuilder.Record->isCompleteDefinition() &&
          "record is already complete");
 
@@ -638,7 +639,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
   // value will get overwritten.
   return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
                                   false, true)
-      .finalizeMethod();
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
@@ -732,7 +733,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
                                   SemaRef.getASTContext().UnsignedIntTy)
       .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
                    PH::Handle, getConstantIntExpr(1))
-      .finalizeMethod();
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
@@ -741,7 +742,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
                                   SemaRef.getASTContext().UnsignedIntTy)
       .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
                    PH::Handle, getConstantIntExpr(-1))
-      .finalizeMethod();
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &
@@ -765,7 +766,7 @@ 
BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
       .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
                    PH::_0)
       .dereference(PH::LastStmt)
-      .finalizeMethod();
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
@@ -780,7 +781,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addAppendMethod() {
                    AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
       .dereference(PH::LastStmt)
       .assign(PH::LastStmt, PH::_0)
-      .finalizeMethod();
+      .finalize();
 }
 
 BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
@@ -793,7 +794,7 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addConsumeMethod() {
       .callBuiltin("__builtin_hlsl_resource_getpointer",
                    AST.getPointerType(ElemTy), PH::Handle, PH::LastStmt)
       .dereference(PH::LastStmt)
-      .finalizeMethod();
+      .finalize();
 }
 
 } // namespace hlsl

>From e9a80485e8f146506469aab74bd555d79dcf4e40 Mon Sep 17 00:00:00 2001
From: Helena Kotas <heko...@microsoft.com>
Date: Fri, 14 Mar 2025 12:52:51 -0700
Subject: [PATCH 3/3] Implement resource constructors

Adds resource constructor that initializes resource handle based on resource 
binding
Updated default constructor to set the handle value to poison

WIP
---
 clang/include/clang/Basic/Builtins.td         |  12 ++
 clang/include/clang/Sema/SemaHLSL.h           |   4 +
 clang/lib/CodeGen/CGBuiltin.cpp               |  18 +++
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |   2 +-
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp |  35 +++++-
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h   |   1 +
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |   3 +-
 clang/lib/Sema/SemaDecl.cpp                   |   6 +-
 clang/lib/Sema/SemaHLSL.cpp                   |  87 +++++++++++++++
 .../ByteAddressBuffers-constructors.hlsl      |  97 ++++++++++++----
 .../builtins/RWBuffer-constructor-opt.hlsl    |   2 +-
 .../builtins/RWBuffer-constructor.hlsl        |  78 +++++++++++--
 .../StructuredBuffers-constructors.hlsl       | 105 ++++++++++++------
 clang/test/CodeGenHLSL/resource-bindings.hlsl |  50 +++++----
 14 files changed, 404 insertions(+), 96 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 2fbdfaea57ccd..8e3828e4a4771 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4783,6 +4783,18 @@ def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
+def HLSLResourceCreatePoisonHandle : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_resource_createpoisonhandle"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
+def HLSLResourceCreateHandleFromBinding : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_resource_createhandlefrombinding"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(...)";
+}
+
 def HLSLAll : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_all"];
   let Attributes = [NoThrow, Const];
diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index f333fe30e8da0..4ad00b210cccf 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -105,6 +105,7 @@ class SemaHLSL : public SemaBase {
                          HLSLParamModifierAttr::Spelling Spelling);
   void ActOnTopLevelFunction(FunctionDecl *FD);
   void ActOnVariableDeclarator(VarDecl *VD);
+  bool ActOnUninitializedVarDecl(VarDecl *D);
   void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
   void CheckEntryPoint(FunctionDecl *FD);
   void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
@@ -179,6 +180,9 @@ class SemaHLSL : public SemaBase {
   void processExplicitBindingsOnDecl(VarDecl *D);
 
   void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
+  bool initResourceVarFromBinding(VarDecl *VD, unsigned SpaceNo,
+                                  unsigned RegisterNo, int32_t Range,
+                                  unsigned Index);
 };
 
 } // namespace clang
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a5ed2595bad4d..5e364b5913a13 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -19579,6 +19579,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
         RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
         ArrayRef<Value *>{HandleOp, IndexOp});
   }
+  case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: {
+    llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
+    return llvm::PoisonValue::get(HandleTy);
+  }
+  case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: {
+    llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
+    Value *SpaceNoOp = EmitScalarExpr(E->getArg(1));
+    Value *RegisterNoOp = EmitScalarExpr(E->getArg(2));
+    Value *RangeOp = EmitScalarExpr(E->getArg(3));
+    Value *IndexOp = EmitScalarExpr(E->getArg(4));
+    // FIXME: NonUniformResourceIndex bit is not yet implemented
+    Value *NonUniform =
+        llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), false);
+    return Builder.CreateIntrinsic(
+        HandleTy, CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
+        ArrayRef<Value *>{SpaceNoOp, RegisterNoOp, RangeOp, IndexOp,
+                          NonUniform});
+  }
   case Builtin::BI__builtin_hlsl_all: {
     Value *Op0 = EmitScalarExpr(E->getArg(0));
     return Builder.CreateIntrinsic(
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index dc34653e8f497..b4e693dbe85f2 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -659,7 +659,7 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl 
*VD,
     // not implemented yet.
     return;
 
-  createResourceInitFn(CGM, GV, RBA->getSlotNumber(), RBA->getSpaceNumber());
+  // createResourceInitFn(CGM, GV, RBA->getSlotNumber(), 
RBA->getSpaceNumber());
 }
 
 llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
index 058525d77d99e..602688d575252 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -399,6 +399,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
 
   // create params & set them to the function prototype
   SmallVector<ParmVarDecl *> ParmDecls;
+  unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth();
   auto FnProtoLoc =
       Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
   for (int I = 0, E = Params.size(); I != E; I++) {
@@ -413,6 +414,7 @@ void BuiltinTypeMethodBuilder::createDecl() {
           HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
       Parm->addAttr(Mod);
     }
+    Parm->setScopeInfo(CurScopeDepth, I);
     ParmDecls.push_back(Parm);
     FnProtoLoc.setParam(I, Parm);
   }
@@ -446,10 +448,14 @@ BuiltinTypeMethodBuilder::callBuiltin(StringRef 
BuiltinName,
       AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
       FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);
 
+  auto *ImpCast = ImplicitCastExpr::Create(
+      AST, AST.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr, DRE, 
nullptr,
+      VK_PRValue, FPOptionsOverride());
+
   if (ReturnType.isNull())
     ReturnType = FD->getReturnType();
 
-  Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
+  Expr *Call = CallExpr::Create(AST, ImpCast, Args, ReturnType, VK_PRValue,
                                 SourceLocation(), FPOptionsOverride());
   StmtsList.push_back(Call);
   return *this;
@@ -634,11 +640,32 @@ BuiltinTypeDeclBuilder 
&BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
   if (Record->isCompleteDefinition())
     return *this;
 
-  // FIXME: initialize handle to poison value; this can be added after
-  // resource constructor from binding is implemented, otherwise the handle
-  // value will get overwritten.
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
   return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
                                   false, true)
+      .callBuiltin("__builtin_hlsl_resource_createpoisonhandle", QualType(),
+                   PH::Handle)
+      .assign(PH::Handle, PH::LastStmt)
+      .finalize();
+}
+
+BuiltinTypeDeclBuilder &
+BuiltinTypeDeclBuilder::addHandleConstructorFromBinding() {
+  if (Record->isCompleteDefinition())
+    return *this;
+
+  using PH = BuiltinTypeMethodBuilder::PlaceHolder;
+  ASTContext &AST = SemaRef.getASTContext();
+  QualType HandleType = getResourceHandleField()->getType();
+
+  return BuiltinTypeMethodBuilder(*this, "", AST.VoidTy, false, true)
+      .addParam("spaceNo", AST.UnsignedIntTy)
+      .addParam("registerNo", AST.UnsignedIntTy)
+      .addParam("range", AST.IntTy)
+      .addParam("index", AST.UnsignedIntTy)
+      .callBuiltin("__builtin_hlsl_resource_createhandlefrombinding",
+                   HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3)
+      .assign(PH::Handle, PH::LastStmt)
       .finalize();
 }
 
diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h 
b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
index 2c944c4a60038..2d3abb6055669 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
@@ -74,6 +74,7 @@ class BuiltinTypeDeclBuilder {
 
   // Builtin types methods
   BuiltinTypeDeclBuilder &addDefaultHandleConstructor();
+  BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
 
   // Builtin types methods
   BuiltinTypeDeclBuilder &addLoadMethods();
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp 
b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 9224f12f2d025..7b477249de0a7 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -131,7 +131,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl 
*Decl, Sema &S,
                                               bool IsROV, bool RawBuffer) {
   return BuiltinTypeDeclBuilder(S, Decl)
       .addHandleMember(RC, RK, IsROV, RawBuffer)
-      .addDefaultHandleConstructor();
+      .addDefaultHandleConstructor()
+      .addHandleConstructorFromBinding();
 }
 
 // This function is responsible for constructing the constraint expression for
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9c67fbd40ac71..b56f0b36b390e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14340,10 +14340,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
         Var->getType().getAddressSpace() == LangAS::opencl_local)
       return;
 
-    // In HLSL, objects in the hlsl_constant address space are initialized
-    // externally, so don't synthesize an implicit initializer.
-    if (getLangOpts().HLSL &&
-        Var->getType().getAddressSpace() == LangAS::hlsl_constant)
+    // Handle HLSL uninitialized decls
+    if (getLangOpts().HLSL && HLSL().ActOnUninitializedVarDecl(Var))
       return;
 
     // C++03 [dcl.init]p9:
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d10acd1b7807c..6971c3780766b 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
@@ -308,6 +309,10 @@ static bool isResourceRecordTypeOrArrayOf(const Type *Ty) {
   return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr;
 }
 
+static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
+  return isResourceRecordTypeOrArrayOf(VD->getType().getTypePtr());
+}
+
 // Returns true if the type is a leaf element type that is not valid to be
 // included in HLSL Buffer, such as a resource class, empty struct, zero-sized
 // array, or a builtin intangible type. Returns false it is a valid leaf 
element
@@ -2359,6 +2364,29 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned 
BuiltinID, CallExpr *TheCall) {
 
     break;
   }
+  case Builtin::BI__builtin_hlsl_resource_createpoisonhandle: {
+    if (SemaRef.checkArgCount(TheCall, 1) ||
+        CheckResourceHandle(&SemaRef, TheCall, 0))
+      return true;
+    // use the type of the handle (arg0) as a return type
+    QualType ResourceTy = TheCall->getArg(0)->getType();
+    TheCall->setType(ResourceTy);
+    break;
+  }
+  case Builtin::BI__builtin_hlsl_resource_createhandlefrombinding: {
+    ASTContext &AST = SemaRef.getASTContext();
+    if (SemaRef.checkArgCount(TheCall, 5) ||
+        CheckResourceHandle(&SemaRef, TheCall, 0) ||
+        CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) ||
+        CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) ||
+        CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) ||
+        CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy))
+      return true;
+    // use the type of the handle (arg0) as a return type
+    QualType ResourceTy = TheCall->getArg(0)->getType();
+    TheCall->setType(ResourceTy);
+    break;
+  }
   case Builtin::BI__builtin_hlsl_and:
   case Builtin::BI__builtin_hlsl_or: {
     if (SemaRef.checkArgCount(TheCall, 2))
@@ -3147,6 +3175,65 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
   }
 }
 
+bool SemaHLSL::initResourceVarFromBinding(VarDecl *VD, unsigned SpaceNo,
+                                          unsigned RegisterNo, int32_t Range,
+                                          unsigned Index) {
+  InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
+  InitializationKind Kind = InitializationKind::CreateDirect(
+      VD->getLocation(), SourceLocation(), SourceLocation());
+
+  ASTContext &AST = SemaRef.getASTContext();
+  uint64_t UIntTySize = AST.getTypeSize(AST.UnsignedIntTy);
+  uint64_t IntTySize = AST.getTypeSize(AST.IntTy);
+  Expr *Args[] = {IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, SpaceNo),
+                                         AST.UnsignedIntTy, SourceLocation()),
+                  IntegerLiteral::Create(AST,
+                                         llvm::APInt(UIntTySize, RegisterNo),
+                                         AST.UnsignedIntTy, SourceLocation()),
+                  IntegerLiteral::Create(AST, llvm::APInt(IntTySize, Range),
+                                         AST.IntTy, SourceLocation()),
+                  IntegerLiteral::Create(AST, llvm::APInt(UIntTySize, Index),
+                                         AST.UnsignedIntTy, SourceLocation())};
+
+  InitializationSequence InitSeq(SemaRef, Entity, Kind, Args);
+  ExprResult Init = InitSeq.Perform(SemaRef, Entity, Kind, Args);
+
+  if (!Init.get())
+    return false;
+
+  VD->setInit(SemaRef.MaybeCreateExprWithCleanups(Init.get()));
+  VD->setInitStyle(VarDecl::CallInit);
+  SemaRef.CheckCompleteVariableDeclaration(VD);
+  return true;
+}
+
+// Returns true in the initialization has been handled;
+// Return false to let Clang handle the default initializaton.
+bool SemaHLSL::ActOnUninitializedVarDecl(VarDecl *VD) {
+  // Objects in the hlsl_constant address space are initialized
+  // externally, so don't synthesize an implicit initializer.
+  if (VD->getType().getAddressSpace() == LangAS::hlsl_constant)
+    return true;
+
+  // Initialize resources (explicit binding)
+  // NOTE: it would probably be best to do this for all resources at the end
+  // of the translation unit after implicit bindings are assigned.
+  if (!isResourceRecordTypeOrArrayOf(VD))
+    return false;
+
+  // FIXME: We currectly support only simple resources - no arrays of resources
+  // or resources in user defined structs).
+  if (!VD->getType()->isHLSLResourceRecord())
+    return false;
+
+  HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
+  if (!RBA)
+    return false;
+
+  return initResourceVarFromBinding(VD, RBA->getSpaceNumber(),
+                                    RBA->getSlotNumber(), 1, 0);
+}
+
 // Walks though the global variable declaration, collects all resource binding
 // requirements and adds them to Bindings
 void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) {
diff --git 
a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl 
b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
index 926a37c689517..73ddc12e78ef9 100644
--- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl
@@ -3,32 +3,85 @@
 
 // NOTE: SPIRV codegen for resource types is not yet implemented
 
-ByteAddressBuffer Buffer0: register(t0);
-RWByteAddressBuffer Buffer1: register(u1, space2);
-RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4);
+ByteAddressBuffer Buf1: register(t1, space2);
+RWByteAddressBuffer Buf2;
 
-// CHECK: "class.hlsl::ByteAddressBuffer" = type { target("dx.RawBuffer", i8, 
0, 0) }
-// CHECK: "class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", 
i8, 1, 0) }
-// CHECK: "class.hlsl::RasterizerOrderedByteAddressBuffer" = type { 
target("dx.RawBuffer", i8, 1, 1) }
+export void foo() {
+  RasterizerOrderedByteAddressBuffer Buf3;
+}
 
-// CHECK: @_ZL7Buffer0 = internal global %"class.hlsl::ByteAddressBuffer" 
poison, align 4
-// CHECK: @_ZL7Buffer1 = internal global %"class.hlsl::RWByteAddressBuffer" 
poison, align 4
-// CHECK: @_ZL7Buffer2 = internal global 
%"class.hlsl::RasterizerOrderedByteAddressBuffer" poison, align 4
+// CHECK: %"class.hlsl::ByteAddressBuffer" = type { target("dx.RawBuffer", i8, 
0, 0) }
+// CHECK: %"class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", 
i8, 1, 0) }
+// CHECK: %"class.hlsl::RasterizerOrderedByteAddressBuffer" = type { 
target("dx.RawBuffer", i8, 1, 1) }
 
-// CHECK; define internal void @_init_resource_Buffer0()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", i8, 0, 0) [[H]], ptr @_ZL7Buffer0, 
align 4
+// CHECK: @_ZL4Buf1 = internal global %"class.hlsl::ByteAddressBuffer" poison, 
align 4
+// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWByteAddressBuffer" 
poison, align 4
 
-// CHECK; define internal void @_init_resource_Buffer1()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 2, i32 1, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 0) [[H]], ptr @_ZL7Buffer1, 
align 4
+//
+// Buf1 initialization part 1 - constructor that creates handle from binding
+//
+// CHECK: define internal void @__cxx_global_var_init()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_ZN4hlsl17ByteAddressBufferC1Ejjij(ptr noundef 
nonnull align 4 dereferenceable(4) @_ZL4Buf1,
+// CHECK-SAME: i32 noundef 2, i32 noundef 1, i32 noundef 1, i32 noundef 0)
 
-// CHECK; define internal void @_init_resource_Buffer2()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 1, 1) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 1) [[H]], ptr @_ZL7Buffer2, 
align 4
+// CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC1Ejjij(ptr 
noundef nonnull align 4 dereferenceable(4) %this,
+// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef 
%range, i32 noundef %index)
+// CHECK: call void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr noundef nonnull 
align 4 dereferenceable(4) %this1, 
+// CHECK-SAME: i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3)
+
+//
+// Buf2 initialization part 1 - default constructor that initializes handle to 
poison
+//
+
+// CHECK: define internal void @__cxx_global_var_init.1()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_ZN4hlsl19RWByteAddressBufferC1Ev(ptr noundef 
nonnull align 4 dereferenceable(4) @_ZL4Buf2)
+
+// CHECK: define linkonce_odr void @_ZN4hlsl19RWByteAddressBufferC1Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK: call void @_ZN4hlsl19RWByteAddressBufferC2Ev(ptr noundef nonnull 
align 4 dereferenceable(4) %this1)
+
+//
+// Buf3 initialization part 1 - local variable with default constructor that 
initializes handle to poison
+//
+
+// CHECK: define void @_Z3foov() #2 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %Buf3 = alloca 
%"class.hlsl::RasterizerOrderedByteAddressBuffer", align 4
+// CHECK-NEXT: call void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %Buf3)
+
+// CHECK: define linkonce_odr void 
@_ZN4hlsl34RasterizerOrderedByteAddressBufferC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this)
+// CHECK: call void @_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %this1)
+
+//
+// Buf1 initialization part 2 - body of constructor that creates handle from 
binding
+//
+// CHECK: define linkonce_odr void @_ZN4hlsl17ByteAddressBufferC2Ejjij(ptr 
noundef nonnull align 4 dereferenceable(4) %this,
+// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef 
%range, i32 noundef %index)
+// CHECK-DXIL: %[[HANDLE:.*]] = call target("dx.RawBuffer", i8, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(
+// CHECK-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::ByteAddressBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.RawBuffer", i8, 0, 0) %[[HANDLE]], ptr 
%[[HANDLE_PTR]], align 4
+
+//
+// Buf2 initialization part 2 - body of default constructor that initializes 
handle to poison
+//
+// CHECK: define linkonce_odr void @_ZN4hlsl19RWByteAddressBufferC2Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWByteAddressBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store i8 poison, ptr %[[HANDLE_PTR]], align 4
+
+//
+// Buf3 initialization part 2 - body of default constructor that initializes 
handle to poison
+//
+// CHECK: define linkonce_odr void 
@_ZN4hlsl34RasterizerOrderedByteAddressBufferC2Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RasterizerOrderedByteAddressBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store i8 poison, ptr %[[HANDLE_PTR]], align 4
+
+//
+// Module initialization
+//
 
 // CHECK: define internal void 
@_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl()
-// CHECK: entry:
-// CHECK: call void @_init_resource__ZL7Buffer0()
-// CHECK: call void @_init_resource__ZL7Buffer1()
-// CHECK: call void @_init_resource__ZL7Buffer2()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__cxx_global_var_init()
+// CHECK-NEXT: call void @__cxx_global_var_init.1()
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl 
b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl
index 56c523f6bc8cf..c83a53897c045 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm 
-O3 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s 
| FileCheck %s
 
-// All referenced to an unused resource should be removed by optimizations.
+// All references to an unused resource should be removed by optimizations.
 RWBuffer<float> Buf : register(u5, space3);
 
 [shader("compute")]
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl 
b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
index 5324176a7b9bb..9bb5121bcf7e8 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
@@ -4,17 +4,81 @@
 
 // NOTE: SPIRV codegen for resource types is not yet implemented
 
-RWBuffer<float> Buf : register(u5, space3);
+RWBuffer<float> Buf1 : register(u5, space3);
+RWBuffer<double> Buf2;
+
+export void foo() {
+    RWBuffer<int> Buf3;
+}
 
 // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 
0, 0) }
-// CHECK: @_ZL3Buf = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: %"class.hlsl::RWBuffer.0" = type { target("dx.TypedBuffer", double, 
1, 0, 0) }
+// CHECK: %"class.hlsl::RWBuffer.1" = type { target("dx.TypedBuffer", i32, 1, 
0, 1) }
 
-// CHECK: define internal void @_init_resource__ZL3Buf()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, 
i32 1, i32 0, i1 false)
-// CHECK-DXIL: store target("dx.TypedBuffer", float, 1, 0, 0) [[H]], ptr 
@_ZL3Buf, align 4
+// CHECK: @_ZL4Buf1 = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWBuffer.0" poison, align 4
 
-// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %this)
+//
+// Buf1 initialization part 1 - constructor that creates handle from binding
+//
+// CHECK: define internal void @__cxx_global_var_init()
 // CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIfEC1Ejjij(ptr noundef nonnull 
align 4 dereferenceable(4) @_ZL4Buf1,
+// CHECK-SAME: i32 noundef 3, i32 noundef 5, i32 noundef 1, i32 noundef 0)
+
+// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC1Ejjij(ptr noundef 
nonnull align 4 dereferenceable(4) %this,
+// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef 
%range, i32 noundef %index)
+// CHECK: call void @_ZN4hlsl8RWBufferIfEC2Ejjij(
 
+//
+// Buf2 initialization part 1 - default constructor that initializes handle to 
poison
+//
+
+// CHECK: define internal void @__cxx_global_var_init.1() #0 {
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIdEC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) @_ZL4Buf2)
+
+// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIdEC1Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %this)
+// CHECK: call void @_ZN4hlsl8RWBufferIdEC2Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this1)
+
+//
+// Buf3 initialization part 1 - local variable with default constructor that 
initializes handle to poison
+//
+// CHECK: define void @_Z3foov()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %Buf3 = alloca %"class.hlsl::RWBuffer.1", align 4
+// CHECK-NEXT: call void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) %Buf3)
+
+// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC1Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %this)
+// CHECK: call void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this1)
+
+//
+// Buf1 initialization part 2 - body of constructor that creates handle from 
binding
+//
+// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ejjij(ptr noundef 
nonnull align 4 dereferenceable(4) %this,
+// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef 
%range, i32 noundef %index)
+// CHECK-DXIL: %[[HANDLE:.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) %[[HANDLE]], ptr 
%[[HANDLE_PTR]], align 4
+
+//
+// Buf2 initialization part 2 - body of default constructor that initializes 
handle to poison
+//
+// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIdEC2Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %this)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWBuffer.0", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.TypedBuffer", double, 1, 0, 0) poison, ptr 
%[[HANDLE_PTR]], align 4
+
+//
+// Buf3 initialization part 2 - body of default constructor that initializes 
handle to poison
+//
+// CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIiEC2Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %this)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWBuffer.1", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.TypedBuffer", i32, 1, 0, 1) poison, ptr 
%[[HANDLE_PTR]], align 4
+
+//
+// Module initialization
+//
 // CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl()
-// CHECK: call void @_init_resource__ZL3Buf()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__cxx_global_var_init()
+// CHECK-NEXT: call void @__cxx_global_var_init.1()
diff --git 
a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl 
b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
index 04534c5550252..da205816dd762 100644
--- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl
@@ -3,57 +3,88 @@
 
 // NOTE: SPIRV codegen for resource types is not yet implemented
 
-StructuredBuffer<float> Buf : register(t10);
-RWStructuredBuffer<float> Buf2 : register(u5, space1);
-AppendStructuredBuffer<float> Buf3 : register(u3);
-ConsumeStructuredBuffer<float> Buf4 : register(u4);
-RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2);
+StructuredBuffer<float> Buf1 : register(t10, space2);
+RWStructuredBuffer<float> Buf2;
+
+export void foo() {
+  AppendStructuredBuffer<float> Buf3;
+}
 
 // CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", 
float, 0, 0) }
 // CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", 
float, 1, 0) }
 // CHECK: %"class.hlsl::AppendStructuredBuffer" = type { 
target("dx.RawBuffer", float, 1, 0) }
-// CHECK: %"class.hlsl::ConsumeStructuredBuffer" = type { 
target("dx.RawBuffer", float, 1, 0) }
-// CHECK: %"class.hlsl::RasterizerOrderedStructuredBuffer" = type { 
target("dx.RawBuffer", float, 1, 1) }
 
-// CHECK: @_ZL3Buf = internal global %"class.hlsl::StructuredBuffer" poison, 
align 4
+// CHECK: @_ZL4Buf1 = internal global %"class.hlsl::StructuredBuffer" poison, 
align 4
 // CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWStructuredBuffer" 
poison, align 4
-// CHECK: @_ZL4Buf3 = internal global %"class.hlsl::AppendStructuredBuffer" 
poison, align 4
-// CHECK: @_ZL4Buf4 = internal global %"class.hlsl::ConsumeStructuredBuffer" 
poison, align 4
-// CHECK: @_ZL4Buf5 = internal global 
%"class.hlsl::RasterizerOrderedStructuredBuffer" poison, align 4
 
-// CHECK: define internal void @_init_resource__ZL3Buf()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 
1, i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", float, 0, 0) [[H]], ptr @_ZL3Buf, 
align 4
+//
+// Buf1 initialization part 1 - constructor that creates handle from binding
+//
+
+// CHECK: define internal void @__cxx_global_var_init()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr noundef 
nonnull align 4 dereferenceable(4) @_ZL4Buf1, i32 noundef 2, i32 noundef 10, 
i32 noundef 1, i32 noundef 0)
 
-// CHECK: define internal void @_init_resource__ZL4Buf2()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf2, 
align 4
+// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC1Ejjij(ptr 
noundef nonnull align 4 dereferenceable(4) %this, 
+// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef 
%range, i32 noundef %index)
+// CHECK: call void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr noundef nonnull 
align 4 dereferenceable(4) %this1, 
+// CHECK-SAME: i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3)
 
-// CHECK: define internal void @_init_resource__ZL4Buf3()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf3, 
align 4
+//
+// Buf2 initialization part 1 - default constructor that initializes handle to 
poison
+//
+
+// CHECK: define internal void @__cxx_global_var_init.1()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @_ZN4hlsl18RWStructuredBufferIfEC1Ev(ptr noundef 
nonnull align 4 dereferenceable(4) @_ZL4Buf2)
 
-// CHECK: define internal void @_init_resource__ZL4Buf4()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf4, 
align 4
+// CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC1Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK: call void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr noundef nonnull 
align 4 dereferenceable(4) %this1)
 
-// CHECK: define internal void @_init_resource__ZL4Buf5()
-// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 1) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, 
i32 0, i1 false)
-// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 1) [[H]], ptr @_ZL4Buf5, 
align 4
+//
+// Buf3 initialization part 1 - local variable with default constructor that 
initializes handle to poison
+//
 
-// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %this)
+// CHECK: define void @_Z3foov()
 // CHECK-NEXT: entry:
+// CHECK-NEXT: %Buf3 = alloca %"class.hlsl::AppendStructuredBuffer", align 4
+// CHECK-NEXT: call void @_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %Buf3)
+
+// CHECK: define linkonce_odr void 
@_ZN4hlsl22AppendStructuredBufferIfEC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this)
+// CHECK: call void @_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef 
nonnull align 4 dereferenceable(4) %this1)
+
+//
+// Buf1 initialization part 2 - body of constructor that creates handle from 
binding
+//
+
+// CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ejjij(ptr 
noundef nonnull align 4 dereferenceable(4) %this,
+// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %registerNo, i32 noundef 
%range, i32 noundef %index)
+// CHECK-DXIL: %[[HANDLE:.*]] = call target("dx.RawBuffer", float, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(
+// CHECK-SAME: i32 %0, i32 %1, i32 %2, i32 %3, i1 false)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::StructuredBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.RawBuffer", float, 0, 0) %4, ptr %[[HANDLE_PTR]], 
align 4
+
+//
+// Buf2 initialization part 2 - body of default constructor that initializes 
handle to poison
+//
+
 // CHECK: define linkonce_odr void @_ZN4hlsl18RWStructuredBufferIfEC2Ev(ptr 
noundef nonnull align 4 dereferenceable(4) %this)
-// CHECK-NEXT: entry:
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWStructuredBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.RawBuffer", float, 1, 0) poison, ptr 
%[[HANDLE_PTR]], align 4
+
+//
+// Buf3 initialization part 2 - body of default constructor that initializes 
handle to poison
+//
+
 // CHECK: define linkonce_odr void 
@_ZN4hlsl22AppendStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this)
-// CHECK-NEXT: entry:
-// CHECK: define linkonce_odr void 
@_ZN4hlsl23ConsumeStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this)
-// CHECK: define linkonce_odr void 
@_ZN4hlsl33RasterizerOrderedStructuredBufferIfEC2Ev(ptr noundef nonnull align 4 
dereferenceable(4) %this)
-// CHECK-NEXT: entry:
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::AppendStructuredBuffer", ptr %this1, i32 0, i32 0
+// CHECK: store target("dx.RawBuffer", float, 1, 0) poison, ptr 
%[[HANDLE_PTR]], align 4
+
+//
+// Module initialization
+//
 
 // CHECK: define internal void 
@_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl()
-// CHECK: call void @_init_resource__ZL3Buf()
-// CHECK: call void @_init_resource__ZL4Buf2()
-// CHECK: call void @_init_resource__ZL4Buf3()
-// CHECK: call void @_init_resource__ZL4Buf4()
-// CHECK: call void @_init_resource__ZL4Buf5()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call void @__cxx_global_var_init()
+// CHECK-NEXT: call void @__cxx_global_var_init.1()
diff --git a/clang/test/CodeGenHLSL/resource-bindings.hlsl 
b/clang/test/CodeGenHLSL/resource-bindings.hlsl
index 3342fb55a59a4..3a7b9fc3e4952 100644
--- a/clang/test/CodeGenHLSL/resource-bindings.hlsl
+++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl
@@ -1,34 +1,46 @@
 // RUN: %clang_cc1 -triple dxil--shadermodel6.6-compute -x hlsl 
-finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
 
-// CHECK: define internal void @_init_resource__ZL4U0S0()
-// CHECK: [[H:%.*]] = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, 
i32 1, i32 0, i1 false)
-// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) [[H]], ptr 
@_ZL4U0S0, align 4
+// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x 
float>, 1, 0, 0) }
+// CHECK: %"class.hlsl::RWBuffer.0" = type { target("dx.TypedBuffer", float, 
1, 0, 0) }
+// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", i32, 
0, 0) }
+// CHECK: %"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", 
%struct.S, 1, 0) }
+
+// CHECK: @_ZL4U0S0 = internal global %"class.hlsl::RWBuffer" poison, align 4
+// CHECK: @_ZL4U5S3 = internal global %"class.hlsl::RWBuffer.0" poison, align 4
+// CHECK: @_ZL4T2S2 = internal global %"class.hlsl::StructuredBuffer" poison, 
align 4
+// CHECK: @_ZL4T3S0 = internal global %"class.hlsl::RWStructuredBuffer" 
poison, align 4
+
+// CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+// CHECK-SAME: 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(
+// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 
%{{[0-9]+}}, i1 false)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWBuffer", ptr %this{{[0-9]*}}, i32 0, i32 0
+// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %[[HANDLE]], 
ptr %[[HANDLE_PTR]], align 4
 RWBuffer<float4> U0S0 : register(u0);
 
-// CHECK: define internal void @_init_resource__ZL4U5S3()
-// CHECK: [[H:%.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, 
i32 1, i32 0, i1 false)
-// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) [[H]], ptr @_ZL4U5S3, 
align 4
+// CHECK: %[[HANDLE:.*]] = call target("dx.TypedBuffer", float, 1, 0, 0)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(
+// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 
%{{[0-9]+}}, i1 false)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWBuffer.0", ptr %this{{[0-9]*}}, i32 0, i32 0
+// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) %[[HANDLE]], ptr 
%[[HANDLE_PTR]], align 4
 RWBuffer<float> U5S3 : register(u5, space3);
 
-// CHECK: define internal void @_init_resource__ZL4T2S2()
-// CHECK: [[H:%.*]] = call target("dx.RawBuffer", i32, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, 
i32 0, i1 false)
-// CHECK: store target("dx.RawBuffer", i32, 0, 0) [[H]], ptr @_ZL4T2S2, align 4
+// CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", i32, 0, 0)
+// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(
+// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 
%{{[0-9]+}}, i1 false)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::StructuredBuffer", ptr %this{{[0-9]*}}, i32 0, i32 0
+// CHECK: store target("dx.RawBuffer", i32, 0, 0) %[[HANDLE]], ptr 
%[[HANDLE_PTR]], align 4
 StructuredBuffer<int> T2S2 : register(t2, space2);
 struct S {
   float4 f;
   int i;
 };
 
-// CHECK: define internal void @_init_resource__ZL4T3S0()
-// CHECK: [[H:%.*]] = call target("dx.RawBuffer", %struct.S, 0, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 
3, i32 1, i32 0, i1 false)
-// CHECK: store target("dx.RawBuffer", %struct.S, 0, 0) [[H]], ptr @_ZL4T3S0, 
align 4
-StructuredBuffer<S> T3S0 : register(t3);
-
-// CHECK: define void @main()
-// CHECK: call void @_init_resource__ZL4U0S0()
-// CHECK: call void @_init_resource__ZL4U5S3()
-// CHECK: call void @_init_resource__ZL4T2S2()
-// CHECK: call void @_init_resource__ZL4T3S0()
+// CHECK: %[[HANDLE:.*]] = call target("dx.RawBuffer", %struct.S, 1, 0)
+// CHECK-SAME: 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_1_0t(
+// CHECK-SAME: i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 %{{[0-9]+}}, i32 
%{{[0-9]+}}, i1 false)
+// CHECK: %[[HANDLE_PTR:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWStructuredBuffer", ptr %this{{[0-9]*}}, i32 0, i32 0
+// CHECK: store target("dx.RawBuffer", %struct.S, 1, 0) %[[HANDLE]], ptr 
%[[HANDLE_PTR]], align 4
+RWStructuredBuffer<S> T3S0 : register(u3);
 
 [numthreads(4,1,1)]
 void main() {}

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to