profiles/mojoshader_profile_d3d.c
changeset 1199 b8ece252a201
child 1200 eb1e5280a5a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/mojoshader_profile_d3d.c	Tue Apr 23 14:43:10 2019 -0400
@@ -0,0 +1,686 @@
+/**
+ * MojoShader; generate shader programs from bytecode of compiled
+ *  Direct3D shaders.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+#pragma GCC visibility push(hidden)
+
+#define __MOJOSHADER_INTERNAL__ 1
+#include "mojoshader_profile.h"
+
+#if SUPPORT_PROFILE_D3D
+
+const char *make_D3D_srcarg_string_in_buf(Context *ctx,
+                                          const SourceArgInfo *arg,
+                                          char *buf, size_t buflen)
+{
+    const char *premod_str = "";
+    const char *postmod_str = "";
+    switch (arg->src_mod)
+    {
+        case SRCMOD_NEGATE:
+            premod_str = "-";
+            break;
+
+        case SRCMOD_BIASNEGATE:
+            premod_str = "-";
+            // fall through.
+        case SRCMOD_BIAS:
+            postmod_str = "_bias";
+            break;
+
+        case SRCMOD_SIGNNEGATE:
+            premod_str = "-";
+            // fall through.
+        case SRCMOD_SIGN:
+            postmod_str = "_bx2";
+            break;
+
+        case SRCMOD_COMPLEMENT:
+            premod_str = "1-";
+            break;
+
+        case SRCMOD_X2NEGATE:
+            premod_str = "-";
+            // fall through.
+        case SRCMOD_X2:
+            postmod_str = "_x2";
+            break;
+
+        case SRCMOD_DZ:
+            postmod_str = "_dz";
+            break;
+
+        case SRCMOD_DW:
+            postmod_str = "_dw";
+            break;
+
+        case SRCMOD_ABSNEGATE:
+            premod_str = "-";
+            // fall through.
+        case SRCMOD_ABS:
+            postmod_str = "_abs";
+            break;
+
+        case SRCMOD_NOT:
+            premod_str = "!";
+            break;
+
+        case SRCMOD_NONE:
+        case SRCMOD_TOTAL:
+             break;  // stop compiler whining.
+    } // switch
+
+
+    char regnum_str[16];
+    const char *regtype_str = get_D3D_register_string(ctx, arg->regtype,
+                                                      arg->regnum, regnum_str,
+                                                      sizeof (regnum_str));
+
+    if (regtype_str == NULL)
+    {
+        fail(ctx, "Unknown source register type.");
+        *buf = '\0';
+        return buf;
+    } // if
+
+    const char *rel_lbracket = "";
+    const char *rel_rbracket = "";
+    char rel_swizzle[4] = { '\0' };
+    char rel_regnum_str[16] = { '\0' };
+    const char *rel_regtype_str = "";
+    if (arg->relative)
+    {
+        if (arg->relative_regtype == REG_TYPE_LOOP)
+        {
+            rel_swizzle[0] = '\0';
+            rel_swizzle[1] = '\0';
+            rel_swizzle[2] = '\0';
+        } // if
+        else
+        {
+            rel_swizzle[0] = '.';
+            rel_swizzle[1] = swizzle_channels[arg->relative_component];
+            rel_swizzle[2] = '\0';
+        } // else
+
+        rel_lbracket = "[";
+        rel_rbracket = "]";
+        rel_regtype_str = get_D3D_register_string(ctx, arg->relative_regtype,
+                                                  arg->relative_regnum,
+                                                  rel_regnum_str,
+                                                  sizeof (rel_regnum_str));
+
+        if (regtype_str == NULL)
+        {
+            fail(ctx, "Unknown relative source register type.");
+            *buf = '\0';
+            return buf;
+        } // if
+    } // if
+
+    char swizzle_str[6];
+    size_t i = 0;
+    const int scalar = isscalar(ctx, ctx->shader_type, arg->regtype, arg->regnum);
+    if (!scalar && !no_swizzle(arg->swizzle))
+    {
+        swizzle_str[i++] = '.';
+        swizzle_str[i++] = swizzle_channels[arg->swizzle_x];
+        swizzle_str[i++] = swizzle_channels[arg->swizzle_y];
+        swizzle_str[i++] = swizzle_channels[arg->swizzle_z];
+        swizzle_str[i++] = swizzle_channels[arg->swizzle_w];
+
+        // .xyzz is the same as .xyz, .z is the same as .zzzz, etc.
+        while (swizzle_str[i-1] == swizzle_str[i-2])
+            i--;
+    } // if
+    swizzle_str[i] = '\0';
+    assert(i < sizeof (swizzle_str));
+
+    // !!! FIXME: c12[a0.x] actually needs to be c[a0.x + 12]
+    snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s",
+             premod_str, regtype_str, regnum_str, postmod_str,
+             rel_lbracket, rel_regtype_str, rel_regnum_str, rel_swizzle,
+             rel_rbracket, swizzle_str);
+    // !!! FIXME: make sure the scratch buffer was large enough.
+    return buf;
+} // make_D3D_srcarg_string_in_buf
+
+
+const char *make_D3D_destarg_string(Context *ctx, char *buf,
+                                    const size_t buflen)
+{
+    const DestArgInfo *arg = &ctx->dest_arg;
+
+    const char *result_shift_str = "";
+    switch (arg->result_shift)
+    {
+        case 0x1: result_shift_str = "_x2"; break;
+        case 0x2: result_shift_str = "_x4"; break;
+        case 0x3: result_shift_str = "_x8"; break;
+        case 0xD: result_shift_str = "_d8"; break;
+        case 0xE: result_shift_str = "_d4"; break;
+        case 0xF: result_shift_str = "_d2"; break;
+    } // switch
+
+    const char *sat_str = (arg->result_mod & MOD_SATURATE) ? "_sat" : "";
+    const char *pp_str = (arg->result_mod & MOD_PP) ? "_pp" : "";
+    const char *cent_str = (arg->result_mod & MOD_CENTROID) ? "_centroid" : "";
+
+    char regnum_str[16];
+    const char *regtype_str = get_D3D_register_string(ctx, arg->regtype,
+                                                      arg->regnum, regnum_str,
+                                                      sizeof (regnum_str));
+    if (regtype_str == NULL)
+    {
+        fail(ctx, "Unknown destination register type.");
+        *buf = '\0';
+        return buf;
+    } // if
+
+    char writemask_str[6];
+    size_t i = 0;
+    const int scalar = isscalar(ctx, ctx->shader_type, arg->regtype, arg->regnum);
+    if (!scalar && !writemask_xyzw(arg->writemask))
+    {
+        writemask_str[i++] = '.';
+        if (arg->writemask0) writemask_str[i++] = 'x';
+        if (arg->writemask1) writemask_str[i++] = 'y';
+        if (arg->writemask2) writemask_str[i++] = 'z';
+        if (arg->writemask3) writemask_str[i++] = 'w';
+    } // if
+    writemask_str[i] = '\0';
+    assert(i < sizeof (writemask_str));
+
+    const char *pred_left = "";
+    const char *pred_right = "";
+    char pred[32] = { '\0' };
+    if (ctx->predicated)
+    {
+        pred_left = "(";
+        pred_right = ") ";
+        make_D3D_srcarg_string_in_buf(ctx, &ctx->predicate_arg,
+                                      pred, sizeof (pred));
+    } // if
+
+    // may turn out something like "_x2_sat_pp_centroid (!p0.x) r0.xyzw" ...
+    snprintf(buf, buflen, "%s%s%s%s %s%s%s%s%s%s",
+             result_shift_str, sat_str, pp_str, cent_str,
+             pred_left, pred, pred_right,
+             regtype_str, regnum_str, writemask_str);
+    // !!! FIXME: make sure the scratch buffer was large enough.
+    return buf;
+} // make_D3D_destarg_string
+
+
+const char *make_D3D_srcarg_string(Context *ctx, const size_t idx,
+                                   char *buf, size_t buflen)
+{
+    if (idx >= STATICARRAYLEN(ctx->source_args))
+    {
+        fail(ctx, "Too many source args");
+        *buf = '\0';
+        return buf;
+    } // if
+
+    const SourceArgInfo *arg = &ctx->source_args[idx];
+    return make_D3D_srcarg_string_in_buf(ctx, arg, buf, buflen);
+} // make_D3D_srcarg_string
+
+const char *get_D3D_const_array_varname(Context *ctx, int base, int size)
+{
+    char buf[64];
+    snprintf(buf, sizeof (buf), "c_array_%d_%d", base, size);
+    return StrDup(ctx, buf);
+} // get_D3D_const_array_varname
+
+
+void emit_D3D_start(Context *ctx, const char *profilestr)
+{
+    const uint major = (uint) ctx->major_ver;
+    const uint minor = (uint) ctx->minor_ver;
+    char minor_str[16];
+
+    ctx->ignores_ctab = 1;
+
+    if (minor == 0xFF)
+        strcpy(minor_str, "sw");
+    else if ((major > 1) && (minor == 1))
+        strcpy(minor_str, "x");  // for >= SM2, apparently this is "x". Weird.
+    else
+        snprintf(minor_str, sizeof (minor_str), "%u", (uint) minor);
+
+    output_line(ctx, "%s_%u_%s", ctx->shader_type_str, major, minor_str);
+} // emit_D3D_start
+
+
+void emit_D3D_end(Context *ctx)
+{
+    output_line(ctx, "end");
+} // emit_D3D_end
+
+
+void emit_D3D_phase(Context *ctx)
+{
+    output_line(ctx, "phase");
+} // emit_D3D_phase
+
+
+void emit_D3D_finalize(Context *ctx)
+{
+    // no-op.
+} // emit_D3D_finalize
+
+
+void emit_D3D_global(Context *ctx, RegisterType regtype, int regnum)
+{
+    // no-op.
+} // emit_D3D_global
+
+
+void emit_D3D_array(Context *ctx, VariableList *var)
+{
+    // no-op.
+} // emit_D3D_array
+
+
+void emit_D3D_const_array(Context *ctx, const ConstantsList *clist,
+                          int base, int size)
+{
+    // no-op.
+} // emit_D3D_const_array
+
+
+void emit_D3D_uniform(Context *ctx, RegisterType regtype, int regnum,
+                      const VariableList *var)
+{
+    // no-op.
+} // emit_D3D_uniform
+
+
+void emit_D3D_sampler(Context *ctx, int s, TextureType ttype, int tb)
+{
+    // no-op.
+} // emit_D3D_sampler
+
+
+void emit_D3D_attribute(Context *ctx, RegisterType regtype, int regnum,
+                        MOJOSHADER_usage usage, int index, int wmask,
+                        int flags)
+{
+    // no-op.
+} // emit_D3D_attribute
+
+
+void emit_D3D_RESERVED(Context *ctx)
+{
+    // do nothing; fails in the state machine.
+} // emit_D3D_RESERVED
+
+
+// Generic D3D opcode emitters. A list of macros generate all the entry points
+//  that call into these...
+
+char *lowercase(char *dst, const char *src)
+{
+    int i = 0;
+    do
+    {
+        const char ch = src[i];
+        dst[i] = (((ch >= 'A') && (ch <= 'Z')) ? (ch - ('A' - 'a')) : ch);
+    } while (src[i++]);
+    return dst;
+} // lowercase
+
+
+void emit_D3D_opcode_d(Context *ctx, const char *opcode)
+{
+    char dst[64]; make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s%s", ctx->coissue ? "+" : "", opcode, dst);
+} // emit_D3D_opcode_d
+
+
+void emit_D3D_opcode_s(Context *ctx, const char *opcode)
+{
+    char src0[64]; make_D3D_srcarg_string(ctx, 0, src0, sizeof (src0));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s %s", ctx->coissue ? "+" : "", opcode, src0);
+} // emit_D3D_opcode_s
+
+
+void emit_D3D_opcode_ss(Context *ctx, const char *opcode)
+{
+    char src0[64]; make_D3D_srcarg_string(ctx, 0, src0, sizeof (src0));
+    char src1[64]; make_D3D_srcarg_string(ctx, 1, src1, sizeof (src1));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s %s, %s", ctx->coissue ? "+" : "", opcode, src0, src1);
+} // emit_D3D_opcode_ss
+
+
+void emit_D3D_opcode_ds(Context *ctx, const char *opcode)
+{
+    char dst[64]; make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    char src0[64]; make_D3D_srcarg_string(ctx, 0, src0, sizeof (src0));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s%s, %s", ctx->coissue ? "+" : "", opcode, dst, src0);
+} // emit_D3D_opcode_ds
+
+
+void emit_D3D_opcode_dss(Context *ctx, const char *opcode)
+{
+    char dst[64]; make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    char src0[64]; make_D3D_srcarg_string(ctx, 0, src0, sizeof (src0));
+    char src1[64]; make_D3D_srcarg_string(ctx, 1, src1, sizeof (src1));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s%s, %s, %s", ctx->coissue ? "+" : "",
+                opcode, dst, src0, src1);
+} // emit_D3D_opcode_dss
+
+
+void emit_D3D_opcode_dsss(Context *ctx, const char *opcode)
+{
+    char dst[64]; make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    char src0[64]; make_D3D_srcarg_string(ctx, 0, src0, sizeof (src0));
+    char src1[64]; make_D3D_srcarg_string(ctx, 1, src1, sizeof (src1));
+    char src2[64]; make_D3D_srcarg_string(ctx, 2, src2, sizeof (src2));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s%s, %s, %s, %s", ctx->coissue ? "+" : "", 
+                opcode, dst, src0, src1, src2);
+} // emit_D3D_opcode_dsss
+
+
+void emit_D3D_opcode_dssss(Context *ctx, const char *opcode)
+{
+    char dst[64]; make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    char src0[64]; make_D3D_srcarg_string(ctx, 0, src0, sizeof (src0));
+    char src1[64]; make_D3D_srcarg_string(ctx, 1, src1, sizeof (src1));
+    char src2[64]; make_D3D_srcarg_string(ctx, 2, src2, sizeof (src2));
+    char src3[64]; make_D3D_srcarg_string(ctx, 3, src3, sizeof (src3));
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx,"%s%s%s, %s, %s, %s, %s", ctx->coissue ? "+" : "",
+                opcode, dst, src0, src1, src2, src3);
+} // emit_D3D_opcode_dssss
+
+
+void emit_D3D_opcode(Context *ctx, const char *opcode)
+{
+    opcode = lowercase((char *) alloca(strlen(opcode) + 1), opcode);
+    output_line(ctx, "%s%s", ctx->coissue ? "+" : "", opcode);
+} // emit_D3D_opcode
+
+
+#define EMIT_D3D_OPCODE_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_D_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_d(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_S_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_s(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_SS_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_ss(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_DS_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_ds(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_DSS_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_dss(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_DSSS_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_dsss(ctx, #op); \
+    }
+#define EMIT_D3D_OPCODE_DSSSS_FUNC(op) \
+    void emit_D3D_##op(Context *ctx) { \
+        emit_D3D_opcode_dssss(ctx, #op); \
+    }
+
+EMIT_D3D_OPCODE_FUNC(NOP)
+EMIT_D3D_OPCODE_DS_FUNC(MOV)
+EMIT_D3D_OPCODE_DSS_FUNC(ADD)
+EMIT_D3D_OPCODE_DSS_FUNC(SUB)
+EMIT_D3D_OPCODE_DSSS_FUNC(MAD)
+EMIT_D3D_OPCODE_DSS_FUNC(MUL)
+EMIT_D3D_OPCODE_DS_FUNC(RCP)
+EMIT_D3D_OPCODE_DS_FUNC(RSQ)
+EMIT_D3D_OPCODE_DSS_FUNC(DP3)
+EMIT_D3D_OPCODE_DSS_FUNC(DP4)
+EMIT_D3D_OPCODE_DSS_FUNC(MIN)
+EMIT_D3D_OPCODE_DSS_FUNC(MAX)
+EMIT_D3D_OPCODE_DSS_FUNC(SLT)
+EMIT_D3D_OPCODE_DSS_FUNC(SGE)
+EMIT_D3D_OPCODE_DS_FUNC(EXP)
+EMIT_D3D_OPCODE_DS_FUNC(LOG)
+EMIT_D3D_OPCODE_DS_FUNC(LIT)
+EMIT_D3D_OPCODE_DSS_FUNC(DST)
+EMIT_D3D_OPCODE_DSSS_FUNC(LRP)
+EMIT_D3D_OPCODE_DS_FUNC(FRC)
+EMIT_D3D_OPCODE_DSS_FUNC(M4X4)
+EMIT_D3D_OPCODE_DSS_FUNC(M4X3)
+EMIT_D3D_OPCODE_DSS_FUNC(M3X4)
+EMIT_D3D_OPCODE_DSS_FUNC(M3X3)
+EMIT_D3D_OPCODE_DSS_FUNC(M3X2)
+EMIT_D3D_OPCODE_S_FUNC(CALL)
+EMIT_D3D_OPCODE_SS_FUNC(CALLNZ)
+EMIT_D3D_OPCODE_SS_FUNC(LOOP)
+EMIT_D3D_OPCODE_FUNC(RET)
+EMIT_D3D_OPCODE_FUNC(ENDLOOP)
+EMIT_D3D_OPCODE_S_FUNC(LABEL)
+EMIT_D3D_OPCODE_DSS_FUNC(POW)
+EMIT_D3D_OPCODE_DSS_FUNC(CRS)
+EMIT_D3D_OPCODE_DSSS_FUNC(SGN)
+EMIT_D3D_OPCODE_DS_FUNC(ABS)
+EMIT_D3D_OPCODE_DS_FUNC(NRM)
+EMIT_D3D_OPCODE_S_FUNC(REP)
+EMIT_D3D_OPCODE_FUNC(ENDREP)
+EMIT_D3D_OPCODE_S_FUNC(IF)
+EMIT_D3D_OPCODE_FUNC(ELSE)
+EMIT_D3D_OPCODE_FUNC(ENDIF)
+EMIT_D3D_OPCODE_FUNC(BREAK)
+EMIT_D3D_OPCODE_DS_FUNC(MOVA)
+EMIT_D3D_OPCODE_D_FUNC(TEXKILL)
+EMIT_D3D_OPCODE_DS_FUNC(TEXBEM)
+EMIT_D3D_OPCODE_DS_FUNC(TEXBEML)
+EMIT_D3D_OPCODE_DS_FUNC(TEXREG2AR)
+EMIT_D3D_OPCODE_DS_FUNC(TEXREG2GB)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X2PAD)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X2TEX)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X3PAD)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X3TEX)
+EMIT_D3D_OPCODE_DSS_FUNC(TEXM3X3SPEC)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X3VSPEC)
+EMIT_D3D_OPCODE_DS_FUNC(EXPP)
+EMIT_D3D_OPCODE_DS_FUNC(LOGP)
+EMIT_D3D_OPCODE_DSSS_FUNC(CND)
+EMIT_D3D_OPCODE_DS_FUNC(TEXREG2RGB)
+EMIT_D3D_OPCODE_DS_FUNC(TEXDP3TEX)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X2DEPTH)
+EMIT_D3D_OPCODE_DS_FUNC(TEXDP3)
+EMIT_D3D_OPCODE_DS_FUNC(TEXM3X3)
+EMIT_D3D_OPCODE_D_FUNC(TEXDEPTH)
+EMIT_D3D_OPCODE_DSSS_FUNC(CMP)
+EMIT_D3D_OPCODE_DSS_FUNC(BEM)
+EMIT_D3D_OPCODE_DSSS_FUNC(DP2ADD)
+EMIT_D3D_OPCODE_DS_FUNC(DSX)
+EMIT_D3D_OPCODE_DS_FUNC(DSY)
+EMIT_D3D_OPCODE_DSSSS_FUNC(TEXLDD)
+EMIT_D3D_OPCODE_DSS_FUNC(TEXLDL)
+EMIT_D3D_OPCODE_S_FUNC(BREAKP)
+
+// special cases for comparison opcodes...
+const char *get_D3D_comparison_string(Context *ctx)
+{
+    const char *comps[] = {
+        "", "_gt", "_eq", "_ge", "_lt", "_ne", "_le"
+    };
+
+    if (ctx->instruction_controls >= STATICARRAYLEN(comps))
+    {
+        fail(ctx, "unknown comparison control");
+        return "";
+    } // if
+
+    return comps[ctx->instruction_controls];
+} // get_D3D_comparison_string
+
+void emit_D3D_BREAKC(Context *ctx)
+{
+    char op[16];
+    snprintf(op, sizeof (op), "break%s", get_D3D_comparison_string(ctx));
+    emit_D3D_opcode_ss(ctx, op);
+} // emit_D3D_BREAKC
+
+void emit_D3D_IFC(Context *ctx)
+{
+    char op[16];
+    snprintf(op, sizeof (op), "if%s", get_D3D_comparison_string(ctx));
+    emit_D3D_opcode_ss(ctx, op);
+} // emit_D3D_IFC
+
+void emit_D3D_SETP(Context *ctx)
+{
+    char op[16];
+    snprintf(op, sizeof (op), "setp%s", get_D3D_comparison_string(ctx));
+    emit_D3D_opcode_dss(ctx, op);
+} // emit_D3D_SETP
+
+void emit_D3D_DEF(Context *ctx)
+{
+    char dst[64];
+    make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    const float *val = (const float *) ctx->dwords; // !!! FIXME: could be int?
+    char val0[32];
+    char val1[32];
+    char val2[32];
+    char val3[32];
+    floatstr(ctx, val0, sizeof (val0), val[0], 0);
+    floatstr(ctx, val1, sizeof (val1), val[1], 0);
+    floatstr(ctx, val2, sizeof (val2), val[2], 0);
+    floatstr(ctx, val3, sizeof (val3), val[3], 0);
+    output_line(ctx, "def%s, %s, %s, %s, %s", dst, val0, val1, val2, val3);
+} // emit_D3D_DEF
+
+void emit_D3D_DEFI(Context *ctx)
+{
+    char dst[64];
+    make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    const int32 *x = (const int32 *) ctx->dwords;
+    output_line(ctx, "defi%s, %d, %d, %d, %d", dst,
+                (int) x[0], (int) x[1], (int) x[2], (int) x[3]);
+} // emit_D3D_DEFI
+
+void emit_D3D_DEFB(Context *ctx)
+{
+    char dst[64];
+    make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    output_line(ctx, "defb%s, %s", dst, ctx->dwords[0] ? "true" : "false");
+} // emit_D3D_DEFB
+
+
+static const char *usagestrs[] = {
+    "_position", "_blendweight", "_blendindices", "_normal", "_psize",
+    "_texcoord", "_tangent", "_binormal", "_tessfactor", "_positiont",
+    "_color", "_fog", "_depth", "_sample"
+};
+
+void emit_D3D_DCL(Context *ctx)
+{
+    char dst[64];
+    make_D3D_destarg_string(ctx, dst, sizeof (dst));
+    const DestArgInfo *arg = &ctx->dest_arg;
+    const char *usage_str = "";
+    char index_str[16] = { '\0' };
+
+    if (arg->regtype == REG_TYPE_SAMPLER)
+    {
+        switch ((const TextureType) ctx->dwords[0])
+        {
+            case TEXTURE_TYPE_2D: usage_str = "_2d"; break;
+            case TEXTURE_TYPE_CUBE: usage_str = "_cube"; break;
+            case TEXTURE_TYPE_VOLUME: usage_str = "_volume"; break;
+            default: fail(ctx, "unknown sampler texture type"); return;
+        } // switch
+    } // if
+
+    else if (arg->regtype == REG_TYPE_MISCTYPE)
+    {
+        switch ((const MiscTypeType) arg->regnum)
+        {
+            case MISCTYPE_TYPE_POSITION:
+            case MISCTYPE_TYPE_FACE:
+                usage_str = "";  // just become "dcl vFace" or whatever.
+                break;
+            default: fail(ctx, "unknown misc register type"); return;
+        } // switch
+    } // else if
+
+    else
+    {
+        const uint32 usage = ctx->dwords[0];
+        const uint32 index = ctx->dwords[1];
+        usage_str = usagestrs[usage];
+        if (index != 0)
+            snprintf(index_str, sizeof (index_str), "%u", (uint) index);
+    } // else
+
+    output_line(ctx, "dcl%s%s%s", usage_str, index_str, dst);
+} // emit_D3D_DCL
+
+
+void emit_D3D_TEXCRD(Context *ctx)
+{
+    // this opcode looks and acts differently depending on the shader model.
+    if (shader_version_atleast(ctx, 1, 4))
+        emit_D3D_opcode_ds(ctx, "texcrd");
+    else
+        emit_D3D_opcode_d(ctx, "texcoord");
+} // emit_D3D_TEXCOORD
+
+void emit_D3D_TEXLD(Context *ctx)
+{
+    // this opcode looks and acts differently depending on the shader model.
+    if (shader_version_atleast(ctx, 2, 0))
+    {
+        if (ctx->instruction_controls == CONTROL_TEXLD)
+           emit_D3D_opcode_dss(ctx, "texld");
+        else if (ctx->instruction_controls == CONTROL_TEXLDP)
+           emit_D3D_opcode_dss(ctx, "texldp");
+        else if (ctx->instruction_controls == CONTROL_TEXLDB)
+           emit_D3D_opcode_dss(ctx, "texldb");
+    } // if
+
+    else if (shader_version_atleast(ctx, 1, 4))
+    {
+        emit_D3D_opcode_ds(ctx, "texld");
+    } // else if
+
+    else
+    {
+        emit_D3D_opcode_d(ctx, "tex");
+    } // else
+} // emit_D3D_TEXLD
+
+void emit_D3D_SINCOS(Context *ctx)
+{
+    // this opcode needs extra registers for sm2 and lower.
+    if (!shader_version_atleast(ctx, 3, 0))
+        emit_D3D_opcode_dsss(ctx, "sincos");
+    else
+        emit_D3D_opcode_ds(ctx, "sincos");
+} // emit_D3D_SINCOS
+
+#endif  // SUPPORT_PROFILE_D3D
+
+#pragma GCC visibility pop
\ No newline at end of file