Added in (most) HLSL intrinsic functions.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 12 Jan 2011 03:44:28 -0500
changeset 974 e4c4963e8889
parent 973 6d4cdbc21301
child 975 95b03c82cf51
Added in (most) HLSL intrinsic functions. There are over 4000 (!) of them when you factor in the overloaded versions. This allows semantic analysis to know all these important functions are defined when the shader makes use of them.
mojoshader_compiler.c
--- a/mojoshader_compiler.c	Wed Jan 12 03:46:17 2011 -0500
+++ b/mojoshader_compiler.c	Wed Jan 12 03:44:28 2011 -0500
@@ -3192,6 +3192,726 @@
 } // build_context
 
 
+// This macro salsa is kinda nasty, but it's the smallest, least error-prone
+//  way I can find to do this well in C.  :/
+
+#define ADD_INTRINSIC(fn, ret, params) do { \
+    push_function(ctx, fn, \
+        build_function_datatype(ctx, ret, STATICARRAYLEN(params), params, 1), \
+        0); \
+} while (0)
+
+#define ADD_INTRINSIC_VECTOR(typestr, code) do { \
+    const MOJOSHADER_astDataType *dt; \
+    dt = get_usertype(ctx, typestr "1"); code; \
+    dt = get_usertype(ctx, typestr "2"); code; \
+    dt = get_usertype(ctx, typestr "3"); code; \
+    dt = get_usertype(ctx, typestr "4"); code; \
+} while (0)
+
+#define ADD_INTRINSIC_VECTOR_FLOAT(code) ADD_INTRINSIC_VECTOR("float", code)
+#define ADD_INTRINSIC_VECTOR_INT(code) ADD_INTRINSIC_VECTOR("int", code)
+#define ADD_INTRINSIC_VECTOR_BOOL(code) ADD_INTRINSIC_VECTOR("bool", code)
+
+#define ADD_INTRINSIC_MATRIX(typestr, code) do { \
+    const MOJOSHADER_astDataType *dt; \
+    dt = get_usertype(ctx, typestr "1x1"); code; \
+    dt = get_usertype(ctx, typestr "1x2"); code; \
+    dt = get_usertype(ctx, typestr "1x3"); code; \
+    dt = get_usertype(ctx, typestr "1x4"); code; \
+    dt = get_usertype(ctx, typestr "2x1"); code; \
+    dt = get_usertype(ctx, typestr "2x2"); code; \
+    dt = get_usertype(ctx, typestr "2x3"); code; \
+    dt = get_usertype(ctx, typestr "2x4"); code; \
+    dt = get_usertype(ctx, typestr "3x1"); code; \
+    dt = get_usertype(ctx, typestr "3x2"); code; \
+    dt = get_usertype(ctx, typestr "3x3"); code; \
+    dt = get_usertype(ctx, typestr "3x4"); code; \
+    dt = get_usertype(ctx, typestr "4x1"); code; \
+    dt = get_usertype(ctx, typestr "4x2"); code; \
+    dt = get_usertype(ctx, typestr "4x3"); code; \
+    dt = get_usertype(ctx, typestr "4x4"); code; \
+} while (0)
+
+#define ADD_INTRINSIC_MATRIX_FLOAT(code) ADD_INTRINSIC_MATRIX("float", code)
+#define ADD_INTRINSIC_MATRIX_INT(code) ADD_INTRINSIC_MATRIX("int", code)
+#define ADD_INTRINSIC_MATRIX_BOOL(code) ADD_INTRINSIC_MATRIX("bool", code)
+
+#define ADD_INTRINSIC_ANY(scalar, typestr, code) do { \
+    { const MOJOSHADER_astDataType *dt = scalar; code; } \
+    ADD_INTRINSIC_VECTOR(typestr, code); \
+    ADD_INTRINSIC_MATRIX(typestr, code); \
+} while (0)
+
+#define ADD_INTRINSIC_ANY_FLOAT(code) do { \
+    ADD_INTRINSIC_ANY(&ctx->dt_double, "double", code); \
+    ADD_INTRINSIC_ANY(&ctx->dt_half, "half", code); \
+    ADD_INTRINSIC_ANY(&ctx->dt_float, "float", code); \
+} while (0)
+#define ADD_INTRINSIC_ANY_INT(code) do { \
+    ADD_INTRINSIC_ANY(&ctx->dt_uint, "uint", code); \
+    ADD_INTRINSIC_ANY(&ctx->dt_int, "int", code); \
+} while (0)
+
+#define ADD_INTRINSIC_ANY_BOOL(code) ADD_INTRINSIC_ANY(&ctx->dt_bool, "bool", code)
+
+static void add_intrinsic1(Context *ctx, const char *fn,
+                           const MOJOSHADER_astDataType *ret,
+                           const MOJOSHADER_astDataType *dt1)
+{
+    const MOJOSHADER_astDataType *params[] = { dt1 };
+    ADD_INTRINSIC(fn, ret, params);
+} // add_intrinsic1
+
+static void add_intrinsic2(Context *ctx, const char *fn,
+                           const MOJOSHADER_astDataType *ret,
+                           const MOJOSHADER_astDataType *dt1,
+                           const MOJOSHADER_astDataType *dt2)
+{
+    const MOJOSHADER_astDataType *params[] = { dt1, dt2 };
+    ADD_INTRINSIC(fn, ret, params);
+} // add_intrinsic2
+
+static void add_intrinsic3(Context *ctx, const char *fn,
+                           const MOJOSHADER_astDataType *ret,
+                           const MOJOSHADER_astDataType *dt1,
+                           const MOJOSHADER_astDataType *dt2,
+                           const MOJOSHADER_astDataType *dt3)
+{
+    const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3 };
+    ADD_INTRINSIC(fn, ret, params);
+} // add_intrinsic3
+
+static void add_intrinsic4(Context *ctx, const char *fn,
+                           const MOJOSHADER_astDataType *ret,
+                           const MOJOSHADER_astDataType *dt1,
+                           const MOJOSHADER_astDataType *dt2,
+                           const MOJOSHADER_astDataType *dt3,
+                           const MOJOSHADER_astDataType *dt4)
+{
+    const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3, dt4 };
+    ADD_INTRINSIC(fn, ret, params);
+} // add_intrinsic4
+
+// PLEASE NOTE that add_intrinsic*() is called AFTER the various
+//  ADD_INTRINSIC_* macros, even though these look like functions that
+//  should be called first. They might be called multiple times by the macro.
+//  The variable "dt" is defined by the macro for use by your code.
+static void add_intrinsic_SAME1_ANYf(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
+} // add_intrinsic_SAME1_ANYf
+
+static void add_intrinsic_SAME1_ANYfi(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, dt, dt));
+    add_intrinsic_SAME1_ANYf(ctx, fn);
+} // add_intrinsic_SAME1_ANYfi
+
+static void add_intrinsic_BOOL_ANYf(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
+} // add_intrinsic_BOOL_ANYf
+
+static void add_intrinsic_BOOL_ANYfib(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_BOOL(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
+    ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
+    add_intrinsic_BOOL_ANYf(ctx, fn);
+} // add_intrinsic_BOOL_ANYfib
+
+static void add_intrinsic_SAME1_ANYf_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dt));
+} // add_intrinsic_SAME1_ANYf_SAME1
+
+static void add_intrinsic_SAME1_ANYfi_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_INT(add_intrinsic2(ctx, fn, dt, dt, dt));
+    add_intrinsic_SAME1_ANYf_SAME1(ctx, fn);
+} // add_intrinsic_SAME1_ANYfi_SAME1
+
+static void add_intrinsic_SAME1_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
+} // add_intrinsic_SAME1_ANYf_SAME1_SAME1
+
+static void add_intrinsic_SAME1_ANYfi_SAME1_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_INT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
+    add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, fn);
+} // add_intrinsic_SAME1_ANYfi_SAME1_SAME1
+
+static void add_intrinsic_SAME1_Mfib(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_MATRIX_BOOL(add_intrinsic1(ctx, fn, dt, dt));
+    ADD_INTRINSIC_MATRIX_INT(add_intrinsic1(ctx, fn, dt, dt));
+    ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
+} // add_intrinsic_SAME1_Mfib
+
+static void add_intrinsic_SAME1_Vf(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
+} // add_intrinsic_SAME1_Vf
+
+static void add_intrinsic_SAME1_Vf_SAME1_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
+} // add_intrinsic_SAME1_Vf_SAME1_SAME1
+
+static void add_intrinsic_SAME1_Vf_SAME1_f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f = &ctx->dt_float;
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, f));
+} // add_intrinsic_SAME1_Vf_SAME1_f
+
+static void add_intrinsic_VOID_ANYf(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, NULL, dt));
+} // add_intrinsic_VOID_ANYf
+
+static void add_intrinsic_VOID_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, NULL, dt, dt, dt));
+} // add_intrinsic_VOID_ANYf_SAME1_SAME1
+
+static void add_intrinsic_f_SQUAREMATRIXf(Context *ctx, const char *fn)
+{
+    add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float1x1"));
+    add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float2x2"));
+    add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float3x3"));
+    add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float4x4"));
+} // add_intrinsic_f_SQUAREMATRIXf
+
+static void add_intrinsic_f_Vf(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, &ctx->dt_float, dt));
+} // add_intrinsic_f_Vf
+
+static void add_intrinsic_fi_Vfi_SAME1(Context *ctx, const char *fn)
+{
+    ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, &ctx->dt_int, dt, dt));
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, &ctx->dt_float, dt, dt));
+} // add_intrinsic_fi_Vfi_SAME1
+
+static void add_intrinsic_f_Vf_SAME1(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f = &ctx->dt_float;
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, f, dt, dt));
+} // add_intrinsic_f_Vf_SAME1
+
+static void add_intrinsic_3f_3f_3f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float3");
+    add_intrinsic2(ctx, fn, dt, dt, dt);
+} // add_intrinsic_3f_3f_3f
+
+static void add_intrinsic_4f_f_f_f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f = &ctx->dt_float;
+    add_intrinsic3(ctx, fn, f4, f, f, f);
+} // add_intrinsic_4f_f_f_f
+
+static void add_intrinsic_4f_s1_4f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
+    add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, dt);
+} // add_intrinsic_4f_s1_4f
+
+static void add_intrinsic_4f_s1_f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
+    add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, &ctx->dt_float);
+} // add_intrinsic_4f_s1_f
+
+static void add_intrinsic_4f_s1_f_f_f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f = &ctx->dt_float;
+    add_intrinsic4(ctx, fn, dt, &ctx->dt_sampler1d, f, f, f);
+} // add_intrinsic_4f_s1_f_f_f
+
+static void add_intrinsic_4f_s2_2f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
+    add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f2);
+} // add_intrinsic_4f_s2_2f
+
+static void add_intrinsic_4f_s2_2f_2f_2f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
+    add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler2d, f2, f2, f2);
+} // add_intrinsic_4f_s2_2f_2f_2f
+
+static void add_intrinsic_4f_s2_4f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f4);
+} // add_intrinsic_4f_s2_4f
+
+static void add_intrinsic_4f_s3_3f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
+    add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f3);
+} // add_intrinsic_4f_s3_3f
+
+static void add_intrinsic_4f_s3_3f_3f_3f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
+    add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler3d, f3, f3, f3);
+} // add_intrinsic_4f_s3_3f_3f_3f
+
+static void add_intrinsic_4f_s3_4f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f4);
+} // add_intrinsic_4f_s3_4f
+
+static void add_intrinsic_4f_sc_3f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
+    add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f3);
+} // add_intrinsic_4f_sc_3f
+
+static void add_intrinsic_4f_sc_3f_3f_3f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
+    add_intrinsic4(ctx, fn, f4, &ctx->dt_samplercube, f3, f3, f3);
+} // add_intrinsic_4f_sc_3f_3f_3f
+
+static void add_intrinsic_4f_sc_4f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f4);
+} // add_intrinsic_4f_sc_4f
+
+static void add_intrinsic_4i_4f(Context *ctx, const char *fn)
+{
+    const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    add_intrinsic1(ctx, fn, i4, f4);
+} // add_intrinsic_4i_4f
+
+static void add_intrinsic_mul(Context *ctx, const char *fn)
+{
+    // mul() is nasty, since there's a bunch of overloads that aren't just
+    //  related to vector size.
+    // !!! FIXME: needs half, double, uint...
+    const MOJOSHADER_astDataType *dtf = &ctx->dt_float;
+    const MOJOSHADER_astDataType *dti = &ctx->dt_int;
+    const MOJOSHADER_astDataType *f1 = get_usertype(ctx, "float1");
+    const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
+    const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
+    const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
+    const MOJOSHADER_astDataType *i1 = get_usertype(ctx, "int1");
+    const MOJOSHADER_astDataType *i2 = get_usertype(ctx, "int2");
+    const MOJOSHADER_astDataType *i3 = get_usertype(ctx, "int3");
+    const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
+    const MOJOSHADER_astDataType *f1x1 = get_usertype(ctx, "float1x1");
+    const MOJOSHADER_astDataType *f1x2 = get_usertype(ctx, "float1x2");
+    const MOJOSHADER_astDataType *f1x3 = get_usertype(ctx, "float1x3");
+    const MOJOSHADER_astDataType *f1x4 = get_usertype(ctx, "float1x4");
+    const MOJOSHADER_astDataType *f2x1 = get_usertype(ctx, "float2x1");
+    const MOJOSHADER_astDataType *f2x2 = get_usertype(ctx, "float2x2");
+    const MOJOSHADER_astDataType *f2x3 = get_usertype(ctx, "float2x3");
+    const MOJOSHADER_astDataType *f2x4 = get_usertype(ctx, "float2x4");
+    const MOJOSHADER_astDataType *f3x1 = get_usertype(ctx, "float3x1");
+    const MOJOSHADER_astDataType *f3x2 = get_usertype(ctx, "float3x2");
+    const MOJOSHADER_astDataType *f3x3 = get_usertype(ctx, "float3x3");
+    const MOJOSHADER_astDataType *f3x4 = get_usertype(ctx, "float3x4");
+    const MOJOSHADER_astDataType *f4x1 = get_usertype(ctx, "float4x1");
+    const MOJOSHADER_astDataType *f4x2 = get_usertype(ctx, "float4x2");
+    const MOJOSHADER_astDataType *f4x3 = get_usertype(ctx, "float4x3");
+    const MOJOSHADER_astDataType *f4x4 = get_usertype(ctx, "float4x4");
+    const MOJOSHADER_astDataType *i1x1 = get_usertype(ctx, "int1x1");
+    const MOJOSHADER_astDataType *i1x2 = get_usertype(ctx, "int1x2");
+    const MOJOSHADER_astDataType *i1x3 = get_usertype(ctx, "int1x3");
+    const MOJOSHADER_astDataType *i1x4 = get_usertype(ctx, "int1x4");
+    const MOJOSHADER_astDataType *i2x1 = get_usertype(ctx, "int2x1");
+    const MOJOSHADER_astDataType *i2x2 = get_usertype(ctx, "int2x2");
+    const MOJOSHADER_astDataType *i2x3 = get_usertype(ctx, "int2x3");
+    const MOJOSHADER_astDataType *i2x4 = get_usertype(ctx, "int2x4");
+    const MOJOSHADER_astDataType *i3x1 = get_usertype(ctx, "int3x1");
+    const MOJOSHADER_astDataType *i3x2 = get_usertype(ctx, "int3x2");
+    const MOJOSHADER_astDataType *i3x3 = get_usertype(ctx, "int3x3");
+    const MOJOSHADER_astDataType *i3x4 = get_usertype(ctx, "int3x4");
+    const MOJOSHADER_astDataType *i4x1 = get_usertype(ctx, "int4x1");
+    const MOJOSHADER_astDataType *i4x2 = get_usertype(ctx, "int4x2");
+    const MOJOSHADER_astDataType *i4x3 = get_usertype(ctx, "int4x3");
+    const MOJOSHADER_astDataType *i4x4 = get_usertype(ctx, "int4x4");
+
+    // scalar * scalar
+    add_intrinsic2(ctx, fn, dti, dti, dti);
+    add_intrinsic2(ctx, fn, dtf, dtf, dtf);
+
+    // scalar * vector
+    ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
+
+    // scalar * matrix
+    ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
+    ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
+
+    // vector * scalar
+    ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
+
+    // vector * vector
+    ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dti, dt, dt));
+    ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dtf, dt, dt));
+
+    // vector * matrix
+    add_intrinsic2(ctx, fn, i1, i1, i1x1);
+    add_intrinsic2(ctx, fn, i2, i1, i1x2);
+    add_intrinsic2(ctx, fn, i3, i1, i1x3);
+    add_intrinsic2(ctx, fn, i4, i1, i1x4);
+    add_intrinsic2(ctx, fn, i1, i2, i2x1);
+    add_intrinsic2(ctx, fn, i2, i2, i2x2);
+    add_intrinsic2(ctx, fn, i3, i2, i2x3);
+    add_intrinsic2(ctx, fn, i4, i2, i2x4);
+    add_intrinsic2(ctx, fn, i1, i3, i3x1);
+    add_intrinsic2(ctx, fn, i2, i3, i3x2);
+    add_intrinsic2(ctx, fn, i3, i3, i3x3);
+    add_intrinsic2(ctx, fn, i4, i3, i3x4);
+    add_intrinsic2(ctx, fn, i1, i4, i4x1);
+    add_intrinsic2(ctx, fn, i2, i4, i4x2);
+    add_intrinsic2(ctx, fn, i3, i4, i4x3);
+    add_intrinsic2(ctx, fn, i4, i4, i4x4);
+    add_intrinsic2(ctx, fn, f1, f1, f1x1);
+    add_intrinsic2(ctx, fn, f2, f1, f1x2);
+    add_intrinsic2(ctx, fn, f3, f1, f1x3);
+    add_intrinsic2(ctx, fn, f4, f1, f1x4);
+    add_intrinsic2(ctx, fn, f1, f2, f2x1);
+    add_intrinsic2(ctx, fn, f2, f2, f2x2);
+    add_intrinsic2(ctx, fn, f3, f2, f2x3);
+    add_intrinsic2(ctx, fn, f4, f2, f2x4);
+    add_intrinsic2(ctx, fn, f1, f3, f3x1);
+    add_intrinsic2(ctx, fn, f2, f3, f3x2);
+    add_intrinsic2(ctx, fn, f3, f3, f3x3);
+    add_intrinsic2(ctx, fn, f4, f3, f3x4);
+    add_intrinsic2(ctx, fn, f1, f4, f4x1);
+    add_intrinsic2(ctx, fn, f2, f4, f4x2);
+    add_intrinsic2(ctx, fn, f3, f4, f4x3);
+    add_intrinsic2(ctx, fn, f4, f4, f4x4);
+
+    // matrix * scalar
+    ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
+    ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
+
+    // matrix * vector
+    add_intrinsic2(ctx, fn, i1, i1x1, i1);
+    add_intrinsic2(ctx, fn, i1, i1x2, i2);
+    add_intrinsic2(ctx, fn, i1, i1x3, i3);
+    add_intrinsic2(ctx, fn, i1, i1x4, i4);
+    add_intrinsic2(ctx, fn, i2, i2x1, i1);
+    add_intrinsic2(ctx, fn, i2, i2x2, i2);
+    add_intrinsic2(ctx, fn, i2, i2x3, i3);
+    add_intrinsic2(ctx, fn, i2, i2x4, i4);
+    add_intrinsic2(ctx, fn, i3, i3x1, i1);
+    add_intrinsic2(ctx, fn, i3, i3x2, i2);
+    add_intrinsic2(ctx, fn, i3, i3x3, i3);
+    add_intrinsic2(ctx, fn, i3, i3x4, i4);
+    add_intrinsic2(ctx, fn, i4, i4x1, i1);
+    add_intrinsic2(ctx, fn, i4, i4x2, i2);
+    add_intrinsic2(ctx, fn, i4, i4x3, i3);
+    add_intrinsic2(ctx, fn, i4, i4x4, i4);
+    add_intrinsic2(ctx, fn, f1, f1x1, f1);
+    add_intrinsic2(ctx, fn, f1, f1x2, f2);
+    add_intrinsic2(ctx, fn, f1, f1x3, f3);
+    add_intrinsic2(ctx, fn, f1, f1x4, f4);
+    add_intrinsic2(ctx, fn, f2, f2x1, f1);
+    add_intrinsic2(ctx, fn, f2, f2x2, f2);
+    add_intrinsic2(ctx, fn, f2, f2x3, f3);
+    add_intrinsic2(ctx, fn, f2, f2x4, f4);
+    add_intrinsic2(ctx, fn, f3, f3x1, f1);
+    add_intrinsic2(ctx, fn, f3, f3x2, f2);
+    add_intrinsic2(ctx, fn, f3, f3x3, f3);
+    add_intrinsic2(ctx, fn, f3, f3x4, f4);
+    add_intrinsic2(ctx, fn, f4, f4x1, f1);
+    add_intrinsic2(ctx, fn, f4, f4x2, f2);
+    add_intrinsic2(ctx, fn, f4, f4x3, f3);
+    add_intrinsic2(ctx, fn, f4, f4x4, f4);
+
+    // matrix * matrix
+    add_intrinsic2(ctx, fn, i1x1, i1x1, i1x1);
+    add_intrinsic2(ctx, fn, i1x2, i1x1, i1x2);
+    add_intrinsic2(ctx, fn, i1x3, i1x1, i1x3);
+    add_intrinsic2(ctx, fn, i1x4, i1x1, i1x4);
+    add_intrinsic2(ctx, fn, i1x1, i1x2, i2x1);
+    add_intrinsic2(ctx, fn, i1x2, i1x2, i2x2);
+    add_intrinsic2(ctx, fn, i1x3, i1x2, i2x3);
+    add_intrinsic2(ctx, fn, i1x4, i1x2, i2x4);
+    add_intrinsic2(ctx, fn, i1x1, i1x3, i3x1);
+    add_intrinsic2(ctx, fn, i1x2, i1x3, i3x2);
+    add_intrinsic2(ctx, fn, i1x3, i1x3, i3x3);
+    add_intrinsic2(ctx, fn, i1x4, i1x3, i3x4);
+    add_intrinsic2(ctx, fn, i1x1, i1x4, i4x1);
+    add_intrinsic2(ctx, fn, i1x2, i1x4, i4x2);
+    add_intrinsic2(ctx, fn, i1x3, i1x4, i4x3);
+    add_intrinsic2(ctx, fn, i1x4, i1x4, i4x4);
+    add_intrinsic2(ctx, fn, i2x1, i2x1, i1x1);
+    add_intrinsic2(ctx, fn, i2x2, i2x1, i1x2);
+    add_intrinsic2(ctx, fn, i2x3, i2x1, i1x3);
+    add_intrinsic2(ctx, fn, i2x4, i2x1, i1x4);
+    add_intrinsic2(ctx, fn, i2x1, i2x2, i2x1);
+    add_intrinsic2(ctx, fn, i2x2, i2x2, i2x2);
+    add_intrinsic2(ctx, fn, i2x3, i2x2, i2x3);
+    add_intrinsic2(ctx, fn, i2x4, i2x2, i2x4);
+    add_intrinsic2(ctx, fn, i2x1, i2x3, i3x1);
+    add_intrinsic2(ctx, fn, i2x2, i2x3, i3x2);
+    add_intrinsic2(ctx, fn, i2x3, i2x3, i3x3);
+    add_intrinsic2(ctx, fn, i2x4, i2x3, i3x4);
+    add_intrinsic2(ctx, fn, i2x1, i2x4, i4x1);
+    add_intrinsic2(ctx, fn, i2x2, i2x4, i4x2);
+    add_intrinsic2(ctx, fn, i2x3, i2x4, i4x3);
+    add_intrinsic2(ctx, fn, i2x4, i2x4, i4x4);
+    add_intrinsic2(ctx, fn, i3x1, i3x1, i1x1);
+    add_intrinsic2(ctx, fn, i3x2, i3x1, i1x2);
+    add_intrinsic2(ctx, fn, i3x3, i3x1, i1x3);
+    add_intrinsic2(ctx, fn, i3x4, i3x1, i1x4);
+    add_intrinsic2(ctx, fn, i3x1, i3x2, i2x1);
+    add_intrinsic2(ctx, fn, i3x2, i3x2, i2x2);
+    add_intrinsic2(ctx, fn, i3x3, i3x2, i2x3);
+    add_intrinsic2(ctx, fn, i3x4, i3x2, i2x4);
+    add_intrinsic2(ctx, fn, i3x1, i3x3, i3x1);
+    add_intrinsic2(ctx, fn, i3x2, i3x3, i3x2);
+    add_intrinsic2(ctx, fn, i3x3, i3x3, i3x3);
+    add_intrinsic2(ctx, fn, i3x4, i3x3, i3x4);
+    add_intrinsic2(ctx, fn, i3x1, i3x4, i4x1);
+    add_intrinsic2(ctx, fn, i3x2, i3x4, i4x2);
+    add_intrinsic2(ctx, fn, i3x3, i3x4, i4x3);
+    add_intrinsic2(ctx, fn, i3x4, i3x4, i4x4);
+    add_intrinsic2(ctx, fn, i4x1, i4x1, i1x1);
+    add_intrinsic2(ctx, fn, i4x2, i4x1, i1x2);
+    add_intrinsic2(ctx, fn, i4x3, i4x1, i1x3);
+    add_intrinsic2(ctx, fn, i4x4, i4x1, i1x4);
+    add_intrinsic2(ctx, fn, i4x1, i4x2, i2x1);
+    add_intrinsic2(ctx, fn, i4x2, i4x2, i2x2);
+    add_intrinsic2(ctx, fn, i4x3, i4x2, i2x3);
+    add_intrinsic2(ctx, fn, i4x4, i4x2, i2x4);
+    add_intrinsic2(ctx, fn, i4x1, i4x3, i3x1);
+    add_intrinsic2(ctx, fn, i4x2, i4x3, i3x2);
+    add_intrinsic2(ctx, fn, i4x3, i4x3, i3x3);
+    add_intrinsic2(ctx, fn, i4x4, i4x3, i3x4);
+    add_intrinsic2(ctx, fn, i4x1, i4x4, i4x1);
+    add_intrinsic2(ctx, fn, i4x2, i4x4, i4x2);
+    add_intrinsic2(ctx, fn, i4x3, i4x4, i4x3);
+    add_intrinsic2(ctx, fn, i4x4, i4x4, i4x4);
+    add_intrinsic2(ctx, fn, f1x1, f1x1, f1x1);
+    add_intrinsic2(ctx, fn, f1x2, f1x1, f1x2);
+    add_intrinsic2(ctx, fn, f1x3, f1x1, f1x3);
+    add_intrinsic2(ctx, fn, f1x4, f1x1, f1x4);
+    add_intrinsic2(ctx, fn, f1x1, f1x2, f2x1);
+    add_intrinsic2(ctx, fn, f1x2, f1x2, f2x2);
+    add_intrinsic2(ctx, fn, f1x3, f1x2, f2x3);
+    add_intrinsic2(ctx, fn, f1x4, f1x2, f2x4);
+    add_intrinsic2(ctx, fn, f1x1, f1x3, f3x1);
+    add_intrinsic2(ctx, fn, f1x2, f1x3, f3x2);
+    add_intrinsic2(ctx, fn, f1x3, f1x3, f3x3);
+    add_intrinsic2(ctx, fn, f1x4, f1x3, f3x4);
+    add_intrinsic2(ctx, fn, f1x1, f1x4, f4x1);
+    add_intrinsic2(ctx, fn, f1x2, f1x4, f4x2);
+    add_intrinsic2(ctx, fn, f1x3, f1x4, f4x3);
+    add_intrinsic2(ctx, fn, f1x4, f1x4, f4x4);
+    add_intrinsic2(ctx, fn, f2x1, f2x1, f1x1);
+    add_intrinsic2(ctx, fn, f2x2, f2x1, f1x2);
+    add_intrinsic2(ctx, fn, f2x3, f2x1, f1x3);
+    add_intrinsic2(ctx, fn, f2x4, f2x1, f1x4);
+    add_intrinsic2(ctx, fn, f2x1, f2x2, f2x1);
+    add_intrinsic2(ctx, fn, f2x2, f2x2, f2x2);
+    add_intrinsic2(ctx, fn, f2x3, f2x2, f2x3);
+    add_intrinsic2(ctx, fn, f2x4, f2x2, f2x4);
+    add_intrinsic2(ctx, fn, f2x1, f2x3, f3x1);
+    add_intrinsic2(ctx, fn, f2x2, f2x3, f3x2);
+    add_intrinsic2(ctx, fn, f2x3, f2x3, f3x3);
+    add_intrinsic2(ctx, fn, f2x4, f2x3, f3x4);
+    add_intrinsic2(ctx, fn, f2x1, f2x4, f4x1);
+    add_intrinsic2(ctx, fn, f2x2, f2x4, f4x2);
+    add_intrinsic2(ctx, fn, f2x3, f2x4, f4x3);
+    add_intrinsic2(ctx, fn, f2x4, f2x4, f4x4);
+    add_intrinsic2(ctx, fn, f3x1, f3x1, f1x1);
+    add_intrinsic2(ctx, fn, f3x2, f3x1, f1x2);
+    add_intrinsic2(ctx, fn, f3x3, f3x1, f1x3);
+    add_intrinsic2(ctx, fn, f3x4, f3x1, f1x4);
+    add_intrinsic2(ctx, fn, f3x1, f3x2, f2x1);
+    add_intrinsic2(ctx, fn, f3x2, f3x2, f2x2);
+    add_intrinsic2(ctx, fn, f3x3, f3x2, f2x3);
+    add_intrinsic2(ctx, fn, f3x4, f3x2, f2x4);
+    add_intrinsic2(ctx, fn, f3x1, f3x3, f3x1);
+    add_intrinsic2(ctx, fn, f3x2, f3x3, f3x2);
+    add_intrinsic2(ctx, fn, f3x3, f3x3, f3x3);
+    add_intrinsic2(ctx, fn, f3x4, f3x3, f3x4);
+    add_intrinsic2(ctx, fn, f3x1, f3x4, f4x1);
+    add_intrinsic2(ctx, fn, f3x2, f3x4, f4x2);
+    add_intrinsic2(ctx, fn, f3x3, f3x4, f4x3);
+    add_intrinsic2(ctx, fn, f3x4, f3x4, f4x4);
+    add_intrinsic2(ctx, fn, f4x1, f4x1, f1x1);
+    add_intrinsic2(ctx, fn, f4x2, f4x1, f1x2);
+    add_intrinsic2(ctx, fn, f4x3, f4x1, f1x3);
+    add_intrinsic2(ctx, fn, f4x4, f4x1, f1x4);
+    add_intrinsic2(ctx, fn, f4x1, f4x2, f2x1);
+    add_intrinsic2(ctx, fn, f4x2, f4x2, f2x2);
+    add_intrinsic2(ctx, fn, f4x3, f4x2, f2x3);
+    add_intrinsic2(ctx, fn, f4x4, f4x2, f2x4);
+    add_intrinsic2(ctx, fn, f4x1, f4x3, f3x1);
+    add_intrinsic2(ctx, fn, f4x2, f4x3, f3x2);
+    add_intrinsic2(ctx, fn, f4x3, f4x3, f3x3);
+    add_intrinsic2(ctx, fn, f4x4, f4x3, f3x4);
+    add_intrinsic2(ctx, fn, f4x1, f4x4, f4x1);
+    add_intrinsic2(ctx, fn, f4x2, f4x4, f4x2);
+    add_intrinsic2(ctx, fn, f4x3, f4x4, f4x3);
+    add_intrinsic2(ctx, fn, f4x4, f4x4, f4x4);
+} // add_intrinsic_mul
+
+static void init_builtins(Context *ctx)
+{
+    // add in standard typedefs...
+    const struct
+    {
+        const char *str;
+        const MOJOSHADER_astDataType *datatype;
+    } types[] = {
+        { "bool", &ctx->dt_bool },
+        { "int", &ctx->dt_int },
+        { "uint", &ctx->dt_uint },
+        { "half", &ctx->dt_half },
+        { "float", &ctx->dt_float },
+        { "double", &ctx->dt_double },
+    };
+
+    int i, j, k;
+    for (i = 0; i < STATICARRAYLEN(types); i++)
+    {
+        char buf[32];
+        int len;
+        const MOJOSHADER_astDataType *dt;
+
+        for (j = 1; j <= 4; j++)
+        {
+            // "float2"
+            dt = new_datatype_vector(ctx, types[i].datatype, j);
+            len = snprintf(buf, sizeof (buf), "%s%d", types[i].str, j);
+            push_usertype(ctx, stringcache_len(ctx->strcache, buf, len), dt);
+            for (k = 1; k <= 4; k++)
+            {
+                // "float2x2"
+                dt = new_datatype_matrix(ctx, types[i].datatype, j, k);
+                len = snprintf(buf, sizeof (buf), "%s%dx%d", types[i].str,j,k);
+                push_usertype(ctx, stringcache_len(ctx->strcache,buf,len), dt);
+            } // for
+        } // for
+    } // for
+
+    // !!! FIXME: block these out by pixel/vertex/etc shader.
+    // !!! FIXME: calculate actual shader model (or maybe just let bytecode verifier throw up?).
+    const int shader_model = 3;
+    if (shader_model >= 1)
+    {
+        add_intrinsic_SAME1_ANYfi(ctx, stringcache(ctx->strcache, "abs"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "acos"));
+        add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "all"));
+        add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "any"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "asin"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "atan"));
+        add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "atan2"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ceil"));
+        add_intrinsic_SAME1_ANYfi_SAME1_SAME1(ctx, stringcache(ctx->strcache, "clamp"));
+        add_intrinsic_VOID_ANYf(ctx, stringcache(ctx->strcache, "clip"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cos"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cosh"));
+        add_intrinsic_3f_3f_3f(ctx, stringcache(ctx->strcache, "cross"));
+        add_intrinsic_4i_4f(ctx, stringcache(ctx->strcache, "D3DCOLORtoUBYTE4"));
+        add_intrinsic_f_Vf_SAME1(ctx, stringcache(ctx->strcache, "distance"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "degrees"));
+        add_intrinsic_f_SQUAREMATRIXf(ctx, stringcache(ctx->strcache, "determinant"));
+        add_intrinsic_fi_Vfi_SAME1(ctx, stringcache(ctx->strcache, "dot"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp2"));
+        add_intrinsic_SAME1_Vf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "faceforward"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "floor"));
+        add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "fmod"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "frac"));
+        add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isfinite"));
+        add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isinf"));
+        add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isnan"));
+        add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "ldexp"));
+        add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "length"));
+        add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "lerp"));
+        add_intrinsic_4f_f_f_f(ctx, stringcache(ctx->strcache, "lit"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log10"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log2"));
+        add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "max"));
+        add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "min"));
+        add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "modf"));  // !!! FIXME: out var?
+        add_intrinsic_mul(ctx, stringcache(ctx->strcache, "mul"));
+        add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "noise"));
+        add_intrinsic_SAME1_Vf(ctx, stringcache(ctx->strcache, "normalize"));
+        add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "pow"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "radians"));
+        add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "reflect"));
+        add_intrinsic_SAME1_Vf_SAME1_f(ctx, stringcache(ctx->strcache, "refract"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "round"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "rsqrt"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "saturate"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sign"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sin"));
+        add_intrinsic_VOID_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "sincos"));  // !!! FIXME: out var?
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sinh"));
+        add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "smoothstep"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sqrt"));
+        add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "step"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tan"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tanh"));
+        add_intrinsic_4f_s1_f(ctx, stringcache(ctx->strcache, "tex1D"));
+        add_intrinsic_4f_s2_2f(ctx, stringcache(ctx->strcache, "tex2D"));
+        add_intrinsic_4f_s3_3f(ctx, stringcache(ctx->strcache, "tex3D"));
+        add_intrinsic_4f_sc_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
+        add_intrinsic_SAME1_Mfib(ctx, stringcache(ctx->strcache, "transpose"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "trunc"));
+    } // if
+
+    if (shader_model >= 2)
+    {
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddx"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddy"));
+        add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "frexp"));
+        add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "fwidth"));
+        add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1D"));
+        add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dbias"));
+        add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1Dgrad"));
+        add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dproj"));
+        add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2D"));
+        add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dbias"));
+        add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2Dgrad"));
+        add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dproj"));
+        add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3D"));
+        add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dbias"));
+        add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3Dgrad"));
+        add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dproj"));
+        add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
+        add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEbias"));
+        add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBEgrad"));
+        add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEproj"));
+    } // if
+
+    if (shader_model >= 3)
+    {
+        add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dlod"));
+        add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dlod"));
+        add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dlod"));
+        add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBElod"));
+    } // if
+} // init_builtins
+
+
 // parse the source code into an AST.
 static void parse_source(Context *ctx, const char *filename,
                          const char *source, unsigned int sourcelen,
@@ -3231,50 +3951,14 @@
 
     // !!! FIXME: check if (parser == NULL)...
 
+    init_builtins(ctx);
+
     SymbolScope *start_scope = ctx->usertypes.scope;
 
     #if DEBUG_COMPILER_PARSER
     ParseHLSLTrace(stdout, "COMPILER: ");
     #endif
 
-    // !!! FIXME: move this to a subroutine.
-    // add in standard typedefs...
-    const struct
-    {
-        const char *str;
-        const MOJOSHADER_astDataType *datatype;
-    } types[] = {
-        { "bool", &ctx->dt_bool },
-        { "int", &ctx->dt_int },
-        { "uint", &ctx->dt_uint },
-        { "half", &ctx->dt_half },
-        { "float", &ctx->dt_float },
-        { "double", &ctx->dt_double },
-    };
-
-    int i, j, k;
-    for (i = 0; i < STATICARRAYLEN(types); i++)
-    {
-        char buf[32];
-        int len;
-        const MOJOSHADER_astDataType *dt;
-
-        for (j = 1; j <= 4; j++)
-        {
-            // "float2"
-            dt = new_datatype_vector(ctx, types[i].datatype, j);
-            len = snprintf(buf, sizeof (buf), "%s%d", types[i].str, j);
-            push_usertype(ctx, stringcache_len(ctx->strcache, buf, len), dt);
-            for (k = 1; k <= 4; k++)
-            {
-                // "float2x2"
-                dt = new_datatype_matrix(ctx, types[i].datatype, j, k);
-                len = snprintf(buf, sizeof (buf), "%s%dx%d", types[i].str,j,k);
-                push_usertype(ctx, stringcache_len(ctx->strcache,buf,len), dt);
-            } // for
-        } // for
-    } // for
-
     // Run the preprocessor/lexer/parser...
     int is_pragma = 0;   // !!! FIXME: remove this later when we can parse #pragma.
     int skipping = 0; // !!! FIXME: remove this later when we can parse #pragma.