Explorar o código

Fix static data member const issue. (#668)

Fix static data member const issue. For now we are setting static data member to have internal linkage simply because current module passes does not remove global variable for static data member unless it's an internal linkage (LowerStaticGlobalIntoAlloca), and we do not allow instructions using global variables. This can be fixed in the future if we want to keep static data member to maintain external linkage and create an extra pass to handle this.
Young Kim %!s(int64=8) %!d(string=hai) anos
pai
achega
32af2dad66

+ 6 - 2
tools/clang/lib/AST/Decl.cpp

@@ -951,9 +951,13 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
 
   // Static data members.
   } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+    // HLSL Change: Make static data member internal linkage. This is to avoid confusion between global constant buffer
+    if (VD->getStorageClass() == StorageClass::SC_Static)
+      LV.setLinkage(Linkage::InternalLinkage);
+
     if (const VarTemplateSpecializationDecl *spec
-        = dyn_cast<VarTemplateSpecializationDecl>(VD))
-      mergeTemplateLV(LV, spec, computation);
+      = dyn_cast<VarTemplateSpecializationDecl>(VD))
+    mergeTemplateLV(LV, spec, computation);
 
     // Modify the variable's linkage by its type, but ignore the
     // type's visibility unless it's a definition.

+ 1 - 1
tools/clang/lib/CodeGen/CodeGenModule.cpp

@@ -2119,7 +2119,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
       if (getLangOpts().CPlusPlus && !NeedsGlobalDtor)
         DelayedCXXInitPosition.erase(D);
       // HLSL Change Begins.
-      if (getLangOpts().HLSL && D->isExternallyVisible()) {
+      if (getLangOpts().HLSL && D->isExternallyVisible() && !D->isStaticDataMember()) {
         // For global constant with init, the init will be ignored.
         Init = EmitNullConstant(D->getType());
         unsigned DiagID = Diags.getCustomDiagID(

+ 29 - 1
tools/clang/lib/Parse/ParseDecl.cpp

@@ -2177,10 +2177,38 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
   // HLSL Change Starts: change global variables that will be in constant buffer to be constant by default 
   // Global variables that are groupshared, static, or typedef 
   // will not be part of constant buffer and therefore should not be const by default.
+
+  // global variable can be inside a global structure as a static member.
+  // Check if the global is a static member and skip global const pass.
+  bool CheckGlobalConst = true;
+  if (NestedNameSpecifier *nameSpecifier = D.getCXXScopeSpec().getScopeRep()) {
+    if (nameSpecifier->getKind() == NestedNameSpecifier::SpecifierKind::TypeSpec) {
+      const Type *type = D.getCXXScopeSpec().getScopeRep()->getAsType();
+      if (type->getTypeClass() == Type::TypeClass::Record) {
+        CXXRecordDecl *RD = type->getAsCXXRecordDecl();
+        for (auto it = RD->decls_begin(), itEnd = RD->decls_end(); it != itEnd; ++it) {
+          if (const VarDecl *VD = dyn_cast<VarDecl>(*it)) {
+            StringRef fieldName = VD->getName();
+            std::string declName = Actions.GetNameForDeclarator(D).getAsString();
+            if (fieldName.equals(declName) && VD->getStorageClass() == StorageClass::SC_Static) {
+              CheckGlobalConst = false;
+              const char *prevSpec = nullptr;
+              unsigned int DiagID;
+              DS.SetStorageClassSpec(
+                  Actions, DeclSpec::SCS::SCS_static,
+                  D.getDeclSpec().getLocStart(), prevSpec, DiagID,
+                  Actions.getASTContext().getPrintingPolicy());
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
   if (getLangOpts().HLSL && !D.isFunctionDeclarator() &&
       D.getContext() == Declarator::TheContext::FileContext &&
       DS.getStorageClassSpec() != DeclSpec::SCS::SCS_static &&
-      DS.getStorageClassSpec() != DeclSpec::SCS::SCS_typedef
+      DS.getStorageClassSpec() != DeclSpec::SCS::SCS_typedef && CheckGlobalConst
       ) {
 
     // Check whether or not there is a 'groupshared' attribute

+ 8 - 2
tools/clang/lib/Sema/SemaDecl.cpp

@@ -5781,7 +5781,11 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       case SC_None:
         break;
       case SC_Static:
-        Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+        if (!getLangOpts().HLSL) // HLSL Change: We had to set SC_Static for
+                                 // static data member to distinguish it from
+                                 // global constant variable.
+                                 // So we ignore this warning.
+          Diag(D.getDeclSpec().getStorageClassSpecLoc(),
              diag::err_static_out_of_line)
           << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
         break;
@@ -7563,8 +7567,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
       NewFD->setImplicitlyInline();
     }
 
+    // HLSL Change: We had to set SC_Static for static data member to
+    // distinguish it from global constant variable.
     if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) &&
-        !CurContext->isRecord()) {
+        !CurContext->isRecord() && !getLangOpts().HLSL) {
       // C++ [class.static]p1:
       //   A data or function member of a class may be declared static
       //   in a class definition, in which case it is a static member of

+ 16 - 0
tools/clang/test/CodeGenHLSL/staticGlobals5.hlsl

@@ -0,0 +1,16 @@
+// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+
+// CHECK: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 2.500000e-01)
+// CHECK-NOT: @dx.op.cbufferLoadLegacy
+
+struct S
+{
+    static float4 data;
+};
+
+float4 S::data = 0.25f;
+
+float4 main() : SV_TARGET
+{
+    return S::data;
+}

+ 5 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -736,6 +736,7 @@ public:
   TEST_METHOD(CodeGenStaticGlobals2)
   TEST_METHOD(CodeGenStaticGlobals3)
   TEST_METHOD(CodeGenStaticGlobals4)
+  TEST_METHOD(CodeGenStaticGlobals5)
   TEST_METHOD(CodeGenStaticMatrix)
   TEST_METHOD(CodeGenStaticResource)
   TEST_METHOD(CodeGenStaticResource2)
@@ -4103,6 +4104,10 @@ TEST_F(CompilerTest, CodeGenStaticGlobals4) {
   CodeGenTest(L"..\\CodeGenHLSL\\staticGlobals4.hlsl");
 }
 
+TEST_F(CompilerTest, CodeGenStaticGlobals5) {
+  CodeGenTestCheck(L"..\\CodeGenHLSL\\staticGlobals5.hlsl");
+}
+
 TEST_F(CompilerTest, CodeGenStaticMatrix) {
   CodeGenTestCheck(L"..\\CodeGenHLSL\\static_matrix.hlsl");
 }