python3kgae updated this revision to Diff 450978.
python3kgae added a comment.

Add more test and comment.
Also use getTargetAddressSpace.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130131/new/

https://reviews.llvm.org/D130131

Files:
  clang/include/clang/Basic/AddressSpaces.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/Basic/Targets/AMDGPU.cpp
  clang/lib/Basic/Targets/DirectX.h
  clang/lib/Basic/Targets/NVPTX.h
  clang/lib/Basic/Targets/SPIR.h
  clang/lib/Basic/Targets/TCE.h
  clang/lib/Basic/Targets/X86.h
  clang/lib/CodeGen/CGDecl.cpp
  clang/lib/CodeGen/CGHLSLRuntime.cpp
  clang/lib/CodeGen/CGHLSLRuntime.h
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/test/CodeGenHLSL/cbuf.hlsl
  clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
  clang/test/CodeGenHLSL/nest_cbuf.hlsl
  clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl

Index: clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
===================================================================
--- /dev/null
+++ clang/test/CodeGenHLSL/static_global_and_function_in_cb.hlsl
@@ -0,0 +1,18 @@
+// RUN: %clang_dxc -Tlib_6_7 -fcgl  -Fo - %s | FileCheck %s
+
+// CHECK-DAG: @[[CB:.+]] = external addrspace(4) constant { float }
+
+cbuffer A {
+  namespace n0 {
+    float a;
+  }
+  // CHECK-DAG:@b = internal global float 3.000000e+00, align 4
+  static float b = 3;
+  // CHECK:load float, ptr addrspacecast (ptr addrspace(4) @[[CB]] to ptr), align 4
+  // CHECK:load float, ptr @b, align 4
+  float foo() { return n0::a + b; }
+}
+
+float bar() {
+  return foo();
+}
Index: clang/test/CodeGenHLSL/nest_cbuf.hlsl
===================================================================
--- /dev/null
+++ clang/test/CodeGenHLSL/nest_cbuf.hlsl
@@ -0,0 +1,20 @@
+// RUN: %clang_dxc -Tlib_6_7 -fcgl  -Fo - %s | FileCheck %s
+
+// CHECK: @[[CB:.+]] = external addrspace(4) constant { float, i32, double }
+cbuffer A {
+  float a;
+  double b;
+  // CHECK: @[[TB:.+]] = external addrspace(5) constant { float, i32, double }
+  tbuffer A : register(t2, space1) {
+    float c;
+    double d;
+  }
+}
+
+float foo() {
+// CHECK: load float, ptr addrspacecast (ptr addrspace(4) @[[CB]] to ptr), align 4
+// CHECK: load double, ptr addrspacecast (ptr addrspace(4) getelementptr inbounds ({ float, i32, double }, ptr addrspace(4) @[[CB]], i32 0, i32 2) to ptr), align 8
+// CHECK: load float, ptr addrspacecast (ptr addrspace(5) @[[TB]] to ptr), align 4
+// CHECK: load double, ptr addrspacecast (ptr addrspace(5) getelementptr inbounds ({ float, i32, double }, ptr addrspace(5) @[[TB]], i32 0, i32 2) to ptr), align 8
+  return a + b + c*d;
+}
Index: clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
===================================================================
--- /dev/null
+++ clang/test/CodeGenHLSL/cbuf_in_namespace.hlsl
@@ -0,0 +1,18 @@
+// RUN: %clang_dxc -Tlib_6_7 -fcgl  -Fo - %s | FileCheck %s
+
+// Make sure namespace inside cbuffer  works.
+// CHECK: @[[CB:.+]] = external addrspace(4) constant { float, float }
+cbuffer A {
+  namespace n0 {
+    float a;
+  }
+  namespace n1 {
+    float b;
+  }
+}
+
+float foo() {
+// CHECK: load float, ptr addrspacecast (ptr addrspace(4) @[[CB]] to ptr), align 4
+// CHECK: load float, ptr addrspacecast (ptr addrspace(4) getelementptr inbounds ({ float, float }, ptr addrspace(4) @[[CB]], i32 0, i32 1) to ptr), align 4
+  return n0::a + n1::b;
+}
Index: clang/test/CodeGenHLSL/cbuf.hlsl
===================================================================
--- /dev/null
+++ clang/test/CodeGenHLSL/cbuf.hlsl
@@ -0,0 +1,21 @@
+// RUN: %clang_dxc -Tlib_6_7 -fcgl  -Fo - %s | FileCheck %s
+
+// CHECK: @[[CB:.+]] = external addrspace(4) constant { float, i32, double }
+cbuffer A : register(b0, space1) {
+  float a;
+  double b;
+}
+
+// CHECK: @[[TB:.+]] = external addrspace(5) constant { float, i32, double }
+tbuffer A : register(t2, space1) {
+  float c;
+  double d;
+}
+
+float foo() {
+// CHECK: load float, ptr addrspacecast (ptr addrspace(4) @[[CB]] to ptr), align 4
+// CHECK: load double, ptr addrspacecast (ptr addrspace(4) getelementptr inbounds ({ float, i32, double }, ptr addrspace(4) @[[CB]], i32 0, i32 2) to ptr), align 8
+// CHECK: load float, ptr addrspacecast (ptr addrspace(5) @[[TB]] to ptr), align 4
+// CHECK: load double, ptr addrspacecast (ptr addrspace(5) getelementptr inbounds ({ float, i32, double }, ptr addrspace(5) @[[TB]], i32 0, i32 2) to ptr), align 8
+  return a + b + c*d;
+}
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -6370,6 +6370,10 @@
         DI->EmitAndRetainType(getContext().getEnumType(cast<EnumDecl>(D)));
     break;
 
+  case Decl::HLSLBuffer:
+    getHLSLRuntime().addBuffer(cast<HLSLBufferDecl>(D));
+    break;
+
   default:
     // Make sure we handled everything we should, every other kind is a
     // non-top-level decl.  FIXME: Would be nice to have an isTopLevelDeclKind
Index: clang/lib/CodeGen/CGHLSLRuntime.h
===================================================================
--- clang/lib/CodeGen/CGHLSLRuntime.h
+++ clang/lib/CodeGen/CGHLSLRuntime.h
@@ -17,15 +17,25 @@
 
 #include "clang/Basic/HLSLRuntime.h"
 
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <vector>
+
 namespace llvm {
 class Value;
 class GlobalVariable;
 class Function;
+class StructType;
 } // namespace llvm
+
 namespace clang {
+class HLSLBufferDecl;
 class CallExpr;
 class Type;
 class VarDecl;
+class DeclContext;
 
 class FunctionDecl;
 
@@ -34,6 +44,19 @@
 class CodeGenModule;
 
 class CGHLSLRuntime {
+public:
+  struct Buffer {
+    Buffer(HLSLBufferDecl *D);
+    llvm::StringRef Name;
+    // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
+    bool IsCBuffer;
+    llvm::Optional<unsigned> Reg;
+    unsigned Space;
+    // Global variable and offset for each constant.
+    std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
+    llvm::StructType *LayoutStruct = nullptr;
+  };
+
 protected:
   CodeGenModule &CGM;
   uint32_t ResourceCounters[static_cast<uint32_t>(
@@ -45,9 +68,15 @@
 
   void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
 
+  void addBuffer(HLSLBufferDecl *D);
   void finishCodeGen();
 
   void setHLSLFunctionAttributes(llvm::Function *, const FunctionDecl *);
+
+private:
+  void addConstant(VarDecl *D, Buffer &CB);
+  void addBufferDecls(DeclContext *DC, Buffer &CB);
+  llvm::SmallVector<Buffer> Buffers;
 };
 
 } // namespace CodeGen
Index: clang/lib/CodeGen/CGHLSLRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -13,7 +13,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "CGHLSLRuntime.h"
+#include "CGDebugInfo.h"
 #include "CodeGenModule.h"
+
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
@@ -24,6 +26,7 @@
 using namespace llvm;
 
 namespace {
+
 void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
   // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
   // Assume ValVersionStr is legal here.
@@ -43,13 +46,184 @@
   StringRef DxilValKey = "dx.valver";
   M.addModuleFlag(llvm::Module::ModFlagBehavior::AppendUnique, DxilValKey, Val);
 }
+
+// cbuffer will be translated into global variable in special address space.
+// If translate into C,
+// cbuffer A {
+//   float a;
+//   float b;
+// }
+// float foo() { return a + b; }
+//
+// will be translated into
+//
+// struct A {
+//   float a;
+//   float b;
+// } cbuffer_A __attribute__((address_space(4)));
+// float foo() { return cbuffer_A.a + cbuffer_A.b; }
+//
+// layoutBuffer will create the struct A type.
+// replaceBuffer will replace use of global variable a and b with cbuffer_A.a
+// and cbuffer_A.b.
+//
+void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
+  if (Buf.Constants.empty())
+    return;
+
+  // FIXME: support legacy cbuffer layout.
+  auto &Ctx = Buf.Constants[0].first->getContext();
+  std::vector<llvm::Type *> EltTys;
+  uint64_t Offset = 0;
+  for (auto &Const : Buf.Constants) {
+    auto *GV = Const.first;
+    Const.second = EltTys.size();
+    auto *Ty = GV->getValueType();
+    auto Align = DL.getPrefTypeAlign(Ty);
+    if (uint64_t PaddingSize = (Offset % Align.value())) {
+      // Not aligned.
+      // Adding padding.
+      auto *PaddingTy = IntegerType::get(Ctx, 8 * PaddingSize);
+      EltTys.emplace_back(PaddingTy);
+      Offset += PaddingSize;
+    }
+    // Save Index for Ty into Const.second.
+    Const.second = EltTys.size();
+    EltTys.emplace_back(Ty);
+
+    Offset += DL.getTypeAllocSize(Ty);
+  }
+  Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+}
+
+GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf,
+                              const unsigned AddressSpace) {
+  // Create global variable for CB.
+  GlobalVariable *CBGV =
+      new GlobalVariable(Buf.LayoutStruct, /*isConstant*/ true,
+                         GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
+                         Buf.Name + (Buf.IsCBuffer ? ".cb." : ".tb."),
+                         GlobalValue::NotThreadLocal, AddressSpace);
+
+  IRBuilder<> B(CBGV->getContext());
+  Value *ZeroIdx = B.getInt32(0);
+  // Replace Const use with CB use.
+  for (auto &Const : Buf.Constants) {
+    auto *EltTy = Buf.LayoutStruct->getElementType(Const.second);
+    auto *GV = Const.first;
+    unsigned Offset = Const.second;
+
+    Value *GEP =
+        B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
+
+    auto *GVTy = GV->getValueType();
+    assert(EltTy == GVTy && "constant type mismatch");
+
+    // Cast address space.
+    GEP = B.CreateAddrSpaceCast(GEP, GVTy->getPointerTo());
+    // Replace.
+    GV->replaceAllUsesWith(GEP);
+    // Erase GV.
+    GV->removeDeadConstantUsers();
+    GV->eraseFromParent();
+  }
+  return CBGV;
+}
+
+void addResourceBinding(GlobalVariable *GV, CGHLSLRuntime::Buffer &CB) {
+  // FIXME: add resource binding to GV.
+}
+
 } // namespace
 
+void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
+  if (D->getStorageClass() == SC_Static) {
+    // For static inside cbuffer, take as global static.
+    // Don't add to cbuffer.
+    CGM.EmitGlobal(D);
+    return;
+  }
+
+  auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
+  // Add debug info for constVal.
+  if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
+    if (CGM.getCodeGenOpts().getDebugInfo() >=
+        codegenoptions::DebugInfoKind::LimitedDebugInfo)
+      DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
+
+  // FIXME: support packoffset.
+  uint32_t Offset = 0;
+  bool HasUserOffset = false;
+
+  unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
+  CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+}
+
+void CGHLSLRuntime::addBufferDecls(DeclContext *DC, Buffer &CB) {
+  for (Decl *it : DC->decls()) {
+    if (VarDecl *ConstDecl = dyn_cast<VarDecl>(it)) {
+      addConstant(ConstDecl, CB);
+    } else if (isa<EmptyDecl>(*it)) {
+      // Nothing to do for this declaration.
+    } else if (isa<CXXRecordDecl>(it)) {
+      // Nothing to do for this declaration.
+    } else if (isa<FunctionDecl>(it)) {
+      // A function within an cbuffer is effectively a top-level function,
+      // as it only refers to globally scoped declarations.
+      CGM.EmitTopLevelDecl(it);
+    } else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(it)) {
+      addBufferDecls(ND, CB);
+    } else {
+      HLSLBufferDecl *Inner = dyn_cast<HLSLBufferDecl>(it);
+      if (!Inner) {
+        // FIXME: add test after more Resource Type like Texture2D is supported.
+        DiagnosticsEngine &Diags = CGM.getDiags();
+        unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+                                                "invalid decl inside cbuffer");
+        Diags.Report(it->getLocation(), DiagID);
+        return;
+      }
+      addBuffer(Inner);
+    }
+  }
+}
+
+void CGHLSLRuntime::addBuffer(HLSLBufferDecl *D) {
+  Buffers.emplace_back(Buffer(D));
+  addBufferDecls(D, Buffers.back());
+}
+
 void CGHLSLRuntime::finishCodeGen() {
   auto &TargetOpts = CGM.getTarget().getTargetOpts();
 
   llvm::Module &M = CGM.getModule();
   addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
+  auto &DL = M.getDataLayout();
+  auto &ASMap = CGM.getTarget().getAddressSpaceMap();
+  const unsigned CBufferAddressSpace =
+      CGM.getContext().getTargetAddressSpace(LangAS::hlsl_cbuffer);
+  const unsigned TBufferAddressSpace =
+      CGM.getContext().getTargetAddressSpace(LangAS::hlsl_tbuffer);
+
+  for (auto &Buf : Buffers) {
+    layoutBuffer(Buf, DL);
+    const unsigned AddressSapce =
+        Buf.IsCBuffer ? CBufferAddressSpace : TBufferAddressSpace;
+    GlobalVariable *GV = replaceBuffer(Buf, AddressSapce);
+    M.getGlobalList().push_back(GV);
+    addResourceBinding(GV, Buf);
+  }
+}
+
+CGHLSLRuntime::Buffer::Buffer(HLSLBufferDecl *D) {
+  Name = D->getName();
+  IsCBuffer = D->isCBuffer();
+  if (auto *Binding = D->getAttr<HLSLResourceBindingAttr>()) {
+    Reg = Binding->getID();
+    Space = Binding->getSpace();
+  } else {
+    Space = 0;
+  }
 }
 
 void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -128,6 +128,7 @@
   case Decl::Concept:
   case Decl::LifetimeExtendedTemporary:
   case Decl::RequiresExprBody:
+  case Decl::HLSLBuffer:
     // None of these decls require codegen support.
     return;
 
Index: clang/lib/Basic/Targets/X86.h
===================================================================
--- clang/lib/Basic/Targets/X86.h
+++ clang/lib/Basic/Targets/X86.h
@@ -43,7 +43,9 @@
     0,   // sycl_private
     270, // ptr32_sptr
     271, // ptr32_uptr
-    272  // ptr64
+    272, // ptr64
+    0,   // hlsl_cbuffer
+    0,   // hlsl_tbuffer
 };
 
 // X86 target abstract base class; x86-32 and x86-64 are very close, so
Index: clang/lib/Basic/Targets/TCE.h
===================================================================
--- clang/lib/Basic/Targets/TCE.h
+++ clang/lib/Basic/Targets/TCE.h
@@ -50,6 +50,8 @@
     0, // ptr32_sptr
     0, // ptr32_uptr
     0, // ptr64
+    0, // hlsl_cbuffer
+    0, // hlsl_tbuffer
 };
 
 class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
Index: clang/lib/Basic/Targets/SPIR.h
===================================================================
--- clang/lib/Basic/Targets/SPIR.h
+++ clang/lib/Basic/Targets/SPIR.h
@@ -42,7 +42,9 @@
     0, // sycl_private
     0, // ptr32_sptr
     0, // ptr32_uptr
-    0  // ptr64
+    0, // ptr64
+    0, // hlsl_cbuffer
+    0, // hlsl_tbuffer
 };
 
 // Used by both the SPIR and SPIR-V targets.
@@ -71,7 +73,9 @@
     0, // sycl_private
     0, // ptr32_sptr
     0, // ptr32_uptr
-    0  // ptr64
+    0, // ptr64
+    0, // hlsl_cbuffer
+    0, // hlsl_tbuffer
 };
 
 // Base class for SPIR and SPIR-V target info.
Index: clang/lib/Basic/Targets/NVPTX.h
===================================================================
--- clang/lib/Basic/Targets/NVPTX.h
+++ clang/lib/Basic/Targets/NVPTX.h
@@ -42,7 +42,9 @@
     0, // sycl_private
     0, // ptr32_sptr
     0, // ptr32_uptr
-    0  // ptr64
+    0, // ptr64
+    0, // hlsl_cbuffer
+    0, // hlsl_tbuffer
 };
 
 /// The DWARF address class. Taken from
Index: clang/lib/Basic/Targets/DirectX.h
===================================================================
--- clang/lib/Basic/Targets/DirectX.h
+++ clang/lib/Basic/Targets/DirectX.h
@@ -40,7 +40,9 @@
     0, // sycl_private
     0, // ptr32_sptr
     0, // ptr32_uptr
-    0  // ptr64
+    0, // ptr64
+    4, // hlsl_cbuffer
+    5, // hlsl_tbuffer
 };
 
 class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
Index: clang/lib/Basic/Targets/AMDGPU.cpp
===================================================================
--- clang/lib/Basic/Targets/AMDGPU.cpp
+++ clang/lib/Basic/Targets/AMDGPU.cpp
@@ -56,7 +56,9 @@
     Private,  // sycl_private
     Generic,  // ptr32_sptr
     Generic,  // ptr32_uptr
-    Generic   // ptr64
+    Generic,  // ptr64
+    0,        // hlsl_cbuffer
+    0,        // hlsl_tbuffer
 };
 
 const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
@@ -79,7 +81,9 @@
     Generic,  // sycl_private
     Generic,  // ptr32_sptr
     Generic,  // ptr32_uptr
-    Generic   // ptr64
+    Generic,  // ptr64
+    0,        // hlsl_cbuffer
+    0,        // hlsl_tbuffer
 
 };
 } // namespace targets
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -948,7 +948,9 @@
         0,  // sycl_private
         10, // ptr32_sptr
         11, // ptr32_uptr
-        12  // ptr64
+        12, // ptr64
+        13, // hlsl_cbuffer
+        14, // hlsl_tbuffer
     };
     return &FakeAddrSpaceMap;
   } else {
Index: clang/include/clang/Basic/AddressSpaces.h
===================================================================
--- clang/include/clang/Basic/AddressSpaces.h
+++ clang/include/clang/Basic/AddressSpaces.h
@@ -56,6 +56,10 @@
   ptr32_uptr,
   ptr64,
 
+  // HLSL specific address spaces.
+  hlsl_cbuffer,
+  hlsl_tbuffer,
+
   // This denotes the count of language-specific address spaces and also
   // the offset added to the target-specific address spaces, which are usually
   // specified by address space attributes __attribute__(address_space(n))).
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to