Clean up HLSL constructor output

Split generating HLSL struct constructors from generating built-in
type constructors, as these didn't have much in common. Struct
constructors are now only generated when they are needed, as opposed
to before, when they were generated on any use of a struct.

This changes built-in constructor naming to include "_ctor" and gets
rid of having special built-in type names just for constructors.

This will make it easier to do changes to constructor output, for
example to add constructors for structs in std140 layout. This might
be needed to implement SSBOs efficiently.

This includes one bug fix for writing out struct declarations for
varyings.

Also improves const-correctness of accessing structs through TType
in general.

BUG=angleproject:2218
TEST=angle_unittests, angle_end2end_tests

Change-Id: If865fb56f86486b9c4a2c31e016ea16427f4a5fa
Reviewed-on: https://chromium-review.googlesource.com/753883
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/InitializeVariables.cpp b/src/compiler/translator/InitializeVariables.cpp
index 61c02c4..f90e06f 100644
--- a/src/compiler/translator/InitializeVariables.cpp
+++ b/src/compiler/translator/InitializeVariables.cpp
@@ -38,7 +38,7 @@
                                TIntermSequence *initSequenceOut)
 {
     ASSERT(initializedNode->getBasicType() == EbtStruct);
-    TStructure *structType = initializedNode->getType().getStruct();
+    const TStructure *structType = initializedNode->getType().getStruct();
     for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
     {
         TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
diff --git a/src/compiler/translator/IntermNode_util.cpp b/src/compiler/translator/IntermNode_util.cpp
index 50c52f4..9f1f596 100644
--- a/src/compiler/translator/IntermNode_util.cpp
+++ b/src/compiler/translator/IntermNode_util.cpp
@@ -140,7 +140,7 @@
     {
         ASSERT(type.getBasicType() == EbtStruct);
 
-        TStructure *structure = type.getStruct();
+        const TStructure *structure = type.getStruct();
         for (const auto &field : structure->fields())
         {
             arguments->push_back(CreateZeroNode(*field->type()));
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index a2776e9..99dc04f 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -306,7 +306,7 @@
     // Declare the struct if we have not done so already.
     if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
     {
-        TStructure *structure = type.getStruct();
+        const TStructure *structure = type.getStruct();
 
         declareStruct(structure);
 
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index 7e84761..bb18beb 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -878,11 +878,13 @@
     }
     else
     {
+        const TType &nodeType = node->getType();
         TQualifier qualifier = node->getQualifier();
 
+        ensureStructDefined(nodeType);
+
         if (qualifier == EvqUniform)
         {
-            const TType &nodeType                 = node->getType();
             const TInterfaceBlock *interfaceBlock = nodeType.getInterfaceBlock();
 
             if (interfaceBlock)
@@ -894,8 +896,6 @@
                 mReferencedUniforms[name] = node;
             }
 
-            ensureStructDefined(nodeType);
-
             out << DecorateVariableIfNeeded(node->getName());
         }
         else if (qualifier == EvqAttribute || qualifier == EvqVertexIn)
@@ -1654,7 +1654,7 @@
         }
         case EOpIndexDirectStruct:
         {
-            TStructure *s       = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
+            const TStructure *s = nodeBinary->getLeft()->getAsTyped()->getType().getStruct();
             int index           = nodeBinary->getRight()->getAsConstantUnion()->getIConst(0);
             const TField *field = s->fields()[index];
 
@@ -1821,7 +1821,8 @@
             else if (variable->getAsSymbolNode() &&
                      variable->getAsSymbolNode()->getSymbol() == "")  // Type (struct) declaration
             {
-                // Already added to constructor map
+                ASSERT(variable->getBasicType() == EbtStruct);
+                // ensureStructDefined has already been called.
             }
             else
                 UNREACHABLE();
@@ -1992,45 +1993,7 @@
             return false;
         }
         case EOpConstruct:
-            if (node->getBasicType() == EbtStruct)
-            {
-                if (node->getType().isArray())
-                {
-                    UNIMPLEMENTED();
-                }
-                const TString &structName = StructNameString(*node->getType().getStruct());
-                mStructureHLSL->addConstructor(node->getType(), structName, node->getSequence());
-                outputTriplet(out, visit, (structName + "_ctor(").c_str(), ", ", ")");
-            }
-            else
-            {
-                const char *name = "";
-                if (node->getType().getNominalSize() == 1)
-                {
-                    switch (node->getBasicType())
-                    {
-                        case EbtFloat:
-                            name = "vec1";
-                            break;
-                        case EbtInt:
-                            name = "ivec1";
-                            break;
-                        case EbtUInt:
-                            name = "uvec1";
-                            break;
-                        case EbtBool:
-                            name = "bvec1";
-                            break;
-                        default:
-                            UNREACHABLE();
-                    }
-                }
-                else
-                {
-                    name = node->getType().getBuiltInTypeNameString();
-                }
-                outputConstructor(out, visit, node->getType(), name, node->getSequence());
-            }
+            outputConstructor(out, visit, node);
             break;
         case EOpEqualComponentWise:
             outputTriplet(out, visit, "(", " == ", ")");
@@ -2742,21 +2705,23 @@
     return "{" + string + "}";
 }
 
-void OutputHLSL::outputConstructor(TInfoSinkBase &out,
-                                   Visit visit,
-                                   const TType &type,
-                                   const char *name,
-                                   const TIntermSequence *parameters)
+void OutputHLSL::outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node)
 {
-    if (type.isArray())
-    {
-        UNIMPLEMENTED();
-    }
+    // Array constructors should have been already pruned from the code.
+    ASSERT(!node->getType().isArray());
 
     if (visit == PreVisit)
     {
-        TString constructorName = mStructureHLSL->addConstructor(type, name, parameters);
-
+        TString constructorName;
+        if (node->getBasicType() == EbtStruct)
+        {
+            constructorName = mStructureHLSL->addStructConstructor(*node->getType().getStruct());
+        }
+        else
+        {
+            constructorName =
+                mStructureHLSL->addBuiltInConstructor(node->getType(), node->getSequence());
+        }
         out << constructorName << "(";
     }
     else if (visit == InVisit)
@@ -2778,7 +2743,7 @@
     const TStructure *structure = type.getStruct();
     if (structure)
     {
-        out << StructNameString(*structure) + "_ctor(";
+        out << mStructureHLSL->addStructConstructor(*structure) << "(";
 
         const TFieldList &fields = structure->fields();
 
@@ -3105,11 +3070,11 @@
 
 void OutputHLSL::ensureStructDefined(const TType &type)
 {
-    TStructure *structure = type.getStruct();
-
+    const TStructure *structure = type.getStruct();
     if (structure)
     {
-        mStructureHLSL->addConstructor(type, StructNameString(*structure), nullptr);
+        ASSERT(type.getBasicType() == EbtStruct);
+        mStructureHLSL->ensureStructDefined(*structure);
     }
 }
 
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index 553d4c5..014f4f5 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -104,12 +104,7 @@
     void outputLineDirective(TInfoSinkBase &out, int line);
     TString argumentString(const TIntermSymbol *symbol);
 
-    // Emit constructor. Called with literal names so using const char* instead of TString.
-    void outputConstructor(TInfoSinkBase &out,
-                           Visit visit,
-                           const TType &type,
-                           const char *name,
-                           const TIntermSequence *parameters);
+    void outputConstructor(TInfoSinkBase &out, Visit visit, TIntermAggregate *node);
     const TConstantUnion *writeConstantUnion(TInfoSinkBase &out,
                                              const TType &type,
                                              const TConstantUnion *constUnion);
diff --git a/src/compiler/translator/StructureHLSL.cpp b/src/compiler/translator/StructureHLSL.cpp
index 1f5199b..61a9431 100644
--- a/src/compiler/translator/StructureHLSL.cpp
+++ b/src/compiler/translator/StructureHLSL.cpp
@@ -4,7 +4,7 @@
 // found in the LICENSE file.
 //
 // StructureHLSL.cpp:
-//   Definitions of methods for HLSL translation of GLSL structures.
+//   HLSL translation of GLSL constructors and structures.
 //
 
 #include "compiler/translator/StructureHLSL.h"
@@ -17,6 +17,77 @@
 namespace sh
 {
 
+namespace
+{
+
+TString Define(const TStructure &structure,
+               bool useHLSLRowMajorPacking,
+               bool useStd140Packing,
+               Std140PaddingHelper *padHelper)
+{
+    const TFieldList &fields = structure.fields();
+    const bool isNameless    = (structure.name() == "");
+    const TString &structName =
+        QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
+    const TString declareString = (isNameless ? "struct" : "struct " + structName);
+
+    TString string;
+    string += declareString +
+              "\n"
+              "{\n";
+
+    for (const TField *field : fields)
+    {
+        const TType &fieldType = *field->type();
+        if (!IsSampler(fieldType.getBasicType()))
+        {
+            const TStructure *fieldStruct = fieldType.getStruct();
+            const TString &fieldTypeString =
+                fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
+                                                        useStd140Packing)
+                            : TypeString(fieldType);
+
+            if (padHelper)
+            {
+                string += padHelper->prePaddingString(fieldType);
+            }
+
+            string += "    " + fieldTypeString + " " + DecorateField(field->name(), structure) +
+                      ArrayString(fieldType) + ";\n";
+
+            if (padHelper)
+            {
+                string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
+            }
+        }
+    }
+
+    // Nameless structs do not finish with a semicolon and newline, to leave room for an instance
+    // variable
+    string += (isNameless ? "} " : "};\n");
+
+    return string;
+}
+
+TString WriteParameterList(const std::vector<TType> &parameters)
+{
+    TString parameterList;
+    for (size_t parameter = 0u; parameter < parameters.size(); parameter++)
+    {
+        const TType &paramType = parameters[parameter];
+
+        parameterList += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType);
+
+        if (parameter < parameters.size() - 1u)
+        {
+            parameterList += ", ";
+        }
+    }
+    return parameterList;
+}
+
+}  // anonymous namespace
+
 Std140PaddingHelper::Std140PaddingHelper(const std::map<TString, int> &structElementIndexes,
                                          unsigned *uniqueCounter)
     : mPaddingCounter(uniqueCounter), mElementIndex(0), mStructElementIndexes(&structElementIndexes)
@@ -103,7 +174,7 @@
     }
 
     int numComponents     = 0;
-    TStructure *structure = type.getStruct();
+    const TStructure *structure = type.getStruct();
 
     if (type.isMatrix())
     {
@@ -159,196 +230,162 @@
     if (useStd140Packing)
     {
         Std140PaddingHelper padHelper = getPaddingHelper();
-        return define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
+        return Define(structure, useHLSLRowMajorPacking, useStd140Packing, &padHelper);
     }
     else
     {
-        return define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr);
+        return Define(structure, useHLSLRowMajorPacking, useStd140Packing, nullptr);
     }
 }
 
 TString StructureHLSL::defineNameless(const TStructure &structure)
 {
-    return define(structure, false, false, nullptr);
+    return Define(structure, false, false, nullptr);
 }
 
-TString StructureHLSL::define(const TStructure &structure,
-                              bool useHLSLRowMajorPacking,
-                              bool useStd140Packing,
-                              Std140PaddingHelper *padHelper)
+StructureHLSL::DefinedStructs::iterator StructureHLSL::defineVariants(const TStructure &structure,
+                                                                      const TString &name)
 {
-    const TFieldList &fields = structure.fields();
-    const bool isNameless    = (structure.name() == "");
-    const TString &structName =
-        QualifiedStructNameString(structure, useHLSLRowMajorPacking, useStd140Packing);
-    const TString declareString = (isNameless ? "struct" : "struct " + structName);
+    ASSERT(mDefinedStructs.find(name) == mDefinedStructs.end());
 
-    TString string;
-    string += declareString +
-              "\n"
-              "{\n";
-
-    for (const TField *field : fields)
+    for (const TField *field : structure.fields())
     {
-        const TType &fieldType = *field->type();
-        if (!IsSampler(fieldType.getBasicType()))
+        const TType *fieldType = field->type();
+        if (fieldType->getBasicType() == EbtStruct)
         {
-            const TStructure *fieldStruct = fieldType.getStruct();
-            const TString &fieldTypeString =
-                fieldStruct ? QualifiedStructNameString(*fieldStruct, useHLSLRowMajorPacking,
-                                                        useStd140Packing)
-                            : TypeString(fieldType);
-
-            if (padHelper)
-            {
-                string += padHelper->prePaddingString(fieldType);
-            }
-
-            string += "    " + fieldTypeString + " " + DecorateField(field->name(), structure) +
-                      ArrayString(fieldType) + ";\n";
-
-            if (padHelper)
-            {
-                string += padHelper->postPaddingString(fieldType, useHLSLRowMajorPacking);
-            }
+            ensureStructDefined(*fieldType->getStruct());
         }
     }
 
-    // Nameless structs do not finish with a semicolon and newline, to leave room for an instance
-    // variable
-    string += (isNameless ? "} " : "};\n");
+    DefinedStructs::iterator addedStruct =
+        mDefinedStructs.insert(std::make_pair(name, new TStructProperties())).first;
+    // Add element index
+    storeStd140ElementIndex(structure, false);
+    storeStd140ElementIndex(structure, true);
 
-    return string;
+    const TString &structString = defineQualified(structure, false, false);
+
+    ASSERT(std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) ==
+           mStructDeclarations.end());
+    // Add row-major packed struct for interface blocks
+    TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
+                             defineQualified(structure, true, false) +
+                             "#pragma pack_matrix(column_major)\n";
+
+    TString std140String         = defineQualified(structure, false, true);
+    TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
+                                   defineQualified(structure, true, true) +
+                                   "#pragma pack_matrix(column_major)\n";
+
+    mStructDeclarations.push_back(structString);
+    mStructDeclarations.push_back(rowMajorString);
+    mStructDeclarations.push_back(std140String);
+    mStructDeclarations.push_back(std140RowMajorString);
+    return addedStruct;
 }
 
-TString StructureHLSL::addConstructor(const TType &type,
-                                      const TString &name,
-                                      const TIntermSequence *parameters)
+void StructureHLSL::ensureStructDefined(const TStructure &structure)
 {
+    const TString name = StructNameString(structure);
+    if (name == "")
+    {
+        return;  // Nameless structures are not defined
+    }
+    if (mDefinedStructs.find(name) == mDefinedStructs.end())
+    {
+        defineVariants(structure, name);
+    }
+}
+
+TString StructureHLSL::addStructConstructor(const TStructure &structure)
+{
+    const TString name = StructNameString(structure);
+
     if (name == "")
     {
         return TString();  // Nameless structures don't have constructors
     }
 
-    if (type.getStruct() && mStructNames.find(name) != mStructNames.end())
+    auto definedStruct = mDefinedStructs.find(name);
+    if (definedStruct == mDefinedStructs.end())
     {
-        return TString(name);  // Already added
+        definedStruct = defineVariants(structure, name);
     }
+    const TString constructorFunctionName = TString(name) + "_ctor";
+    TString *constructor                  = &definedStruct->second->constructor;
+    if (!constructor->empty())
+    {
+        return constructorFunctionName;  // Already added
+    }
+    *constructor += name + " " + constructorFunctionName + "(";
+
+    std::vector<TType> ctorParameters;
+    const TFieldList &fields = structure.fields();
+    for (const TField *field : fields)
+    {
+        const TType *fieldType = field->type();
+        if (!IsSampler(fieldType->getBasicType()))
+        {
+            ctorParameters.push_back(*fieldType);
+        }
+    }
+    // Structs that have sampler members should not have constructor calls, and otherwise structs
+    // are guaranteed to be non-empty by the grammar. Structs can't contain empty declarations
+    // either.
+    ASSERT(!ctorParameters.empty());
+
+    *constructor += WriteParameterList(ctorParameters);
+
+    *constructor +=
+        ")\n"
+        "{\n"
+        "    " +
+        name + " structure = { ";
+
+    for (size_t parameterIndex = 0u; parameterIndex < ctorParameters.size(); ++parameterIndex)
+    {
+        *constructor += "x" + str(parameterIndex);
+        if (parameterIndex < ctorParameters.size() - 1u)
+        {
+            *constructor += ", ";
+        }
+    }
+    *constructor +=
+        "};\n"
+        "    return structure;\n"
+        "}\n";
+
+    return constructorFunctionName;
+}
+
+TString StructureHLSL::addBuiltInConstructor(const TType &type, const TIntermSequence *parameters)
+{
+    ASSERT(!type.isArray());
+    ASSERT(type.getStruct() == nullptr);
+    ASSERT(parameters);
 
     TType ctorType = type;
-    while (ctorType.isArray())
-    {
-        ctorType.toArrayElementType();
-    }
     ctorType.setPrecision(EbpHigh);
     ctorType.setQualifier(EvqTemporary);
 
-    typedef std::vector<TType> ParameterArray;
-    ParameterArray ctorParameters;
+    const TString constructorFunctionName =
+        TString(type.getBuiltInTypeNameString()) + "_ctor" + DisambiguateFunctionName(parameters);
+    TString constructor = TypeString(ctorType) + " " + constructorFunctionName + "(";
 
-    TString constructorFunctionName;
-
-    const TStructure *structure = type.getStruct();
-    if (structure)
+    std::vector<TType> ctorParameters;
+    for (auto parameter : *parameters)
     {
-        const TFieldList &fields = structure->fields();
-        for (const TField *field : fields)
-        {
-            const TType *fieldType = field->type();
-            if (!IsSampler(fieldType->getBasicType()))
-            {
-                ctorParameters.push_back(*fieldType);
-            }
-            if (fieldType->getBasicType() == EbtStruct)
-            {
-                addConstructor(*fieldType, StructNameString(*fieldType->getStruct()), nullptr);
-            }
-        }
-
-        mStructNames.insert(name);
-
-        // Add element index
-        storeStd140ElementIndex(*structure, false);
-        storeStd140ElementIndex(*structure, true);
-
-        const TString &structString = defineQualified(*structure, false, false);
-
-        if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structString) ==
-            mStructDeclarations.end())
-        {
-            // Add row-major packed struct for interface blocks
-            TString rowMajorString = "#pragma pack_matrix(row_major)\n" +
-                                     defineQualified(*structure, true, false) +
-                                     "#pragma pack_matrix(column_major)\n";
-
-            TString std140String         = defineQualified(*structure, false, true);
-            TString std140RowMajorString = "#pragma pack_matrix(row_major)\n" +
-                                           defineQualified(*structure, true, true) +
-                                           "#pragma pack_matrix(column_major)\n";
-
-            mStructDeclarations.push_back(structString);
-            mStructDeclarations.push_back(rowMajorString);
-            mStructDeclarations.push_back(std140String);
-            mStructDeclarations.push_back(std140RowMajorString);
-        }
-
-        constructorFunctionName = TString(name);
+        const TType &paramType = parameter->getAsTyped()->getType();
+        ASSERT(!paramType.isArray());
+        ctorParameters.push_back(paramType);
     }
-    else if (parameters)
-    {
-        for (auto parameter : *parameters)
-        {
-            const TType &paramType = parameter->getAsTyped()->getType();
-            ctorParameters.push_back(paramType);
-        }
-        constructorFunctionName = TString(name) + DisambiguateFunctionName(parameters);
-    }
-    else
-        UNREACHABLE();
-
-    TString constructor;
-
-    if (ctorType.getStruct())
-    {
-        constructor += name + " " + name + "_ctor(";
-    }
-    else  // Built-in type
-    {
-        constructor += TypeString(ctorType) + " " + constructorFunctionName + "(";
-    }
-
-    for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
-    {
-        const TType &paramType = ctorParameters[parameter];
-
-        constructor += TypeString(paramType) + " x" + str(parameter) + ArrayString(paramType);
-
-        if (parameter < ctorParameters.size() - 1)
-        {
-            constructor += ", ";
-        }
-    }
+    constructor += WriteParameterList(ctorParameters);
 
     constructor +=
         ")\n"
-        "{\n";
-
-    if (ctorType.getStruct())
-    {
-        constructor += "    " + name + " structure";
-        if (ctorParameters.empty())
-        {
-            constructor += ";\n";
-        }
-        else
-        {
-            constructor += " = { ";
-        }
-    }
-    else
-    {
-        constructor += "    return " + TypeString(ctorType) + "(";
-    }
+        "{\n"
+        "    return " +
+        TypeString(ctorType) + "(";
 
     if (ctorType.isMatrix() && ctorParameters.size() == 1)
     {
@@ -403,15 +440,7 @@
     }
     else
     {
-        size_t remainingComponents = 0;
-        if (ctorType.getStruct())
-        {
-            remainingComponents = ctorParameters.size();
-        }
-        else
-        {
-            remainingComponents = ctorType.getObjectSize();
-        }
+        size_t remainingComponents = ctorType.getObjectSize();
         size_t parameterIndex = 0;
 
         while (remainingComponents > 0)
@@ -422,13 +451,7 @@
 
             constructor += "x" + str(parameterIndex);
 
-            if (ctorType.getStruct())
-            {
-                ASSERT(remainingComponents == 1 || moreParameters);
-
-                --remainingComponents;
-            }
-            else if (parameter.isScalar())
+            if (parameter.isScalar())
             {
                 remainingComponents -= parameter.getObjectSize();
             }
@@ -504,7 +527,9 @@
                 }
             }
             else
+            {
                 UNREACHABLE();
+            }
 
             if (moreParameters)
             {
@@ -518,24 +543,11 @@
         }
     }
 
-    if (ctorType.getStruct())
-    {
-        if (!ctorParameters.empty())
-        {
-            constructor += "};\n";
-        }
-        constructor +=
-            "    return structure;\n"
-            "}\n";
-    }
-    else
-    {
-        constructor +=
-            ");\n"
-            "}\n";
-    }
+    constructor +=
+        ");\n"
+        "}\n";
 
-    mConstructors.insert(constructor);
+    mBuiltInConstructors.insert(constructor);
 
     return constructorFunctionName;
 }
@@ -544,15 +556,19 @@
 {
     TInfoSinkBase out;
 
-    for (size_t structIndex = 0; structIndex < mStructDeclarations.size(); structIndex++)
+    for (auto &declaration : mStructDeclarations)
     {
-        out << mStructDeclarations[structIndex];
+        out << declaration;
     }
 
-    for (Constructors::const_iterator constructor = mConstructors.begin();
-         constructor != mConstructors.end(); constructor++)
+    for (auto &structure : mDefinedStructs)
     {
-        out << *constructor;
+        out << structure.second->constructor;
+    }
+
+    for (auto &constructor : mBuiltInConstructors)
+    {
+        out << constructor;
     }
 
     return out.str();
diff --git a/src/compiler/translator/StructureHLSL.h b/src/compiler/translator/StructureHLSL.h
index b8c6d62..daced8f 100644
--- a/src/compiler/translator/StructureHLSL.h
+++ b/src/compiler/translator/StructureHLSL.h
@@ -4,7 +4,7 @@
 // found in the LICENSE file.
 //
 // StructureHLSL.h:
-//   Interfaces of methods for HLSL translation of GLSL structures.
+//   HLSL translation of GLSL constructors and structures.
 //
 
 #ifndef COMPILER_TRANSLATOR_STRUCTUREHLSL_H_
@@ -49,17 +49,14 @@
   public:
     StructureHLSL();
 
-    // Returns the name of the constructor function. "name" parameter is the name of the type being
-    // constructed.
-    TString addConstructor(const TType &type,
-                           const TString &name,
-                           const TIntermSequence *parameters);
-    std::string structsHeader() const;
+    // Returns the name of the constructor function.
+    TString addStructConstructor(const TStructure &structure);
+    TString addBuiltInConstructor(const TType &type, const TIntermSequence *parameters);
 
-    TString defineQualified(const TStructure &structure,
-                            bool useHLSLRowMajorPacking,
-                            bool useStd140Packing);
     static TString defineNameless(const TStructure &structure);
+    void ensureStructDefined(const TStructure &structure);
+
+    std::string structsHeader() const;
 
     Std140PaddingHelper getPaddingHelper();
 
@@ -68,20 +65,33 @@
 
     std::map<TString, int> mStd140StructElementIndexes;
 
-    typedef std::set<TString> StructNames;
-    StructNames mStructNames;
+    struct TStructProperties : public angle::NonCopyable
+    {
+        POOL_ALLOCATOR_NEW_DELETE();
 
-    typedef std::set<TString> Constructors;
-    Constructors mConstructors;
+        TStructProperties() {}
 
+        // Constructor is an empty string in case the struct doesn't have a constructor yet.
+        TString constructor;
+    };
+
+    // Map from struct name to struct properties.
+    typedef std::map<TString, TStructProperties *> DefinedStructs;
+    DefinedStructs mDefinedStructs;
+
+    // Struct declarations need to be kept in a vector instead of having them inside mDefinedStructs
+    // since maintaining the original order is necessary for nested structs.
     typedef std::vector<TString> StructDeclarations;
     StructDeclarations mStructDeclarations;
 
+    typedef std::set<TString> BuiltInConstructors;
+    BuiltInConstructors mBuiltInConstructors;
+
     void storeStd140ElementIndex(const TStructure &structure, bool useHLSLRowMajorPacking);
-    static TString define(const TStructure &structure,
-                          bool useHLSLRowMajorPacking,
-                          bool useStd140Packing,
-                          Std140PaddingHelper *padHelper);
+    TString defineQualified(const TStructure &structure,
+                            bool useHLSLRowMajorPacking,
+                            bool useStd140Packing);
+    DefinedStructs::iterator defineVariants(const TStructure &structure, const TString &name);
 };
 }
 
diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
index d1a88d0..ceeef5c 100644
--- a/src/compiler/translator/Types.h
+++ b/src/compiler/translator/Types.h
@@ -383,7 +383,8 @@
 
     bool canBeConstructed() const;
 
-    TStructure *getStruct() const { return structure; }
+    TStructure *getStruct() { return structure; }
+    const TStructure *getStruct() const { return structure; }
     void setStruct(TStructure *s)
     {
         if (structure != s)
diff --git a/src/compiler/translator/UniformHLSL.cpp b/src/compiler/translator/UniformHLSL.cpp
index 311209d..9f18509 100644
--- a/src/compiler/translator/UniformHLSL.cpp
+++ b/src/compiler/translator/UniformHLSL.cpp
@@ -38,7 +38,7 @@
     const TType &fieldType                   = *field.type();
     const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking;
     ASSERT(matrixPacking != EmpUnspecified);
-    TStructure *structure = fieldType.getStruct();
+    const TStructure *structure = fieldType.getStruct();
 
     if (fieldType.isMatrix())
     {