diff --git a/Test/baseResults/hlsl.hull.1.tesc.out b/Test/baseResults/hlsl.hull.1.tesc.out
new file mode 100644
index 0000000000000000000000000000000000000000..18034c8bed252b8033cda416a2630e0a1db7a39c
--- /dev/null
+++ b/Test/baseResults/hlsl.hull.1.tesc.out
@@ -0,0 +1,359 @@
+hlsl.hull.1.tesc
+Shader version: 450
+vertices = 4
+0:? Sequence
+0:26  Function Definition: @main(struct-VS_OUT-vf31[4];u1; (temp structure{temp 3-component vector of float cpoint})
+0:26    Function Parameters: 
+0:26      'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:26      'm_cpid' (in uint)
+0:?     Sequence
+0:28      move second child to first child (temp 3-component vector of float)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          'output' (temp structure{temp 3-component vector of float cpoint})
+0:28          Constant:
+0:28            0 (const int)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          direct index (temp structure{temp 3-component vector of float cpoint})
+0:28            'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:28            Constant:
+0:28              0 (const int)
+0:28          Constant:
+0:28            0 (const int)
+0:29      Branch: Return with expression
+0:29        'output' (temp structure{temp 3-component vector of float cpoint})
+0:26  Function Definition: main( (temp void)
+0:26    Function Parameters: 
+0:?     Sequence
+0:26      move second child to first child (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:26      move second child to first child (temp uint)
+0:?         'm_cpid' (temp uint)
+0:?         'm_cpid' (in uint InvocationID)
+0:26      move second child to first child (temp structure{temp 3-component vector of float cpoint})
+0:?         '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:26        Function Call: @main(struct-VS_OUT-vf31[4];u1; (temp structure{temp 3-component vector of float cpoint})
+0:?           'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?           'm_cpid' (temp uint)
+0:?       Barrier (temp void)
+0:?       Test condition and select (temp void)
+0:?         Condition
+0:?         Compare Equal (temp bool)
+0:?           'm_cpid' (in uint InvocationID)
+0:?           Constant:
+0:?             0 (const int)
+0:?         true case
+0:?         Sequence
+0:?           move second child to first child (temp structure{temp 2-element array of float edges})
+0:?             '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?             Function Call: PCF(u1; (temp structure{temp 2-element array of float edges})
+0:?               'pid' (in uint PrimitiveID)
+0:?           Sequence
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   1 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   1 (const int)
+0:33  Function Definition: PCF(u1; (temp structure{temp 2-element array of float edges})
+0:33    Function Parameters: 
+0:33      'pid' (in uint)
+0:?     Sequence
+0:36      move second child to first child (temp float)
+0:36        direct index (temp float)
+0:36          edges: direct index for structure (temp 2-element array of float)
+0:36            'output' (temp structure{temp 2-element array of float edges})
+0:36            Constant:
+0:36              0 (const int)
+0:36          Constant:
+0:36            0 (const int)
+0:36        Constant:
+0:36          2.000000
+0:37      move second child to first child (temp float)
+0:37        direct index (temp float)
+0:37          edges: direct index for structure (temp 2-element array of float)
+0:37            'output' (temp structure{temp 2-element array of float edges})
+0:37            Constant:
+0:37              0 (const int)
+0:37          Constant:
+0:37            1 (const int)
+0:37        Constant:
+0:37          8.000000
+0:38      Branch: Return with expression
+0:38        'output' (temp structure{temp 2-element array of float edges})
+0:?   Linker Objects
+0:?     '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:?     'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:?     'm_cpid' (in uint InvocationID)
+0:?     'pid' (in uint PrimitiveID)
+0:?     '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+
+
+Linked tessellation control stage:
+
+
+Shader version: 450
+vertices = 4
+0:? Sequence
+0:26  Function Definition: @main(struct-VS_OUT-vf31[4];u1; (temp structure{temp 3-component vector of float cpoint})
+0:26    Function Parameters: 
+0:26      'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:26      'm_cpid' (in uint)
+0:?     Sequence
+0:28      move second child to first child (temp 3-component vector of float)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          'output' (temp structure{temp 3-component vector of float cpoint})
+0:28          Constant:
+0:28            0 (const int)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          direct index (temp structure{temp 3-component vector of float cpoint})
+0:28            'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:28            Constant:
+0:28              0 (const int)
+0:28          Constant:
+0:28            0 (const int)
+0:29      Branch: Return with expression
+0:29        'output' (temp structure{temp 3-component vector of float cpoint})
+0:26  Function Definition: main( (temp void)
+0:26    Function Parameters: 
+0:?     Sequence
+0:26      move second child to first child (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:26      move second child to first child (temp uint)
+0:?         'm_cpid' (temp uint)
+0:?         'm_cpid' (in uint InvocationID)
+0:26      move second child to first child (temp structure{temp 3-component vector of float cpoint})
+0:?         '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:26        Function Call: @main(struct-VS_OUT-vf31[4];u1; (temp structure{temp 3-component vector of float cpoint})
+0:?           'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?           'm_cpid' (temp uint)
+0:?       Barrier (temp void)
+0:?       Test condition and select (temp void)
+0:?         Condition
+0:?         Compare Equal (temp bool)
+0:?           'm_cpid' (in uint InvocationID)
+0:?           Constant:
+0:?             0 (const int)
+0:?         true case
+0:?         Sequence
+0:?           move second child to first child (temp structure{temp 2-element array of float edges})
+0:?             '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?             Function Call: PCF(u1; (temp structure{temp 2-element array of float edges})
+0:?               'pid' (in uint PrimitiveID)
+0:?           Sequence
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   1 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   1 (const int)
+0:33  Function Definition: PCF(u1; (temp structure{temp 2-element array of float edges})
+0:33    Function Parameters: 
+0:33      'pid' (in uint)
+0:?     Sequence
+0:36      move second child to first child (temp float)
+0:36        direct index (temp float)
+0:36          edges: direct index for structure (temp 2-element array of float)
+0:36            'output' (temp structure{temp 2-element array of float edges})
+0:36            Constant:
+0:36              0 (const int)
+0:36          Constant:
+0:36            0 (const int)
+0:36        Constant:
+0:36          2.000000
+0:37      move second child to first child (temp float)
+0:37        direct index (temp float)
+0:37          edges: direct index for structure (temp 2-element array of float)
+0:37            'output' (temp structure{temp 2-element array of float edges})
+0:37            Constant:
+0:37              0 (const int)
+0:37          Constant:
+0:37            1 (const int)
+0:37        Constant:
+0:37          8.000000
+0:38      Branch: Return with expression
+0:38        'output' (temp structure{temp 2-element array of float edges})
+0:?   Linker Objects
+0:?     '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:?     'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:?     'm_cpid' (in uint InvocationID)
+0:?     'pid' (in uint PrimitiveID)
+0:?     '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 85
+
+                              Capability Tessellation
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint TessellationControl 4  "main" 40 44 47 62 67
+                              ExecutionMode 4 OutputVertices 4
+                              Name 4  "main"
+                              Name 8  "VS_OUT"
+                              MemberName 8(VS_OUT) 0  "cpoint"
+                              Name 14  "HS_OUT"
+                              MemberName 14(HS_OUT) 0  "cpoint"
+                              Name 18  "@main(struct-VS_OUT-vf31[4];u1;"
+                              Name 16  "ip"
+                              Name 17  "m_cpid"
+                              Name 22  "HS_CONSTANT_OUT"
+                              MemberName 22(HS_CONSTANT_OUT) 0  "edges"
+                              Name 25  "PCF(u1;"
+                              Name 24  "pid"
+                              Name 28  "output"
+                              Name 38  "ip"
+                              Name 40  "ip"
+                              Name 42  "m_cpid"
+                              Name 44  "m_cpid"
+                              Name 47  "@entryPointOutput"
+                              Name 48  "param"
+                              Name 50  "param"
+                              Name 61  "@patchConstantResult"
+                              Name 62  "pid"
+                              Name 63  "param"
+                              Name 67  "@patchConstantOutput_edges"
+                              Name 77  "output"
+                              Decorate 40(ip) Location 0
+                              Decorate 44(m_cpid) BuiltIn InvocationId
+                              Decorate 47(@entryPointOutput) Location 0
+                              Decorate 62(pid) BuiltIn PrimitiveId
+                              Decorate 67(@patchConstantOutput_edges) BuiltIn TessLevelOuter
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 3
+       8(VS_OUT):             TypeStruct 7(fvec3)
+               9:             TypeInt 32 0
+              10:      9(int) Constant 4
+              11:             TypeArray 8(VS_OUT) 10
+              12:             TypePointer Function 11
+              13:             TypePointer Function 9(int)
+      14(HS_OUT):             TypeStruct 7(fvec3)
+              15:             TypeFunction 14(HS_OUT) 12(ptr) 13(ptr)
+              20:      9(int) Constant 2
+              21:             TypeArray 6(float) 20
+22(HS_CONSTANT_OUT):             TypeStruct 21
+              23:             TypeFunction 22(HS_CONSTANT_OUT) 13(ptr)
+              27:             TypePointer Function 14(HS_OUT)
+              29:             TypeInt 32 1
+              30:     29(int) Constant 0
+              31:             TypePointer Function 7(fvec3)
+              39:             TypePointer Input 11
+          40(ip):     39(ptr) Variable Input
+              43:             TypePointer Input 9(int)
+      44(m_cpid):     43(ptr) Variable Input
+              46:             TypePointer Output 14(HS_OUT)
+47(@entryPointOutput):     46(ptr) Variable Output
+              53:      9(int) Constant 1
+              54:      9(int) Constant 0
+              56:             TypeBool
+              60:             TypePointer Function 22(HS_CONSTANT_OUT)
+         62(pid):     43(ptr) Variable Input
+              66:             TypePointer Output 21
+67(@patchConstantOutput_edges):     66(ptr) Variable Output
+              68:             TypePointer Function 6(float)
+              71:             TypePointer Output 6(float)
+              73:     29(int) Constant 1
+              78:    6(float) Constant 1073741824
+              80:    6(float) Constant 1090519040
+         4(main):           2 Function None 3
+               5:             Label
+          38(ip):     12(ptr) Variable Function
+      42(m_cpid):     13(ptr) Variable Function
+       48(param):     12(ptr) Variable Function
+       50(param):     13(ptr) Variable Function
+61(@patchConstantResult):     60(ptr) Variable Function
+       63(param):     13(ptr) Variable Function
+              41:          11 Load 40(ip)
+                              Store 38(ip) 41
+              45:      9(int) Load 44(m_cpid)
+                              Store 42(m_cpid) 45
+              49:          11 Load 38(ip)
+                              Store 48(param) 49
+              51:      9(int) Load 42(m_cpid)
+                              Store 50(param) 51
+              52:  14(HS_OUT) FunctionCall 18(@main(struct-VS_OUT-vf31[4];u1;) 48(param) 50(param)
+                              Store 47(@entryPointOutput) 52
+                              ControlBarrier 20 53 54
+              55:      9(int) Load 44(m_cpid)
+              57:    56(bool) IEqual 55 30
+                              SelectionMerge 59 None
+                              BranchConditional 57 58 59
+              58:               Label
+              64:      9(int)   Load 62(pid)
+                                Store 63(param) 64
+              65:22(HS_CONSTANT_OUT)   FunctionCall 25(PCF(u1;) 63(param)
+                                Store 61(@patchConstantResult) 65
+              69:     68(ptr)   AccessChain 61(@patchConstantResult) 30 30
+              70:    6(float)   Load 69
+              72:     71(ptr)   AccessChain 67(@patchConstantOutput_edges) 30
+                                Store 72 70
+              74:     68(ptr)   AccessChain 61(@patchConstantResult) 30 73
+              75:    6(float)   Load 74
+              76:     71(ptr)   AccessChain 67(@patchConstantOutput_edges) 73
+                                Store 76 75
+                                Branch 59
+              59:             Label
+                              Return
+                              FunctionEnd
+18(@main(struct-VS_OUT-vf31[4];u1;):  14(HS_OUT) Function None 15
+          16(ip):     12(ptr) FunctionParameter
+      17(m_cpid):     13(ptr) FunctionParameter
+              19:             Label
+      28(output):     27(ptr) Variable Function
+              32:     31(ptr) AccessChain 16(ip) 30 30
+              33:    7(fvec3) Load 32
+              34:     31(ptr) AccessChain 28(output) 30
+                              Store 34 33
+              35:  14(HS_OUT) Load 28(output)
+                              ReturnValue 35
+                              FunctionEnd
+     25(PCF(u1;):22(HS_CONSTANT_OUT) Function None 23
+         24(pid):     13(ptr) FunctionParameter
+              26:             Label
+      77(output):     60(ptr) Variable Function
+              79:     68(ptr) AccessChain 77(output) 30 30
+                              Store 79 78
+              81:     68(ptr) AccessChain 77(output) 30 73
+                              Store 81 80
+              82:22(HS_CONSTANT_OUT) Load 77(output)
+                              ReturnValue 82
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.hull.2.tesc.out b/Test/baseResults/hlsl.hull.2.tesc.out
new file mode 100644
index 0000000000000000000000000000000000000000..d3c9cb841ae46139938c39c8fa55d2791f4a157f
--- /dev/null
+++ b/Test/baseResults/hlsl.hull.2.tesc.out
@@ -0,0 +1,357 @@
+hlsl.hull.2.tesc
+Shader version: 450
+vertices = 4
+0:? Sequence
+0:26  Function Definition: @main(struct-VS_OUT-vf31[4]; (temp structure{temp 3-component vector of float cpoint})
+0:26    Function Parameters: 
+0:26      'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:?     Sequence
+0:28      move second child to first child (temp 3-component vector of float)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          'output' (temp structure{temp 3-component vector of float cpoint})
+0:28          Constant:
+0:28            0 (const int)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          direct index (temp structure{temp 3-component vector of float cpoint})
+0:28            'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:28            Constant:
+0:28              0 (const int)
+0:28          Constant:
+0:28            0 (const int)
+0:29      Branch: Return with expression
+0:29        'output' (temp structure{temp 3-component vector of float cpoint})
+0:26  Function Definition: main( (temp void)
+0:26    Function Parameters: 
+0:?     Sequence
+0:26      move second child to first child (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:26      move second child to first child (temp structure{temp 3-component vector of float cpoint})
+0:?         '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:26        Function Call: @main(struct-VS_OUT-vf31[4]; (temp structure{temp 3-component vector of float cpoint})
+0:?           'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?       Barrier (temp void)
+0:?       Test condition and select (temp void)
+0:?         Condition
+0:?         Compare Equal (temp bool)
+0:?           'InvocationId' (in uint InvocationID)
+0:?           Constant:
+0:?             0 (const int)
+0:?         true case
+0:?         Sequence
+0:?           move second child to first child (temp structure{temp 2-element array of float edges})
+0:?             '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?             Function Call: PCF(u1;vf4; (temp structure{temp 2-element array of float edges})
+0:?               'pid' (in uint PrimitiveID)
+0:?               'pos' (in 4-component vector of float Position)
+0:?           Sequence
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   1 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   1 (const int)
+0:33  Function Definition: PCF(u1;vf4; (temp structure{temp 2-element array of float edges})
+0:33    Function Parameters: 
+0:33      'pid' (in uint)
+0:33      'pos' (in 4-component vector of float)
+0:?     Sequence
+0:36      move second child to first child (temp float)
+0:36        direct index (temp float)
+0:36          edges: direct index for structure (temp 2-element array of float)
+0:36            'output' (temp structure{temp 2-element array of float edges})
+0:36            Constant:
+0:36              0 (const int)
+0:36          Constant:
+0:36            0 (const int)
+0:36        Constant:
+0:36          2.000000
+0:37      move second child to first child (temp float)
+0:37        direct index (temp float)
+0:37          edges: direct index for structure (temp 2-element array of float)
+0:37            'output' (temp structure{temp 2-element array of float edges})
+0:37            Constant:
+0:37              0 (const int)
+0:37          Constant:
+0:37            1 (const int)
+0:37        Constant:
+0:37          8.000000
+0:38      Branch: Return with expression
+0:38        'output' (temp structure{temp 2-element array of float edges})
+0:?   Linker Objects
+0:?     '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:?     'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:?     'pid' (in uint PrimitiveID)
+0:?     'pos' (in 4-component vector of float Position)
+0:?     'InvocationId' (in uint InvocationID)
+0:?     '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+
+
+Linked tessellation control stage:
+
+
+Shader version: 450
+vertices = 4
+0:? Sequence
+0:26  Function Definition: @main(struct-VS_OUT-vf31[4]; (temp structure{temp 3-component vector of float cpoint})
+0:26    Function Parameters: 
+0:26      'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:?     Sequence
+0:28      move second child to first child (temp 3-component vector of float)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          'output' (temp structure{temp 3-component vector of float cpoint})
+0:28          Constant:
+0:28            0 (const int)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          direct index (temp structure{temp 3-component vector of float cpoint})
+0:28            'ip' (in 4-element array of structure{temp 3-component vector of float cpoint})
+0:28            Constant:
+0:28              0 (const int)
+0:28          Constant:
+0:28            0 (const int)
+0:29      Branch: Return with expression
+0:29        'output' (temp structure{temp 3-component vector of float cpoint})
+0:26  Function Definition: main( (temp void)
+0:26    Function Parameters: 
+0:?     Sequence
+0:26      move second child to first child (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:26      move second child to first child (temp structure{temp 3-component vector of float cpoint})
+0:?         '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:26        Function Call: @main(struct-VS_OUT-vf31[4]; (temp structure{temp 3-component vector of float cpoint})
+0:?           'ip' (temp 4-element array of structure{temp 3-component vector of float cpoint})
+0:?       Barrier (temp void)
+0:?       Test condition and select (temp void)
+0:?         Condition
+0:?         Compare Equal (temp bool)
+0:?           'InvocationId' (in uint InvocationID)
+0:?           Constant:
+0:?             0 (const int)
+0:?         true case
+0:?         Sequence
+0:?           move second child to first child (temp structure{temp 2-element array of float edges})
+0:?             '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?             Function Call: PCF(u1;vf4; (temp structure{temp 2-element array of float edges})
+0:?               'pid' (in uint PrimitiveID)
+0:?               'pos' (in 4-component vector of float Position)
+0:?           Sequence
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   0 (const int)
+0:?             move second child to first child (temp float)
+0:?               direct index (out float TessLevelOuter)
+0:?                 '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+0:?                 Constant:
+0:?                   1 (const int)
+0:?               direct index (temp float)
+0:?                 edges: direct index for structure (temp 2-element array of float)
+0:?                   '@patchConstantResult' (temp structure{temp 2-element array of float edges})
+0:?                   Constant:
+0:?                     0 (const int)
+0:?                 Constant:
+0:?                   1 (const int)
+0:33  Function Definition: PCF(u1;vf4; (temp structure{temp 2-element array of float edges})
+0:33    Function Parameters: 
+0:33      'pid' (in uint)
+0:33      'pos' (in 4-component vector of float)
+0:?     Sequence
+0:36      move second child to first child (temp float)
+0:36        direct index (temp float)
+0:36          edges: direct index for structure (temp 2-element array of float)
+0:36            'output' (temp structure{temp 2-element array of float edges})
+0:36            Constant:
+0:36              0 (const int)
+0:36          Constant:
+0:36            0 (const int)
+0:36        Constant:
+0:36          2.000000
+0:37      move second child to first child (temp float)
+0:37        direct index (temp float)
+0:37          edges: direct index for structure (temp 2-element array of float)
+0:37            'output' (temp structure{temp 2-element array of float edges})
+0:37            Constant:
+0:37              0 (const int)
+0:37          Constant:
+0:37            1 (const int)
+0:37        Constant:
+0:37          8.000000
+0:38      Branch: Return with expression
+0:38        'output' (temp structure{temp 2-element array of float edges})
+0:?   Linker Objects
+0:?     '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:?     'ip' (layout(location=0 ) in 4-element array of structure{temp 3-component vector of float cpoint})
+0:?     'pid' (in uint PrimitiveID)
+0:?     'pos' (in 4-component vector of float Position)
+0:?     'InvocationId' (in uint InvocationID)
+0:?     '@patchConstantOutput_edges' (out 2-element array of float TessLevelOuter)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 87
+
+                              Capability Tessellation
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint TessellationControl 4  "main" 42 45 52 60 62 69
+                              ExecutionMode 4 OutputVertices 4
+                              Name 4  "main"
+                              Name 8  "VS_OUT"
+                              MemberName 8(VS_OUT) 0  "cpoint"
+                              Name 13  "HS_OUT"
+                              MemberName 13(HS_OUT) 0  "cpoint"
+                              Name 16  "@main(struct-VS_OUT-vf31[4];"
+                              Name 15  "ip"
+                              Name 23  "HS_CONSTANT_OUT"
+                              MemberName 23(HS_CONSTANT_OUT) 0  "edges"
+                              Name 27  "PCF(u1;vf4;"
+                              Name 25  "pid"
+                              Name 26  "pos"
+                              Name 30  "output"
+                              Name 40  "ip"
+                              Name 42  "ip"
+                              Name 45  "@entryPointOutput"
+                              Name 46  "param"
+                              Name 52  "InvocationId"
+                              Name 59  "@patchConstantResult"
+                              Name 60  "pid"
+                              Name 62  "pos"
+                              Name 63  "param"
+                              Name 65  "param"
+                              Name 69  "@patchConstantOutput_edges"
+                              Name 79  "output"
+                              Decorate 42(ip) Location 0
+                              Decorate 45(@entryPointOutput) Location 0
+                              Decorate 52(InvocationId) BuiltIn InvocationId
+                              Decorate 60(pid) BuiltIn PrimitiveId
+                              Decorate 62(pos) BuiltIn Position
+                              Decorate 69(@patchConstantOutput_edges) BuiltIn TessLevelOuter
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 3
+       8(VS_OUT):             TypeStruct 7(fvec3)
+               9:             TypeInt 32 0
+              10:      9(int) Constant 4
+              11:             TypeArray 8(VS_OUT) 10
+              12:             TypePointer Function 11
+      13(HS_OUT):             TypeStruct 7(fvec3)
+              14:             TypeFunction 13(HS_OUT) 12(ptr)
+              18:             TypePointer Function 9(int)
+              19:             TypeVector 6(float) 4
+              20:             TypePointer Function 19(fvec4)
+              21:      9(int) Constant 2
+              22:             TypeArray 6(float) 21
+23(HS_CONSTANT_OUT):             TypeStruct 22
+              24:             TypeFunction 23(HS_CONSTANT_OUT) 18(ptr) 20(ptr)
+              29:             TypePointer Function 13(HS_OUT)
+              31:             TypeInt 32 1
+              32:     31(int) Constant 0
+              33:             TypePointer Function 7(fvec3)
+              41:             TypePointer Input 11
+          42(ip):     41(ptr) Variable Input
+              44:             TypePointer Output 13(HS_OUT)
+45(@entryPointOutput):     44(ptr) Variable Output
+              49:      9(int) Constant 1
+              50:      9(int) Constant 0
+              51:             TypePointer Input 9(int)
+52(InvocationId):     51(ptr) Variable Input
+              54:             TypeBool
+              58:             TypePointer Function 23(HS_CONSTANT_OUT)
+         60(pid):     51(ptr) Variable Input
+              61:             TypePointer Input 19(fvec4)
+         62(pos):     61(ptr) Variable Input
+              68:             TypePointer Output 22
+69(@patchConstantOutput_edges):     68(ptr) Variable Output
+              70:             TypePointer Function 6(float)
+              73:             TypePointer Output 6(float)
+              75:     31(int) Constant 1
+              80:    6(float) Constant 1073741824
+              82:    6(float) Constant 1090519040
+         4(main):           2 Function None 3
+               5:             Label
+          40(ip):     12(ptr) Variable Function
+       46(param):     12(ptr) Variable Function
+59(@patchConstantResult):     58(ptr) Variable Function
+       63(param):     18(ptr) Variable Function
+       65(param):     20(ptr) Variable Function
+              43:          11 Load 42(ip)
+                              Store 40(ip) 43
+              47:          11 Load 40(ip)
+                              Store 46(param) 47
+              48:  13(HS_OUT) FunctionCall 16(@main(struct-VS_OUT-vf31[4];) 46(param)
+                              Store 45(@entryPointOutput) 48
+                              ControlBarrier 21 49 50
+              53:      9(int) Load 52(InvocationId)
+              55:    54(bool) IEqual 53 32
+                              SelectionMerge 57 None
+                              BranchConditional 55 56 57
+              56:               Label
+              64:      9(int)   Load 60(pid)
+                                Store 63(param) 64
+              66:   19(fvec4)   Load 62(pos)
+                                Store 65(param) 66
+              67:23(HS_CONSTANT_OUT)   FunctionCall 27(PCF(u1;vf4;) 63(param) 65(param)
+                                Store 59(@patchConstantResult) 67
+              71:     70(ptr)   AccessChain 59(@patchConstantResult) 32 32
+              72:    6(float)   Load 71
+              74:     73(ptr)   AccessChain 69(@patchConstantOutput_edges) 32
+                                Store 74 72
+              76:     70(ptr)   AccessChain 59(@patchConstantResult) 32 75
+              77:    6(float)   Load 76
+              78:     73(ptr)   AccessChain 69(@patchConstantOutput_edges) 75
+                                Store 78 77
+                                Branch 57
+              57:             Label
+                              Return
+                              FunctionEnd
+16(@main(struct-VS_OUT-vf31[4];):  13(HS_OUT) Function None 14
+          15(ip):     12(ptr) FunctionParameter
+              17:             Label
+      30(output):     29(ptr) Variable Function
+              34:     33(ptr) AccessChain 15(ip) 32 32
+              35:    7(fvec3) Load 34
+              36:     33(ptr) AccessChain 30(output) 32
+                              Store 36 35
+              37:  13(HS_OUT) Load 30(output)
+                              ReturnValue 37
+                              FunctionEnd
+ 27(PCF(u1;vf4;):23(HS_CONSTANT_OUT) Function None 24
+         25(pid):     18(ptr) FunctionParameter
+         26(pos):     20(ptr) FunctionParameter
+              28:             Label
+      79(output):     58(ptr) Variable Function
+              81:     70(ptr) AccessChain 79(output) 32 32
+                              Store 81 80
+              83:     70(ptr) AccessChain 79(output) 32 75
+                              Store 83 82
+              84:23(HS_CONSTANT_OUT) Load 79(output)
+                              ReturnValue 84
+                              FunctionEnd
diff --git a/Test/baseResults/hlsl.hull.void.tesc.out b/Test/baseResults/hlsl.hull.void.tesc.out
new file mode 100644
index 0000000000000000000000000000000000000000..7576fdcea8418b3d4e3149658ea94b508c1b33ee
--- /dev/null
+++ b/Test/baseResults/hlsl.hull.void.tesc.out
@@ -0,0 +1,186 @@
+hlsl.hull.void.tesc
+Shader version: 450
+vertices = 3
+0:? Sequence
+0:26  Function Definition: @main(struct-VS_OUT-vf31[3]; (temp structure{temp 3-component vector of float cpoint})
+0:26    Function Parameters: 
+0:26      'ip' (in 3-element array of structure{temp 3-component vector of float cpoint})
+0:?     Sequence
+0:28      move second child to first child (temp 3-component vector of float)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          'output' (temp structure{temp 3-component vector of float cpoint})
+0:28          Constant:
+0:28            0 (const int)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          direct index (temp structure{temp 3-component vector of float cpoint})
+0:28            'ip' (in 3-element array of structure{temp 3-component vector of float cpoint})
+0:28            Constant:
+0:28              0 (const int)
+0:28          Constant:
+0:28            0 (const int)
+0:29      Branch: Return with expression
+0:29        'output' (temp structure{temp 3-component vector of float cpoint})
+0:26  Function Definition: main( (temp void)
+0:26    Function Parameters: 
+0:?     Sequence
+0:26      move second child to first child (temp 3-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (temp 3-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (layout(location=0 ) in 3-element array of structure{temp 3-component vector of float cpoint})
+0:26      move second child to first child (temp structure{temp 3-component vector of float cpoint})
+0:?         '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:26        Function Call: @main(struct-VS_OUT-vf31[3]; (temp structure{temp 3-component vector of float cpoint})
+0:?           'ip' (temp 3-element array of structure{temp 3-component vector of float cpoint})
+0:?       Barrier (temp void)
+0:?       Test condition and select (temp void)
+0:?         Condition
+0:?         Compare Equal (temp bool)
+0:?           'InvocationId' (in uint InvocationID)
+0:?           Constant:
+0:?             0 (const int)
+0:?         true case
+0:?         Function Call: PCF( (temp void)
+0:33  Function Definition: PCF( (temp void)
+0:33    Function Parameters: 
+0:?   Linker Objects
+0:?     '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:?     'ip' (layout(location=0 ) in 3-element array of structure{temp 3-component vector of float cpoint})
+0:?     'InvocationId' (in uint InvocationID)
+
+
+Linked tessellation control stage:
+
+
+Shader version: 450
+vertices = 3
+0:? Sequence
+0:26  Function Definition: @main(struct-VS_OUT-vf31[3]; (temp structure{temp 3-component vector of float cpoint})
+0:26    Function Parameters: 
+0:26      'ip' (in 3-element array of structure{temp 3-component vector of float cpoint})
+0:?     Sequence
+0:28      move second child to first child (temp 3-component vector of float)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          'output' (temp structure{temp 3-component vector of float cpoint})
+0:28          Constant:
+0:28            0 (const int)
+0:28        cpoint: direct index for structure (temp 3-component vector of float)
+0:28          direct index (temp structure{temp 3-component vector of float cpoint})
+0:28            'ip' (in 3-element array of structure{temp 3-component vector of float cpoint})
+0:28            Constant:
+0:28              0 (const int)
+0:28          Constant:
+0:28            0 (const int)
+0:29      Branch: Return with expression
+0:29        'output' (temp structure{temp 3-component vector of float cpoint})
+0:26  Function Definition: main( (temp void)
+0:26    Function Parameters: 
+0:?     Sequence
+0:26      move second child to first child (temp 3-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (temp 3-element array of structure{temp 3-component vector of float cpoint})
+0:?         'ip' (layout(location=0 ) in 3-element array of structure{temp 3-component vector of float cpoint})
+0:26      move second child to first child (temp structure{temp 3-component vector of float cpoint})
+0:?         '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:26        Function Call: @main(struct-VS_OUT-vf31[3]; (temp structure{temp 3-component vector of float cpoint})
+0:?           'ip' (temp 3-element array of structure{temp 3-component vector of float cpoint})
+0:?       Barrier (temp void)
+0:?       Test condition and select (temp void)
+0:?         Condition
+0:?         Compare Equal (temp bool)
+0:?           'InvocationId' (in uint InvocationID)
+0:?           Constant:
+0:?             0 (const int)
+0:?         true case
+0:?         Function Call: PCF( (temp void)
+0:33  Function Definition: PCF( (temp void)
+0:33    Function Parameters: 
+0:?   Linker Objects
+0:?     '@entryPointOutput' (layout(location=0 ) out structure{temp 3-component vector of float cpoint})
+0:?     'ip' (layout(location=0 ) in 3-element array of structure{temp 3-component vector of float cpoint})
+0:?     'InvocationId' (in uint InvocationID)
+
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 51
+
+                              Capability Tessellation
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint TessellationControl 4  "main" 33 36 44
+                              ExecutionMode 4 OutputVertices 3
+                              Name 4  "main"
+                              Name 8  "VS_OUT"
+                              MemberName 8(VS_OUT) 0  "cpoint"
+                              Name 13  "HS_OUT"
+                              MemberName 13(HS_OUT) 0  "cpoint"
+                              Name 16  "@main(struct-VS_OUT-vf31[3];"
+                              Name 15  "ip"
+                              Name 18  "PCF("
+                              Name 21  "output"
+                              Name 31  "ip"
+                              Name 33  "ip"
+                              Name 36  "@entryPointOutput"
+                              Name 37  "param"
+                              Name 44  "InvocationId"
+                              Decorate 33(ip) Location 0
+                              Decorate 36(@entryPointOutput) Location 0
+                              Decorate 44(InvocationId) BuiltIn InvocationId
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeFloat 32
+               7:             TypeVector 6(float) 3
+       8(VS_OUT):             TypeStruct 7(fvec3)
+               9:             TypeInt 32 0
+              10:      9(int) Constant 3
+              11:             TypeArray 8(VS_OUT) 10
+              12:             TypePointer Function 11
+      13(HS_OUT):             TypeStruct 7(fvec3)
+              14:             TypeFunction 13(HS_OUT) 12(ptr)
+              20:             TypePointer Function 13(HS_OUT)
+              22:             TypeInt 32 1
+              23:     22(int) Constant 0
+              24:             TypePointer Function 7(fvec3)
+              32:             TypePointer Input 11
+          33(ip):     32(ptr) Variable Input
+              35:             TypePointer Output 13(HS_OUT)
+36(@entryPointOutput):     35(ptr) Variable Output
+              40:      9(int) Constant 2
+              41:      9(int) Constant 1
+              42:      9(int) Constant 0
+              43:             TypePointer Input 9(int)
+44(InvocationId):     43(ptr) Variable Input
+              46:             TypeBool
+         4(main):           2 Function None 3
+               5:             Label
+          31(ip):     12(ptr) Variable Function
+       37(param):     12(ptr) Variable Function
+              34:          11 Load 33(ip)
+                              Store 31(ip) 34
+              38:          11 Load 31(ip)
+                              Store 37(param) 38
+              39:  13(HS_OUT) FunctionCall 16(@main(struct-VS_OUT-vf31[3];) 37(param)
+                              Store 36(@entryPointOutput) 39
+                              ControlBarrier 40 41 42
+              45:      9(int) Load 44(InvocationId)
+              47:    46(bool) IEqual 45 23
+                              SelectionMerge 49 None
+                              BranchConditional 47 48 49
+              48:               Label
+              50:           2   FunctionCall 18(PCF()
+                                Branch 49
+              49:             Label
+                              Return
+                              FunctionEnd
+16(@main(struct-VS_OUT-vf31[3];):  13(HS_OUT) Function None 14
+          15(ip):     12(ptr) FunctionParameter
+              17:             Label
+      21(output):     20(ptr) Variable Function
+              25:     24(ptr) AccessChain 15(ip) 23 23
+              26:    7(fvec3) Load 25
+              27:     24(ptr) AccessChain 21(output) 23
+                              Store 27 26
+              28:  13(HS_OUT) Load 21(output)
+                              ReturnValue 28
+                              FunctionEnd
+        18(PCF():           2 Function None 3
+              19:             Label
+                              Return
+                              FunctionEnd
diff --git a/Test/hlsl.hull.1.tesc b/Test/hlsl.hull.1.tesc
new file mode 100644
index 0000000000000000000000000000000000000000..4959b45331470f56414a6150ac4bdd0974e7dcb3
--- /dev/null
+++ b/Test/hlsl.hull.1.tesc
@@ -0,0 +1,39 @@
+// *** 
+// invocation ID coming from input to entry point
+// ***
+
+struct VS_OUT
+{
+    float3 cpoint : CPOINT;
+};
+
+struct HS_CONSTANT_OUT
+{
+    float edges[2] : SV_TessFactor;
+};
+
+struct HS_OUT
+{
+    float3 cpoint : CPOINT;
+};
+
+[domain("isoline")]
+[partitioning("integer")]
+[outputtopology("line")]
+[outputcontrolpoints(4)]
+[patchconstantfunc("PCF")]
+HS_OUT main(InputPatch<VS_OUT, 4> ip, uint m_cpid : SV_OutputControlPointID)
+{
+    HS_OUT output;
+    output.cpoint = ip[0].cpoint;
+    return output;
+}
+
+HS_CONSTANT_OUT PCF(uint pid : SV_PrimitiveId)
+{
+    HS_CONSTANT_OUT output;
+    
+    output.edges[0] = 2.0f;
+    output.edges[1] = 8.0f;
+    return output;
+}
diff --git a/Test/hlsl.hull.2.tesc b/Test/hlsl.hull.2.tesc
new file mode 100644
index 0000000000000000000000000000000000000000..3c0afcc5d669f0472909891d18090ee6fc8a958e
--- /dev/null
+++ b/Test/hlsl.hull.2.tesc
@@ -0,0 +1,39 @@
+// *** 
+// invocation ID coming from synthesized variable
+// ***
+
+struct VS_OUT
+{
+    float3 cpoint : CPOINT;
+};
+
+struct HS_CONSTANT_OUT
+{
+    float edges[2] : SV_TessFactor;
+};
+
+struct HS_OUT
+{
+    float3 cpoint : CPOINT;
+};
+
+[domain("isoline")]
+[partitioning("integer")]
+[outputtopology("line")]
+[outputcontrolpoints(4)]
+[patchconstantfunc("PCF")]
+HS_OUT main(InputPatch<VS_OUT, 4> ip)
+{
+    HS_OUT output;
+    output.cpoint = ip[0].cpoint;
+    return output;
+}
+
+HS_CONSTANT_OUT PCF(uint pid : SV_PrimitiveId, float4 pos : SV_Position)
+{
+    HS_CONSTANT_OUT output;
+    
+    output.edges[0] = 2.0f;
+    output.edges[1] = 8.0f;
+    return output;
+}
diff --git a/Test/hlsl.hull.void.tesc b/Test/hlsl.hull.void.tesc
new file mode 100644
index 0000000000000000000000000000000000000000..971d613bf78ecec2d0e531fd59697a0238f2cb57
--- /dev/null
+++ b/Test/hlsl.hull.void.tesc
@@ -0,0 +1,34 @@
+// *** 
+// void patchconstantfunction input and return
+// ***
+
+struct VS_OUT
+{
+    float3 cpoint : CPOINT;
+};
+
+struct HS_CONSTANT_OUT
+{
+    float edges[2] : SV_TessFactor;
+};
+
+struct HS_OUT
+{
+    float3 cpoint : CPOINT;
+};
+
+[domain("tri")]
+[partitioning("fractional_even")]
+[outputtopology("line")]
+[outputcontrolpoints(3)]
+[patchconstantfunc("PCF")]
+HS_OUT main(InputPatch<VS_OUT, 3> ip)
+{
+    HS_OUT output;
+    output.cpoint = ip[0].cpoint;
+    return output;
+}
+
+void PCF()
+{
+}
diff --git a/glslang/Include/ConstantUnion.h b/glslang/Include/ConstantUnion.h
index b95bc25a0a16e31a23410e273304971b6636b9b9..f66a7ff5192d351ae59942c1de46a4c636266c63 100644
--- a/glslang/Include/ConstantUnion.h
+++ b/glslang/Include/ConstantUnion.h
@@ -81,12 +81,19 @@ public:
         type = EbtBool;
     }
 
+    void setSConst(const TString* s)
+    {
+        sConst = s;
+        type = EbtString;
+    }
+
     int                getIConst() const   { return iConst; }
     unsigned int       getUConst() const   { return uConst; }
     long long          getI64Const() const { return i64Const; }
     unsigned long long getU64Const() const { return u64Const; }
     double             getDConst() const   { return dConst; }
     bool               getBConst() const   { return bConst; }
+    const TString*     getSConst() const   { return sConst; }
 
     bool operator==(const int i) const
     {
@@ -532,6 +539,7 @@ private:
         unsigned long long u64Const;    // used for u64vec, scalar uint64s
         bool               bConst;      // used for bvec, scalar bools
         double             dConst;      // used for vec, dvec, mat, dmat, scalar floats and doubles
+        const TString*     sConst;      // string constant
     };
 
     TBasicType type;
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index 2854235588ddbb09f3a923da42f5e46b71eec7f7..2ebd741eebbec0162f1a752cf3a6dabf1c9f7a83 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -1403,6 +1403,14 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseT
     return addConstantUnion(unionArray, TType(baseType, EvqConst), loc, literal);
 }
 
+TIntermConstantUnion* TIntermediate::addConstantUnion(const TString* s, const TSourceLoc& loc, bool literal) const
+{
+    TConstUnionArray unionArray(1);
+    unionArray[0].setSConst(s);
+
+    return addConstantUnion(unionArray, TType(EbtString, EvqConst), loc, literal);
+}
+
 // Put vector swizzle selectors onto the given sequence
 void TIntermediate::pushSelector(TIntermSequence& sequence, const TVectorSelector& selector, const TSourceLoc& loc)
 {
diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h
index e506e614047138519d4fd0051656d1641c049054..29ee40e15fef51ae2dc39be34fbcb1b3a415a49d 100644
--- a/glslang/MachineIndependent/SymbolTable.h
+++ b/glslang/MachineIndependent/SymbolTable.h
@@ -198,6 +198,7 @@ struct TParameter {
     TString *name;
     TType* type;
     TIntermTyped* defaultValue;
+    TBuiltInVariable declaredBuiltIn;
     void copyParam(const TParameter& param)
     {
         if (param.name)
@@ -206,6 +207,7 @@ struct TParameter {
             name = 0;
         type = param.type->clone();
         defaultValue = param.defaultValue;
+        declaredBuiltIn = param.declaredBuiltIn;
     }
 };
 
@@ -222,7 +224,11 @@ public:
         TSymbol(name),
         mangledName(*name + '('),
         op(tOp),
-        defined(false), prototyped(false), defaultParamCount(0) { returnType.shallowCopy(retType); }
+        defined(false), prototyped(false), defaultParamCount(0)
+    {
+        returnType.shallowCopy(retType);
+        declaredBuiltIn = retType.getQualifier().builtIn;
+    }
     virtual TFunction* clone() const;
     virtual ~TFunction();
 
@@ -232,6 +238,7 @@ public:
     virtual void addParameter(TParameter& p)
     {
         assert(writable);
+        p.declaredBuiltIn = p.type->getQualifier().builtIn;
         parameters.push_back(p);
         p.type->appendMangledName(mangledName);
 
@@ -246,6 +253,7 @@ public:
 
     virtual const TString& getMangledName() const { return mangledName; }
     virtual const TType& getType() const { return returnType; }
+    virtual TBuiltInVariable getDeclaredBuiltInType() const { return declaredBuiltIn; }
     virtual TType& getWritableType() { return returnType; }
     virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
     virtual TOperator getBuiltInOp() const { return op; }
@@ -273,6 +281,8 @@ protected:
     typedef TVector<TParameter> TParamList;
     TParamList parameters;
     TType returnType;
+    TBuiltInVariable declaredBuiltIn;
+
     TString mangledName;
     TOperator op;
     bool defined;
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index 75bd679e3395203504724148e1f5b422fbca7a56..14193f56adcf3a091026833b4c3e386fb585a2e3 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -263,6 +263,7 @@ public:
     TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
     TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
     TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
+    TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp
index 701863ac012915af44b64541b602181764bc0d3d..ed1cb008e3ee423142aa2576dcda257210d9ebfd 100644
--- a/gtests/Hlsl.FromFile.cpp
+++ b/gtests/Hlsl.FromFile.cpp
@@ -119,6 +119,9 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.getdimensions.rw.dx10.frag", "main"},
         {"hlsl.getdimensions.dx10.vert", "main"},
         {"hlsl.getsampleposition.dx10.frag", "main"},
+        {"hlsl.hull.1.tesc", "main"},
+        {"hlsl.hull.2.tesc", "main"},
+        {"hlsl.hull.void.tesc", "main"},
         {"hlsl.identifier.sample.frag", "main"},
         {"hlsl.if.frag", "PixelShaderFunction"},
         {"hlsl.inoutquals.frag", "main"},
diff --git a/hlsl/hlslAttributes.h b/hlsl/hlslAttributes.h
index 820909b19becad036bb30fb408b042ce4fe3b369..5a7c033d45300a4fdc9b6f66788a068201f85741 100644
--- a/hlsl/hlslAttributes.h
+++ b/hlsl/hlslAttributes.h
@@ -60,6 +60,7 @@ namespace glslang {
         EatOutputTopology,
         EatPartitioning,
         EatPatchConstantFunc,
+        EatPatchSize,
         EatUnroll,
     };
 }
diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp
index a454c444d0aa3b5b0ad1867824f836fd7420c784..ea2ae5559a0bd388e5805a5cafd74b3fa4160875 100755
--- a/hlsl/hlslGrammar.cpp
+++ b/hlsl/hlslGrammar.cpp
@@ -869,6 +869,67 @@ bool HlslGrammar::acceptOutputPrimitiveGeometry(TLayoutGeometry& geometry)
     return true;
 }
 
+// tessellation_decl_type
+//      : INPUTPATCH
+//      | OUTPUTPATCH
+//
+bool HlslGrammar::acceptTessellationDeclType()
+{
+    // read geometry type
+    const EHlslTokenClass tessType = peek();
+
+    switch (tessType) {
+    case EHTokInputPatch:    break;
+    case EHTokOutputPatch:   break;
+    default:
+        return false;  // not a tessellation decl
+    }
+
+    advanceToken();  // consume the keyword
+    return true;
+}
+
+// tessellation_patch_template_type
+//      : tessellation_decl_type LEFT_ANGLE type comma integer_literal RIGHT_ANGLE
+//
+bool HlslGrammar::acceptTessellationPatchTemplateType(TType& type)
+{
+    if (! acceptTessellationDeclType())
+        return false;
+    
+    if (! acceptTokenClass(EHTokLeftAngle))
+        return false;
+
+    if (! acceptType(type)) {
+        expected("tessellation patch type");
+        return false;
+    }
+
+    if (! acceptTokenClass(EHTokComma))
+        return false;
+
+    // integer size
+    if (! peekTokenClass(EHTokIntConstant)) {
+        expected("literal integer");
+        return false;
+    }
+
+    TIntermTyped* size;
+    if (! acceptLiteral(size))
+        return false;
+
+    TArraySizes* arraySizes = new TArraySizes;
+    arraySizes->addInnerSize(size->getAsConstantUnion()->getConstArray()[0].getIConst());
+    type.newArraySizes(*arraySizes);
+
+    if (! acceptTokenClass(EHTokRightAngle)) {
+        expected("right angle bracket");
+        return false;
+    }
+
+    return true;
+}
+    
 // stream_out_template_type
 //      : output_primitive_geometry_type LEFT_ANGLE type RIGHT_ANGLE
 //
@@ -1147,6 +1208,15 @@ bool HlslGrammar::acceptType(TType& type)
             return true;
         }
 
+    case EHTokInputPatch:             // fall through
+    case EHTokOutputPatch:            // ...
+        {
+            if (! acceptTessellationPatchTemplateType(type))
+                return false;
+
+            return true;
+        }
+
     case EHTokSampler:                // fall through
     case EHTokSampler1d:              // ...
     case EHTokSampler2d:              // ...
@@ -2522,7 +2592,7 @@ bool HlslGrammar::acceptLiteral(TIntermTyped*& node)
         node = intermediate.addConstantUnion(token.b, token.loc, true);
         break;
     case EHTokStringConstant:
-        node = nullptr;
+        node = intermediate.addConstantUnion(token.string, token.loc, true);
         break;
 
     default:
diff --git a/hlsl/hlslGrammar.h b/hlsl/hlslGrammar.h
index 0629eaae6f27f61ff4b61ca8ec155ee625f89ba5..f98d650cb5e69560260cfcac0cc945e7d47005ce 100755
--- a/hlsl/hlslGrammar.h
+++ b/hlsl/hlslGrammar.h
@@ -76,6 +76,8 @@ namespace glslang {
         bool acceptTemplateVecMatBasicType(TBasicType&);
         bool acceptVectorTemplateType(TType&);
         bool acceptMatrixTemplateType(TType&);
+        bool acceptTessellationDeclType();
+        bool acceptTessellationPatchTemplateType(TType&);
         bool acceptStreamOutTemplateType(TType&, TLayoutGeometry&);
         bool acceptOutputPrimitiveGeometry(TLayoutGeometry&);
         bool acceptAnnotations(TQualifier&);
diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp
index 1a4ae06b1da779cb0474387a909cfc2e27bf2be4..272632ba8246ffc9962c6a726604560fd2fcab77 100755
--- a/hlsl/hlslParseHelper.cpp
+++ b/hlsl/hlslParseHelper.cpp
@@ -48,6 +48,7 @@
 #include <functional>
 #include <cctype>
 #include <array>
+#include <set>
 
 namespace glslang {
 
@@ -63,7 +64,9 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int
     builtInIoIndex(nullptr),
     builtInIoBase(nullptr),
     nextInLocation(0), nextOutLocation(0),
-    sourceEntryPointName(sourceEntryPointName)
+    sourceEntryPointName(sourceEntryPointName),
+    entryPointFunction(nullptr),
+    entryPointFunctionBody(nullptr)
 {
     globalUniformDefaults.clear();
     globalUniformDefaults.layoutMatrix = ElmRowMajor;
@@ -1343,6 +1346,17 @@ TIntermTyped* HlslParseContext::splitAccessStruct(const TSourceLoc& loc, TInterm
     }
 }
 
+// Pass through to base class after remembering builtin mappings.
+void HlslParseContext::trackLinkage(TSymbol& symbol)
+{
+    TBuiltInVariable biType = symbol.getType().getQualifier().builtIn;
+    if (biType != EbvNone)
+        builtInLinkageSymbols[biType] = symbol.clone();
+
+    TParseContextBase::trackLinkage(symbol);
+}
+
+
 // Variables that correspond to the user-interface in and out of a stage
 // (not the built-in interface) are assigned locations and
 // registered as a linkage node (part of the stage's external interface).
@@ -1362,6 +1376,7 @@ void HlslParseContext::assignLocations(TVariable& variable)
                     nextOutLocation += intermediate.computeTypeLocationSize(variable.getType());
                 }
             }
+
             trackLinkage(variable);
         }
     };
@@ -1512,9 +1527,6 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
             if (! symbolTable.insert(*variable))
                 error(loc, "redefinition", variable->getName().c_str(), "");
             else {
-                // Transfer ownership of name pointer to symbol table.
-                param.name = nullptr;
-
                 // Add the parameter to the AST
                 paramNodes = intermediate.growAggregate(paramNodes,
                                                         intermediate.addSymbol(*variable, loc),
@@ -1570,6 +1582,8 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
         return nullptr;
     }
 
+    entryPointFunction = &userFunction; // needed in finish()
+
     // entry point logic...
 
     // Handle entry-point function attributes
@@ -1580,9 +1594,128 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
         for (int lid = 0; lid < int(sequence.size()); ++lid)
             intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
     }
+
+    // MaxVertexCount
     const TIntermAggregate* maxVertexCount = attributes[EatMaxVertexCount];
-    if (maxVertexCount != nullptr)
-        intermediate.setVertices(maxVertexCount->getSequence()[0]->getAsConstantUnion()->getConstArray()[0].getIConst());
+    if (maxVertexCount != nullptr) {
+        if (! intermediate.setVertices(maxVertexCount->getSequence()[0]->getAsConstantUnion()->getConstArray()[0].getIConst())) {
+            error(loc, "cannot change previously set maxvertexcount attribute", "", "");
+        }
+    }
+
+    // Handle [patchconstantfunction("...")]
+    const TIntermAggregate* pcfAttr = attributes[EatPatchConstantFunc]; 
+    if (pcfAttr != nullptr) {
+        const TConstUnion& pcfName = pcfAttr->getSequence()[0]->getAsConstantUnion()->getConstArray()[0];
+
+        if (pcfName.getType() != EbtString) {
+            error(loc, "invalid patch constant function", "", "");
+        } else {
+            patchConstantFunctionName = *pcfName.getSConst();
+        }
+    }
+
+    // Handle [domain("...")]
+    const TIntermAggregate* domainAttr = attributes[EatDomain]; 
+    if (domainAttr != nullptr) {
+        const TConstUnion& domainType = domainAttr->getSequence()[0]->getAsConstantUnion()->getConstArray()[0];
+        if (domainType.getType() != EbtString) {
+            error(loc, "invalid domain", "", "");
+        } else {
+            TString domainStr = *domainType.getSConst();
+            std::transform(domainStr.begin(), domainStr.end(), domainStr.begin(), ::tolower);
+
+            TLayoutGeometry domain = ElgNone;
+
+            if (domainStr == "tri") {
+                domain = ElgTriangles;
+            } else if (domainStr == "quad") {
+                domain = ElgQuads;
+            } else if (domainStr == "isoline") {
+                domain = ElgIsolines;
+            } else {
+                error(loc, "unsupported domain type", domainStr.c_str(), "");
+            }
+
+            if (! intermediate.setInputPrimitive(domain)) {
+                error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+            }
+        }
+    }
+
+    // Handle [outputtoplogy("...")]
+    const TIntermAggregate* topologyAttr = attributes[EatOutputTopology];
+    if (topologyAttr != nullptr) {
+        const TConstUnion& topoType = topologyAttr->getSequence()[0]->getAsConstantUnion()->getConstArray()[0];
+        if (topoType.getType() != EbtString) {
+            error(loc, "invalid outputtoplogy", "", "");
+        } else {
+            TString topologyStr = *topoType.getSConst();
+            std::transform(topologyStr.begin(), topologyStr.end(), topologyStr.begin(), ::tolower);
+
+            TVertexOrder topology = EvoNone;
+                
+            if (topologyStr == "point") {
+                topology = EvoNone;
+            } else if (topologyStr == "line") {
+                topology = EvoNone;
+            } else if (topologyStr == "triangle_cw") {
+                topology = EvoCw;
+            } else if (topologyStr == "triangle_ccw") {
+                topology = EvoCcw;
+            } else {
+                error(loc, "unsupported outputtoplogy type", topologyStr.c_str(), "");
+            }
+
+            if (topology != EvoNone) {
+                if (! intermediate.setVertexOrder(topology)) {
+                    error(loc, "cannot change previously set outputtopology", TQualifier::getVertexOrderString(topology), "");
+                }
+            }
+        }
+    }
+
+    // Handle [partitioning("...")]
+    const TIntermAggregate* partitionAttr = attributes[EatPartitioning]; 
+    if (partitionAttr != nullptr) {
+        const TConstUnion& partType = partitionAttr->getSequence()[0]->getAsConstantUnion()->getConstArray()[0];
+        if (partType.getType() != EbtString) {
+            error(loc, "invalid partitioning", "", "");
+        } else {
+            TString partitionStr = *partType.getSConst();
+            std::transform(partitionStr.begin(), partitionStr.end(), partitionStr.begin(), ::tolower);
+
+            TVertexSpacing partitioning = EvsNone;
+                
+            if (partitionStr == "integer") {
+                partitioning = EvsEqual;
+            } else if (partitionStr == "fractional_even") {
+                partitioning = EvsFractionalEven;
+            } else if (partitionStr == "fractional_odd") {
+                partitioning = EvsFractionalOdd;
+                //} else if (partition == "pow2") { // TODO: currently nothing to map this to.
+            } else {
+                error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
+            }
+
+            if (! intermediate.setVertexSpacing(partitioning))
+                error(loc, "cannot change previously set partitioning", TQualifier::getVertexSpacingString(partitioning), "");
+        }
+    }
+
+    // Handle [outputcontrolpoints("...")]
+    const TIntermAggregate* outputControlPoints = attributes[EatOutputControlPoints]; 
+    if (outputControlPoints != nullptr) {
+        const TConstUnion& ctrlPointConst = outputControlPoints->getSequence()[0]->getAsConstantUnion()->getConstArray()[0];
+        if (ctrlPointConst.getType() != EbtInt) {
+            error(loc, "invalid outputcontrolpoints", "", "");
+        } else {
+            const int ctrlPoints = ctrlPointConst.getIConst();
+            if (! intermediate.setVertices(ctrlPoints)) {
+                error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
+            }
+        }
+    }
 
     // Move parameters and return value to shader in/out
     TVariable* entryPointOutput; // gets created in remapEntryPointIO
@@ -1675,6 +1808,8 @@ TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunct
     TIntermNode* synthFunctionDef = synthParams;
     handleFunctionBody(loc, synthEntryPoint, synthBody, synthFunctionDef);
 
+    entryPointFunctionBody = synthBody;
+
     return synthFunctionDef;
 }
 
@@ -1920,6 +2055,8 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
 
             // array case
             for (int element=0; element < left->getType().getOuterArraySize(); ++element) {
+                arrayElement.push_back(element);
+
                 // Add a new AST symbol node if we have a temp variable holding a complex RHS.
                 TIntermTyped* subLeft  = getMember(true,  left,  element, left, element);
                 TIntermTyped* subRight = getMember(false, right, element, right, element);
@@ -1927,8 +2064,6 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op
                 TIntermTyped* subSplitLeft =  isSplitLeft  ? getMember(true,  left,  element, splitLeft, element) : subLeft;
                 TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right, element, splitRight, element) : subRight; 
 
-                arrayElement.push_back(element);
-
                 if (isFinalFlattening(dereferencedType))
                     assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc);
                 else
@@ -6787,9 +6922,282 @@ void HlslParseContext::clearUniformInputOutput(TQualifier& qualifier)
     correctUniform(qualifier);
 }
 
+// Add patch constant function invocation
+void HlslParseContext::addPatchConstantInvocation()
+{
+    TSourceLoc loc;
+    loc.init();
+
+    // If there's no patch constant function, or we're not a HS, do nothing.
+    if (patchConstantFunctionName.empty() || language != EShLangTessControl)
+        return;
+
+    if (symbolTable.isFunctionNameVariable(patchConstantFunctionName)) {
+        error(loc, "can't use variable in patch constant function", patchConstantFunctionName.c_str(), "");
+        return;
+    }
+
+    const TString mangledName = patchConstantFunctionName + "(";
+
+    // create list of PCF candidates
+    TVector<const TFunction*> candidateList;
+    bool builtIn;
+    symbolTable.findFunctionNameList(mangledName, candidateList, builtIn);
+    
+    // We have to have one and only one, or we don't know which to pick: the patchconstantfunc does not
+    // allow any disambiguation of overloads.
+    if (candidateList.empty()) {
+        error(loc, "patch constant function not found", patchConstantFunctionName.c_str(), "");
+        return;
+    }
+
+    // Based on directed experiments, it appears that if there are overloaded patchconstantfunctions,
+    // HLSL picks the last one in shader source order.  Since that isn't yet implemented here, error
+    // out if there is more than one candidate.
+    if (candidateList.size() > 1) {
+        error(loc, "ambiguous patch constant function", patchConstantFunctionName.c_str(), "");
+        return;
+    }
+
+    // Look for builtin variables in a function's parameter list.
+    const auto findBuiltIns = [&](const TFunction& function, std::set<tInterstageIoData>& builtIns) {
+        for (int p=0; p<function.getParamCount(); ++p) {
+            const TStorageQualifier storage = function[p].type->getQualifier().storage;
+
+            if (function[p].declaredBuiltIn != EbvNone)
+                builtIns.insert(tInterstageIoData(function[p].declaredBuiltIn, storage));
+            else
+                builtIns.insert(tInterstageIoData(function[p].type->getQualifier().builtIn, storage));
+        }
+    };
+
+
+    // If we synthesize a builtin interface variable, we must add it to the linkage.
+    const auto addToLinkage = [&](const TType& type, const TString* name, TIntermSymbol** symbolNode) {
+        if (name == nullptr) {
+            error(loc, "unable to locate patch function parameter name", "", "");
+            return;
+        } else {
+            TVariable& variable = *new TVariable(name, type);
+            if (! symbolTable.insert(variable)) {
+                error(loc, "unable to declare patch constant function interface variable", name->c_str(), "");
+                return;
+            }
+
+            globalQualifierFix(loc, variable.getWritableType().getQualifier());
+
+            if (symbolNode != nullptr)
+                *symbolNode = intermediate.addSymbol(variable);
+
+            trackLinkage(variable);
+        }
+    };
+
+    // Return a symbol for the linkage variable of the given TBuiltInVariable type
+    const auto findLinkageSymbol = [this](TBuiltInVariable biType) -> TIntermSymbol* {
+        const auto it = builtInLinkageSymbols.find(biType);
+        if (it == builtInLinkageSymbols.end())  // if it wasn't declared by the user, return nullptr
+            return nullptr;
+
+        return intermediate.addSymbol(*it->second->getAsVariable());
+    };
+    
+    // We will perform these steps.  Each is in a scoped block for separation: they could
+    // become separate functions to make addPatchConstantInvocation shorter.
+    // 
+    // 1. Union the interfaces, and create builtins for anything present in the PCF and
+    //    declared as a builtin variable that isn't present in the entry point's signature.
+    //
+    // 2. Synthesizes a call to the patchconstfunction using builtin variables from either main,
+    //    or the ones we created.  Matching is based on builtin type.  We may use synthesized
+    //    variables from (1) above.
+    //
+    // 3. Create a return sequence: copy the return value (if any) from the PCF to a
+    //    (non-sanitized) output variable.  In case this may involve multiple copies, such as for
+    //    an arrayed variable, a temporary copy of the PCF output is created to avoid multiple
+    //    indirections into a complex R-value coming from the call to the PCF.
+    //
+    // 4. Add a barrier to the end of the entry point body
+    //
+    // 5. Call the PCF inside an if test for (invocation id == 0).
+
+    TFunction& patchConstantFunction = const_cast<TFunction&>(*candidateList[0]);
+    const int pcfParamCount = patchConstantFunction.getParamCount();
+    TIntermSymbol* invocationIdSym = findLinkageSymbol(EbvInvocationId);
+    TIntermSequence& epBodySeq = entryPointFunctionBody->getAsAggregate()->getSequence();
+
+    // ================ Step 1A: Union Interfaces ================
+    // Our patch constant function.
+    {
+        std::set<tInterstageIoData> pcfBuiltIns;  // patch constant function builtins
+        std::set<tInterstageIoData> epfBuiltIns;  // entry point function builtins
+
+        assert(entryPointFunction);
+        assert(entryPointFunctionBody);
+
+        findBuiltIns(patchConstantFunction, pcfBuiltIns);
+        findBuiltIns(*entryPointFunction,   epfBuiltIns);
+
+        // Patchconstantfunction can contain only builtin qualified variables.  (Technically, only HS inputs,
+        // but this test is less assertive than that).
+
+        for (auto bi = pcfBuiltIns.begin(); bi != pcfBuiltIns.end(); ++bi) {
+            if (bi->builtIn == EbvNone) {
+                error(loc, "patch constant function invalid parameter", "", "");
+                return;
+            }
+        }
+
+        // Find the set of builtins in the PCF that are not present in the entry point.
+        std::set<tInterstageIoData> notInEntryPoint;
+
+        notInEntryPoint = pcfBuiltIns;
+
+        for (auto bi : epfBuiltIns) // std::set_difference not usable on unordered containers
+            notInEntryPoint.erase(bi);
+
+        // Now we'll add those to the entry and to the linkage.
+        for (int p=0; p<pcfParamCount; ++p) {
+            TType* paramType = patchConstantFunction[p].type->clone();
+            const TBuiltInVariable biType   = patchConstantFunction[p].declaredBuiltIn;
+            const TStorageQualifier storage = patchConstantFunction[p].type->getQualifier().storage;
+
+            // Use the original declaration type for the linkage
+            paramType->getQualifier().builtIn = biType;
+
+            if (notInEntryPoint.count(tInterstageIoData(biType, storage)) == 1)
+                addToLinkage(*paramType, patchConstantFunction[p].name, nullptr);
+        }
+
+        // If we didn't find it because the shader made one, add our own.
+        if (invocationIdSym == nullptr) {
+            TType invocationIdType(EbtUint, EvqIn, 1);
+            TString* invocationIdName = NewPoolTString("InvocationId");
+            invocationIdType.getQualifier().builtIn = EbvInvocationId;
+            addToLinkage(invocationIdType, invocationIdName, &invocationIdSym);
+        }
+
+        assert(invocationIdSym);
+    }
+
+    TIntermTyped* pcfArguments = nullptr;
+
+    // ================ Step 1B: Argument synthesis ================
+    // Create pcfArguments for synthesis of patchconstantfunction invocation
+    // TODO: handle struct or array inputs
+    {
+        for (int p=0; p<pcfParamCount; ++p) {
+            if (patchConstantFunction[p].type->isArray() ||
+                patchConstantFunction[p].type->isStruct()) {
+                error(loc, "unimplemented array or variable in patch constant function signature", "", "");
+                return;
+            }
+        
+            // find which builtin it is
+            const TBuiltInVariable biType = patchConstantFunction[p].declaredBuiltIn;
+
+            TIntermSymbol* builtIn = findLinkageSymbol(biType);
+        
+            if (builtIn == nullptr) {
+                error(loc, "unable to find patch constant function builtin variable", "", "");
+                return;
+            }
+
+            if (pcfParamCount == 1)
+                pcfArguments = builtIn;
+            else
+                pcfArguments = intermediate.growAggregate(pcfArguments, builtIn);
+        }
+    }
+
+    // ================ Step 2: Synthesize call to PCF ================
+    TIntermTyped* pcfCall = nullptr;
+
+    {
+        // Create a function call to the patchconstantfunction
+        if (pcfArguments)
+            addInputArgumentConversions(patchConstantFunction, pcfArguments);
+
+        // Synthetic call.
+        pcfCall = intermediate.setAggregateOperator(pcfArguments, EOpFunctionCall, patchConstantFunction.getType(), loc);
+        pcfCall->getAsAggregate()->setUserDefined();
+        pcfCall->getAsAggregate()->setName(patchConstantFunction.getMangledName());
+        intermediate.addToCallGraph(infoSink, entryPointFunction->getMangledName(), patchConstantFunction.getMangledName());
+
+        if (pcfCall->getAsAggregate()) {
+            TQualifierList& qualifierList = pcfCall->getAsAggregate()->getQualifierList();
+            for (int i = 0; i < patchConstantFunction.getParamCount(); ++i) {
+                TStorageQualifier qual = patchConstantFunction[i].type->getQualifier().storage;
+                qualifierList.push_back(qual);
+            }
+            pcfCall = addOutputArgumentConversions(patchConstantFunction, *pcfCall->getAsOperator());
+        }
+    }
+
+    // ================ Step 3: Create return Sequence ================
+    // Return sequence: copy PCF result to a temporary, then to shader output variable.
+    if (pcfCall->getBasicType() != EbtVoid) {
+        const TType* retType = &patchConstantFunction.getType();  // return type from the PCF
+        TType outType; // output type that goes with the return type.
+        outType.shallowCopy(*retType);
+
+        // substitute the output type
+        const auto newLists = ioTypeMap.find(retType->getStruct());
+        if (newLists != ioTypeMap.end())
+            outType.setStruct(newLists->second.output);
+
+        // Substitute the top level type's builtin type
+        if (patchConstantFunction.getDeclaredBuiltInType() != EbvNone)
+            outType.getQualifier().builtIn = patchConstantFunction.getDeclaredBuiltInType();
+
+        TVariable* pcfOutput = makeInternalVariable("@patchConstantOutput", outType);
+        pcfOutput->getWritableType().getQualifier().storage = EvqVaryingOut;
+
+        if (pcfOutput->getType().containsBuiltInInterstageIO(language))
+            split(*pcfOutput);
+
+        TIntermSymbol* pcfOutputSym = intermediate.addSymbol(*pcfOutput, loc);
+
+        // The call to the PCF is a complex R-value: we want to store it in a temp to avoid
+        // repeated calls to the PCF:
+        TVariable* pcfCallResult = makeInternalVariable("@patchConstantResult", *retType);
+        pcfCallResult->getWritableType().getQualifier().makeTemporary();
+        TIntermSymbol* pcfResultVar = intermediate.addSymbol(*pcfCallResult, loc);
+        // sanitizeType(&pcfCall->getWritableType());
+        TIntermNode* pcfResultAssign = intermediate.addAssign(EOpAssign, pcfResultVar, pcfCall, loc);
+
+        TIntermNode* pcfResultToOut = handleAssign(loc, EOpAssign, pcfOutputSym, intermediate.addSymbol(*pcfCallResult, loc));
+
+        TIntermTyped* pcfAggregate = nullptr;
+        pcfAggregate = intermediate.growAggregate(pcfAggregate, pcfResultAssign);
+        pcfAggregate = intermediate.growAggregate(pcfAggregate, pcfResultToOut);
+        pcfAggregate = intermediate.setAggregateOperator(pcfAggregate, EOpSequence, *retType, loc);
+
+        pcfCall = pcfAggregate;
+    }
+
+    // ================ Step 4: Barrier ================    
+    TIntermTyped* barrier = new TIntermAggregate(EOpBarrier);
+    barrier->setLoc(loc);
+    barrier->setType(TType(EbtVoid));
+    epBodySeq.insert(epBodySeq.end(), barrier);
+
+    // ================ Step 5: Test on invocation ID ================    
+    TIntermTyped* zero = intermediate.addConstantUnion(0, loc, true);
+    TIntermTyped* cmp =  intermediate.addBinaryNode(EOpEqual, invocationIdSym, zero, loc, TType(EbtBool));
+
+    // Create if statement
+    TIntermTyped* invocationIdTest = new TIntermSelection(cmp, pcfCall, nullptr);
+    invocationIdTest->setLoc(loc);
+
+    // add our test sequence before the return.
+    epBodySeq.insert(epBodySeq.end(), invocationIdTest);
+}
+
 // post-processing
 void HlslParseContext::finish()
 {
+    addPatchConstantInvocation();
     addInterstageIoToLinkage();
 
     TParseContextBase::finish();
diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h
index 6aec72b16124bc0f1e8cb9eb574e2585c24a4684..fa1cbf470559900c2b3c02e3ea14e1c65cdd1156 100755
--- a/hlsl/hlslParseHelper.h
+++ b/hlsl/hlslParseHelper.h
@@ -225,6 +225,7 @@ protected:
     TVariable* getSplitIoVar(const TVariable* var) const;
     TVariable* getSplitIoVar(int id) const;
     void addInterstageIoToLinkage();
+    void addPatchConstantInvocation();
 
     void flatten(const TSourceLoc& loc, const TVariable& variable);
     int flatten(const TSourceLoc& loc, const TVariable& variable, const TType&, TFlattenData&, TString name);
@@ -242,6 +243,10 @@ protected:
     void correctUniform(TQualifier& qualifier);
     void clearUniformInputOutput(TQualifier& qualifier);
 
+    // Pass through to base class after remembering builtin mappings.
+    using TParseContextBase::trackLinkage;
+    void trackLinkage(TSymbol& variable) override;
+
     void finish() override; // post-processing
 
     // Current state of parsing
@@ -324,6 +329,9 @@ protected:
     // can build the linkage correctly if position appears on both sides.  Otherwise, multiple positions
     // are considered identical.
     struct tInterstageIoData {
+        tInterstageIoData(TBuiltInVariable bi, TStorageQualifier q) :
+            builtIn(bi), storage(q) { }
+
         tInterstageIoData(const TType& memberType, const TType& storageType) :
             builtIn(memberType.getQualifier().builtIn),
             storage(storageType.getQualifier().storage) { }
@@ -348,7 +356,13 @@ protected:
     unsigned int nextInLocation;
     unsigned int nextOutLocation;
 
-    TString sourceEntryPointName;
+    TString    sourceEntryPointName;
+    TFunction* entryPointFunction;
+    TIntermNode* entryPointFunctionBody;
+
+    TString patchConstantFunctionName; // hull shader patch constant function name, from function level attribute.
+    TMap<TBuiltInVariable, TSymbol*> builtInLinkageSymbols; // used for tessellation, finding declared builtins
+
 };
 
 } // end namespace glslang
diff --git a/hlsl/hlslScanContext.cpp b/hlsl/hlslScanContext.cpp
index 69c1e37f8690d22dce73ac9a4cb422af6513a05f..7fe8ca262a8d642c924148bd5b115bee5a795184 100755
--- a/hlsl/hlslScanContext.cpp
+++ b/hlsl/hlslScanContext.cpp
@@ -129,6 +129,9 @@ void HlslScanContext::fillInKeywordMap()
     (*KeywordMap)["LineStream"] =              EHTokLineStream;
     (*KeywordMap)["TriangleStream"] =          EHTokTriangleStream;
 
+    (*KeywordMap)["InputPatch"] =              EHTokInputPatch;
+    (*KeywordMap)["OutputPatch"] =             EHTokOutputPatch;
+
     (*KeywordMap)["Buffer"] =                  EHTokBuffer;
     (*KeywordMap)["vector"] =                  EHTokVector;
     (*KeywordMap)["matrix"] =                  EHTokMatrix;
@@ -540,6 +543,11 @@ EHlslTokenClass HlslScanContext::tokenizeIdentifier()
     case EHTokTriangleStream:
         return keyword;
 
+    // Tessellation patches
+    case EHTokInputPatch:
+    case EHTokOutputPatch:
+        return keyword;
+
     case EHTokBuffer:
     case EHTokVector:
     case EHTokMatrix:
diff --git a/hlsl/hlslTokens.h b/hlsl/hlslTokens.h
index ae267705e251af393347d4efb41031588664b20a..95b3826ed9f2522c9142cef0415a0a8bdded81fd 100755
--- a/hlsl/hlslTokens.h
+++ b/hlsl/hlslTokens.h
@@ -78,6 +78,10 @@ enum EHlslTokenClass {
     EHTokLineStream,
     EHTokTriangleStream,
 
+    // Tessellation patches
+    EHTokInputPatch,
+    EHTokOutputPatch,
+
     // template types
     EHTokBuffer,
     EHTokVector,