diff --git a/Test/300.frag b/Test/300.frag
index 6fa7e336f453649858a8c769fe43389de550a86d..dea0c4e72ddbe18acfd9e461240b27d1ab7a914e 100644
--- a/Test/300.frag
+++ b/Test/300.frag
@@ -133,6 +133,16 @@ void foo324(void)
 {
     float p = pow(3.2, 4.6);
     p += sin(0.4);
+    p += distance(vec2(10.0, 11.0), vec2(13.0, 15.0)); // 5
+    p += dot(vec3(2,3,5), vec3(-2,-1,4));              // 13
+    vec3 c3 = cross(vec3(3,-3,1), vec3(4,9,2));        // (-15, -2, 39)
+    c3 += faceforward(vec3(1,2,3), vec3(2,3,5), vec3(-2,-1,4));     // (-1,-2,-3)
+    c3 += faceforward(vec3(1,2,3), vec3(-2,-3,-5), vec3(-2,-1,4));  // (1,2,3)
+    vec2 c2 = reflect(vec2(1,3), vec2(0,1));           // (1,-3)
+    c2 += refract(vec2(1,3), vec2(0,1), 1.0);          // (1,-3)
+    c2 += refract(vec2(1,3), vec2(0,1), 3.0);
+    c2 += refract(vec2(1,0.1), vec2(0,1), 5.0);        // (0,0)
+    mat3x2 m32 = outerProduct(vec2(2,3), vec3(5,7,11));// rows: (10, 14, 22), (15, 21, 33)
 }
 
 float imageBuffer;    // ERROR, reserved
diff --git a/glslang/Include/ConstantUnion.h b/glslang/Include/ConstantUnion.h
index c19502e8ade6c924b5c06ee7dbad47e26c5381e4..5de0d77409f36712f81391efc7d93043d1bc1156 100644
--- a/glslang/Include/ConstantUnion.h
+++ b/glslang/Include/ConstantUnion.h
@@ -463,6 +463,17 @@ public:
     }
     bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); }
 
+    double dot(const TConstUnionArray& rhs)
+    {
+        assert(rhs.unionArray->size() == unionArray->size());
+        double sum = 0.0;
+
+        for (size_t comp = 0; comp < unionArray->size(); ++comp)
+            sum += (*this)[comp].getDConst() * rhs[comp].getDConst();
+
+        return sum;
+    }
+
     bool empty() const { return unionArray == 0; }
 
 protected:
diff --git a/glslang/MachineIndependent/Constant.cpp b/glslang/MachineIndependent/Constant.cpp
index 9837761a7929d2a344b1971c76f950e248bef5e0..48be7d37608eb1ba2124d4e4cbce32f4c3e41034 100644
--- a/glslang/MachineIndependent/Constant.cpp
+++ b/glslang/MachineIndependent/Constant.cpp
@@ -303,7 +303,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
     // but not always.
     int resultSize;
     switch (op) {
-    // TODO: 3.0 functionality: constant folding: finish listing exceptions to size here
     case EOpDeterminant:
     case EOpAny:
     case EOpAll:
@@ -316,6 +315,18 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
         // These don't actually fold
         return 0;
 
+    case EOpPackSnorm2x16:
+    case EOpPackUnorm2x16:
+    case EOpPackHalf2x16:
+        resultSize = 1;
+        break;
+
+    case EOpUnpackSnorm2x16:
+    case EOpUnpackUnorm2x16:
+    case EOpUnpackHalf2x16:
+        resultSize = 2;
+        break;
+
     default:
         resultSize = getType().getObjectSize();
         break;
@@ -332,7 +343,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
     {
         double sum = 0;
         for (int i = 0; i < objectSize; i++)
-            sum += double(unionArray[i].getDConst()) * unionArray[i].getDConst();
+            sum += unionArray[i].getDConst() * unionArray[i].getDConst();
         double length = sqrt(sum);
         if (op == EOpLength)
             newConstArray[0].setDConst(length);
@@ -487,7 +498,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType)
             break;
         }
 
-        // TODO: 3.0 Functionality: constant folding: the rest of the ops have to be fleshed out
+        // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
 
         case EOpSinh:
         case EOpCosh:
@@ -693,20 +704,74 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
     } else {
         // Non-componentwise...
 
-        switch (aggrNode->getOp()) {
-
-        // TODO: 3.0 Functionality: constant folding: the rest of the ops have to be fleshed out
+        int numComps = children[0]->getAsConstantUnion()->getType().getObjectSize();
+        double dot;
 
-        case EOpModf:
+        switch (aggrNode->getOp()) {
         case EOpDistance:
+        {
+            double sum = 0.0;
+            for (int comp = 0; comp < numComps; ++comp) {
+                double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst();
+                sum += diff * diff;
+            }
+            newConstArray[0].setDConst(sqrt(sum));
+            break;
+        }
         case EOpDot:
+            newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
+            break;
         case EOpCross:
+            newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1];
+            newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2];
+            newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0];
+            break;
         case EOpFaceForward:
+            // If dot(Nref, I) < 0 return N, otherwise return –N:  Arguments are (N, I, Nref).
+            dot = childConstUnions[1].dot(childConstUnions[2]);
+            for (int comp = 0; comp < numComps; ++comp) {
+                if (dot < 0.0)
+                    newConstArray[comp] = childConstUnions[0][comp];
+                else
+                    newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst());
+            }
+            break;
         case EOpReflect:
+            // I – 2 * dot(N, I) * N:  Arguments are (I, N).
+            dot = childConstUnions[0].dot(childConstUnions[1]);
+            dot *= 2.0;
+            for (int comp = 0; comp < numComps; ++comp)
+                newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst());
+            break;
         case EOpRefract:
+        {
+            // Arguments are (I, N, eta).
+            // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
+            // if (k < 0.0)
+            //     return dvec(0.0)
+            // else
+            //     return eta * I - (eta * dot(N, I) + sqrt(k)) * N
+            dot = childConstUnions[0].dot(childConstUnions[1]);
+            double eta = childConstUnions[2][0].getDConst();
+            double k = 1.0 - eta * eta * (1.0 - dot * dot);
+            if (k < 0.0) {
+                for (int comp = 0; comp < numComps; ++comp)
+                    newConstArray[comp].setDConst(0.0);
+            } else {
+                for (int comp = 0; comp < numComps; ++comp)
+                    newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst());
+            }
+            break;
+        }
         case EOpOuterProduct:
-            return aggrNode;
-
+        {
+            int numRows = numComps;
+            int numCols = children[1]->getAsConstantUnion()->getType().getObjectSize();
+            for (int row = 0; row < numRows; ++row)
+                for (int col = 0; col < numCols; ++col)
+                    newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
+            break;
+        }
         default:
             return aggrNode;
         }