diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 4fce3ed2be90e26e87e178082fd33a1e5f0603f8..a797295e9345d5c1e960e10a63e688b0ca78eb4a 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -105,6 +105,7 @@ void GenerateResources(TBuiltInResource& resources)
     resources.maxVaryingVectors = 8;
     resources.maxFragmentUniformVectors = 16;
     resources.maxVertexOutputVectors = 16;
+    resources.maxFragmentInputVectors = 15;
     resources.minProgramTexelOffset = -8;
     resources.maxProgramTexelOffset = 7;
 }
diff --git a/Test/300.vert b/Test/300.vert
new file mode 100644
index 0000000000000000000000000000000000000000..96b55d0a0b8f9d72b9d9784fae165403894d1e45
--- /dev/null
+++ b/Test/300.vert
@@ -0,0 +1,31 @@
+#version 300 es
+
+uniform mat4x3 m43;
+uniform mat3x3 m33;
+uniform mat4x4 m44;
+
+in vec3 v3;
+in vec2 v2;
+
+void main()
+{
+    int id = gl_VertexID + gl_InstanceID;
+
+    int c0 = gl_MaxVertexAttribs;
+    int c1 = gl_MaxVertexUniformVectors;
+    int c2 = gl_MaxVertexOutputVectors;
+    int c3 = gl_MaxFragmentInputVectors;
+    int c4 = gl_MaxVertexTextureImageUnits;
+    int c5 = gl_MaxCombinedTextureImageUnits;
+    int c6 = gl_MaxTextureImageUnits;
+    int c7 = gl_MaxFragmentUniformVectors;
+    int c8 = gl_MaxDrawBuffers;
+    int c9 = gl_MinProgramTexelOffset;
+    int c10 = gl_MaxProgramTexelOffset;
+
+    mat3x4 tm = transpose(m43);
+    highp float dm = determinant(m44);
+    mat3x3 im = inverse(m33);
+
+    mat3x2 op = outerProduct(v2, v3);
+}
diff --git a/Test/testlist b/Test/testlist
index 7a2be1bff7168d10c53eb55bc927c3ffd5233afb..fafa6bb58b4acc81ba125d300b6359ee5db9b5ed 100644
--- a/Test/testlist
+++ b/Test/testlist
@@ -20,3 +20,4 @@ pointCoord.frag
 array.frag
 array100.frag
 comment.frag
+300.vert
diff --git a/glslang/Include/ResourceLimits.h b/glslang/Include/ResourceLimits.h
index faf61268111125c7b167277802441a1483badd19..bc60592ead211f5968128bd38d0f83d824696c66 100644
--- a/glslang/Include/ResourceLimits.h
+++ b/glslang/Include/ResourceLimits.h
@@ -54,6 +54,7 @@ struct TBuiltInResource {
     int maxVaryingVectors;
     int maxFragmentUniformVectors;
     int maxVertexOutputVectors;
+    int maxFragmentInputVectors;
     int minProgramTexelOffset;
     int maxProgramTexelOffset;
 };
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index 72825f2f31c32c97034017353f0f53f18185b665..7b9b981fb9affaa1d1b8a516966f11fdc42ff143 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -169,6 +169,10 @@ enum TOperator {
     EOpFwidth,          // Fragment only
 
     EOpMatrixTimesMatrix,
+    EOpOuterProduct,
+    EOpDeterminant,
+    EOpMatrixInverse,
+    EOpTranspose,
 
     EOpAny,
     EOpAll,
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index 41b356f4f7b8bb102c390475b137528a8effd872..5dac7c1e9f4852087bd8644f987e12c08724b31a 100644
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -283,6 +283,38 @@ void TBuiltIns::initialize(int version, EProfile profile)
         s.append(TString("mat3 matrixCompMult(mat3 x, mat3 y);"));
         s.append(TString("mat4 matrixCompMult(mat4 x, mat4 y);"));
 
+        if (version >= 120) {
+            s.append(TString("mat2   outerProduct(vec2 c, vec2 r);"));
+            s.append(TString("mat3   outerProduct(vec3 c, vec3 r);"));
+            s.append(TString("mat4   outerProduct(vec4 c, vec4 r);"));
+            s.append(TString("mat2x3 outerProduct(vec3 c, vec2 r);"));
+            s.append(TString("mat3x2 outerProduct(vec2 c, vec3 r);"));
+            s.append(TString("mat2x4 outerProduct(vec4 c, vec2 r);"));
+            s.append(TString("mat4x2 outerProduct(vec2 c, vec4 r);"));
+            s.append(TString("mat3x4 outerProduct(vec4 c, vec3 r);"));
+            s.append(TString("mat4x3 outerProduct(vec3 c, vec4 r);"));
+
+            s.append(TString("mat2   transpose(mat2   m);"));
+            s.append(TString("mat3   transpose(mat3   m);"));
+            s.append(TString("mat4   transpose(mat4   m);"));
+            s.append(TString("mat2x3 transpose(mat3x2 m);"));
+            s.append(TString("mat3x2 transpose(mat2x3 m);"));
+            s.append(TString("mat2x4 transpose(mat4x2 m);"));
+            s.append(TString("mat4x2 transpose(mat2x4 m);"));
+            s.append(TString("mat3x4 transpose(mat4x3 m);"));
+            s.append(TString("mat4x3 transpose(mat3x4 m);"));
+
+            if (version >= 150) {
+                s.append(TString("float determinant(mat2 m);"));
+                s.append(TString("float determinant(mat3 m);"));
+                s.append(TString("float determinant(mat4 m);"));
+                
+                s.append(TString("mat2 inverse(mat2 m);"));
+                s.append(TString("mat3 inverse(mat3 m);"));
+                s.append(TString("mat4 inverse(mat4 m);"));
+            }
+        }
+
         //
         // Vector relational functions.
         //
@@ -795,6 +827,9 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf
                 snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxVertexOutputVectors = %d;", resources.maxVertexOutputVectors);
                 s.append(TString(builtInConstant));
 
+                snprintf(builtInConstant, maxSize, "const mediump int  gl_MaxFragmentInputVectors = %d;", resources.maxFragmentInputVectors);
+                s.append(TString(builtInConstant));
+
                 snprintf(builtInConstant, maxSize, "const mediump int  gl_MinProgramTexelOffset = %d;", resources.minProgramTexelOffset);
                 s.append(TString(builtInConstant));
                 
@@ -964,6 +999,15 @@ void IdentifyBuiltIns(int version, EProfile profile, EShLanguage language, TSymb
     symbolTable.relateToOperator("not",              EOpVectorLogicalNot);
 
     symbolTable.relateToOperator("matrixCompMult",   EOpMul);
+    if (version >= 120) {
+        symbolTable.relateToOperator("outerProduct", EOpOuterProduct);
+        symbolTable.relateToOperator("transpose", EOpTranspose);
+        if (version >= 150) {
+            symbolTable.relateToOperator("determinant", EOpDeterminant);                
+            symbolTable.relateToOperator("inverse", EOpMatrixInverse);
+        }
+    }
+
     symbolTable.relateToOperator("mod",              EOpMod);
 
     symbolTable.relateToOperator("equal",            EOpVectorEqual);
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index d13f09948d5554f8d48676225315c5cdd4a4a260..551454c5e50c8d99757371e09c34910e82d6bcb9 100644
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -1202,6 +1202,18 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNod
             }
             returnType = TType(getType().getBasicType(), EvqConst, 0, getMatrixRows(), node->getMatrixCols());
             break;
+        case EOpOuterProduct:
+            // TODO: functionality >= 120
+            break;
+        case EOpDeterminant:
+            // TODO: functionality >= 150
+            break;
+        case EOpMatrixInverse:
+            // TODO: functionality >= 150
+            break;
+        case EOpTranspose:
+            // TODO: functionality >= 120
+            break;
         case EOpDiv: 
             tempConstArray = new constUnion[objectSize];
             for (int i = 0; i < objectSize; i++) {
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 0d4fc27f27e8492ab96afc00923b35d20f434413..556c0ac5738c94e49065ce7316cb3112faa24507 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -46,7 +46,7 @@
 //
 
 //
-// Use this class to carry along data from node to node in 
+// Use this class to carry along data from node to node in
 // the traversal
 //
 class TOutputTraverser : public TIntermTraverser {
@@ -80,7 +80,7 @@ TString TType::getCompleteString() const
     snprintf(p, end - p, "%s", getBasicString());
 
     return TString(buf);
-}   
+}
 
 //
 // Helper functions for printing, not part of traversing.
@@ -91,7 +91,7 @@ void OutputTreeText(TInfoSink& infoSink, TIntermNode* node, const int depth)
     int i;
 
     infoSink.debug << FormatSourceLoc(node->getLine());
-    
+
     for (i = 0; i < depth; ++i)
         infoSink.debug << "  ";
 }
@@ -135,7 +135,7 @@ bool OutputBinary(bool /* preVisit */, TIntermBinary* node, TIntermTraverser* it
     case EOpVectorTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
     case EOpVectorTimesScalarAssign:  out.debug << "vector scale second child into first child"; break;
     case EOpMatrixTimesScalarAssign:  out.debug << "matrix scale second child into first child"; break;
-    case EOpMatrixTimesMatrixAssign:  out.debug << "matrix mult second child into first child"; break;
+    case EOpMatrixTimesMatrixAssign:  out.debug << "matrix mult second child into first child";  break;
     case EOpDivAssign:                out.debug << "divide second child into first child";       break;
     case EOpModAssign:                out.debug << "mod second child into first child";          break;
     case EOpAndAssign:                out.debug << "and second child into first child";          break;
@@ -192,7 +192,7 @@ bool OutputUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
 
     OutputTreeText(out, node, oit->depth);
 
-    switch (node->getOp()) {        
+    switch (node->getOp()) {
     case EOpNegative:       out.debug << "Negate value";         break;
     case EOpVectorLogicalNot:
     case EOpLogicalNot:     out.debug << "Negate conditional";   break;
@@ -234,10 +234,13 @@ bool OutputUnary(bool /* preVisit */, TIntermUnary* node, TIntermTraverser* it)
 
     case EOpLength:         out.debug << "length";               break;
     case EOpNormalize:      out.debug << "normalize";            break;
-    case EOpDPdx:           out.debug << "dPdx";                 break;               
-    case EOpDPdy:           out.debug << "dPdy";                 break;   
-    case EOpFwidth:         out.debug << "fwidth";               break;                   
-    
+    case EOpDPdx:           out.debug << "dPdx";                 break;
+    case EOpDPdy:           out.debug << "dPdy";                 break;
+    case EOpFwidth:         out.debug << "fwidth";               break;
+    case EOpDeterminant:    out.debug << "determinant";          break;
+    case EOpMatrixInverse:  out.debug << "inverse";              break;
+    case EOpTranspose:      out.debug << "transpose";            break;
+
     case EOpAny:            out.debug << "any";                  break;
     case EOpAll:            out.debug << "all";                  break;
 
@@ -269,7 +272,7 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers
     case EOpFunction:      out.debug << "Function Definition: " << node->getName(); break;
     case EOpFunctionCall:  out.debug << "Function Call: "       << node->getName(); break;
     case EOpParameters:    out.debug << "Function Parameters: ";                    break;
-    
+
     case EOpConstructFloat: out.debug << "Construct float"; break;
     case EOpConstructVec2:  out.debug << "Construct vec2";  break;
     case EOpConstructVec3:  out.debug << "Construct vec3";  break;
@@ -301,7 +304,7 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers
     case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
     case EOpConstructDMat4x4: out.debug << "Construct dmat4";  break;
     case EOpConstructStruct:  out.debug << "Construct structure";  break;
-        
+
     case EOpLessThan:         out.debug << "Compare Less Than";             break;
     case EOpGreaterThan:      out.debug << "Compare Greater Than";          break;
     case EOpLessThanEqual:    out.debug << "Compare Less Than or Equal";    break;
@@ -328,13 +331,14 @@ bool OutputAggregate(bool /* preVisit */, TIntermAggregate* node, TIntermTravers
     case EOpReflect:       out.debug << "reflect";                 break;
     case EOpRefract:       out.debug << "refract";                 break;
     case EOpMul:           out.debug << "component-wise multiply"; break;
+    case EOpOuterProduct:  out.debug << "outer product";           break;
 
     default: out.debug.message(EPrefixError, "Bad aggregation op");
     }
 
     if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
         out.debug << " (" << node->getCompleteString() << ")";
-    
+
     out.debug << "\n";
 
     return true;
@@ -349,9 +353,9 @@ bool OutputSelection(bool /* preVisit */, TIntermSelection* node, TIntermTravers
 
     out.debug << "Test condition and select";
     out.debug << " (" << node->getCompleteString() << ")\n";
-    
+
     ++oit->depth;
-    
+
     OutputTreeText(oit->infoSink, node, oit->depth);
     out.debug << "Condition\n";
     node->getCondition()->traverse(it);
@@ -362,13 +366,13 @@ bool OutputSelection(bool /* preVisit */, TIntermSelection* node, TIntermTravers
 		node->getTrueBlock()->traverse(it);
 	} else
 		out.debug << "true case is null\n";
-    
+
     if (node->getFalseBlock()) {
         OutputTreeText(oit->infoSink, node, oit->depth);
         out.debug << "false case\n";
         node->getFalseBlock()->traverse(it);
     }
-    
+
     --oit->depth;
 
     return false;
@@ -378,7 +382,7 @@ void OutputConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
 {
     TOutputTraverser* oit = static_cast<TOutputTraverser*>(it);
     TInfoSink& out = oit->infoSink;
-    
+
     int size = node->getType().getObjectSize();
 
     for (int i = 0; i < size; i++) {
@@ -400,7 +404,7 @@ void OutputConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
                 char buf[maxSize];
                 snprintf(buf, maxSize, "%f (%s)", node->getUnionArrayPointer()[i].getFConst(), "const float");
 
-                out.debug << buf << "\n";           
+                out.debug << buf << "\n";
             }
             break;
         case EbtDouble:
@@ -409,7 +413,7 @@ void OutputConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
                 char buf[maxSize];
                 snprintf(buf, maxSize, "%f (%s)", node->getUnionArrayPointer()[i].getDConst(), "const double");
 
-                out.debug << buf << "\n";           
+                out.debug << buf << "\n";
             }
             break;
         case EbtInt:
@@ -421,7 +425,7 @@ void OutputConstantUnion(TIntermConstantUnion* node, TIntermTraverser* it)
                 out.debug << buf << "\n";
             }
             break;
-        default: 
+        default:
             out.info.message(EPrefixInternalError, "Unknown constant", node->getLine());
             break;
         }
@@ -434,21 +438,21 @@ bool OutputLoop(bool /* preVisit */, TIntermLoop* node, TIntermTraverser* it)
     TInfoSink& out = oit->infoSink;
 
     OutputTreeText(out, node, oit->depth);
-    
+
     out.debug << "Loop with condition ";
     if (! node->testFirst())
         out.debug << "not ";
     out.debug << "tested first\n";
-    
+
     ++oit->depth;
-    
+
     OutputTreeText(oit->infoSink, node, oit->depth);
     if (node->getTest()) {
         out.debug << "Loop Condition\n";
         node->getTest()->traverse(it);
     } else
         out.debug << "No loop condition\n";
-    
+
     OutputTreeText(oit->infoSink, node, oit->depth);
     if (node->getBody()) {
         out.debug << "Loop Body\n";