⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 constfold.c

📁 cg编译器
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************\
Copyright (c) 2002, NVIDIA Corporation.

NVIDIA Corporation("NVIDIA") supplies this software to you in
consideration of your agreement to the following terms, and your use,
installation, modification or redistribution of this NVIDIA software
constitutes acceptance of these terms.  If you do not agree with these
terms, please do not use, install, modify or redistribute this NVIDIA
software.

In consideration of your agreement to abide by the following terms, and
subject to these terms, NVIDIA grants you a personal, non-exclusive
license, under NVIDIA's copyrights in this original NVIDIA software (the
"NVIDIA Software"), to use, reproduce, modify and redistribute the
NVIDIA Software, with or without modifications, in source and/or binary
forms; provided that if you redistribute the NVIDIA Software, you must
retain the copyright notice of NVIDIA, this notice and the following
text and disclaimers in all such redistributions of the NVIDIA Software.
Neither the name, trademarks, service marks nor logos of NVIDIA
Corporation may be used to endorse or promote products derived from the
NVIDIA Software without specific prior written permission from NVIDIA.
Except as expressly stated in this notice, no other rights or licenses
express or implied, are granted by NVIDIA herein, including but not
limited to any patent rights that may be infringed by your derivative
works or by other works in which the NVIDIA Software may be
incorporated. No hardware is licensed hereunder. 

THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
PRODUCTS.

IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\****************************************************************************/

//
// constfold.c
//

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
//#include <string.h>

#include "slglobals.h"

#if 0
#define DB(X)   X
#else
#define DB(X)
#endif

// IsConstant(expr *)
// return true iff the argument is a constant
static int IsConstant(expr *fexpr)
{
    return fexpr && fexpr->common.kind == CONST_N;
} // IsConstant

// IsConstList(expr *)
// return true iff the argument is a constant or a list of constants
static int IsConstList(expr *fexpr)
{
    while (fexpr &&
           fexpr->common.kind == BINARY_N &&
           fexpr->bin.op == EXPR_LIST_OP
    ) {
        if (!IsConstant(fexpr->bin.left)) return 0;
        if (!(fexpr = fexpr->bin.right)) return 1;
    }
    return fexpr && fexpr->common.kind == CONST_N;
} // IsConstList

// NewConst
// create a new blank constant node we can fill in
// This is a bit of a hack, as the opcode field is really redundant with
// the type info in the node, so we just create an opcode that's as close
// as possible to what we want -- which sometimes may not exist (vectors
// other than float
static expr *NewConst(int base, int len)
{
    float       tmp[4] = { 0, 0, 0, 0 };
    opcode      op = FCONST_OP;

    // This is a bit of a hack -- we use NewFConstNodeV to allocate a node
    // even for non-FCONST_V nodes.  It turns out that it works out ok.
    if (runtime_ops[base]) op = runtime_ops[base]->const_opcode;
    if (len) op++;
    return (expr *)NewFConstNodeV(op, tmp, len, base);
}

// GetConstVal
// get the actual value from a constant node
static scalar_constant *GetConstVal(expr *constexpr) {
    if (!constexpr || constexpr->common.kind != CONST_N) return 0;
    return constexpr->co.val;
} // GetConstVal

typedef struct constlist_iter {
    expr        *curr, *rest;
    int         i, lim;
} constlist_iter;

static void InitConstList_iter(constlist_iter *iter, expr *fexpr)
{
    iter->curr = 0;
    iter->rest = fexpr;
    iter->i = iter->lim = 0;
} // InitConstList_iter

static scalar_constant *ConstListNext(constlist_iter *iter) {
    if (iter->i >= iter->lim) {
        do {
            if (!iter->rest) return 0;
            if (iter->rest->common.kind == BINARY_N &&
                iter->rest->bin.op == EXPR_LIST_OP
            ) {
                iter->curr = iter->rest->bin.left;
                iter->rest = iter->rest->bin.right;
            } else if (iter->rest->common.kind == CONST_N) {
                iter->curr = iter->rest;
                iter->rest = 0;
            } else {
                iter->rest = 0;
                return 0;
            }
        } while (!iter->curr || iter->curr->common.kind != CONST_N);
        iter->i = 0;
        iter->lim = SUBOP_GET_S(iter->curr->co.subop);
    }
    return &iter->curr->co.val[iter->i++];
} // ConstListNext

DB(
static void pconst(scalar_constant *v, int type) {
    switch(type) {
    case TYPE_BASE_BOOLEAN:
        printf("%c", v->i ? 'T' : 'F');
        break;
    case TYPE_BASE_INT:
    case TYPE_BASE_CINT:
        printf("%d", v->i);
        break;
    default:
        printf("%g", v->f);
        break;
    }
}

static void DumpConstList(expr *fexpr, int type) {
    constlist_iter      iter;
    int                 first = 1;
    scalar_constant     *v;

    InitConstList_iter(&iter, fexpr);
    printf("(");
    while ((v = ConstListNext(&iter))) {
        if (first) first = 0;
        else printf(", ");
        pconst(v, type);
    }
    printf(")");
}
)

/*
 * FoldConstants() - Fold this expression if possible.
 *
 */

expr *FoldConstants(expr *fexpr)
{
    return PostApplyToNodes(ConstantFoldNode, fexpr, 0, 0);
}


// ConstantFoldNode
// all the real work is done here
expr *ConstantFoldNode(expr *fexpr, void *_arg1, int arg2)
{
    expr *rv = fexpr;
    int base, target;
    int len;
    int i;
    scalar_constant *a1, *a2;
    void (*unfn)(scalar_constant *, const scalar_constant *) = 0;
    void (*binfn)(scalar_constant *, const scalar_constant *, const scalar_constant *) = 0;
    void (*shfn)(scalar_constant *, const scalar_constant *, int) = 0;
    int (*cmpfn)(const scalar_constant *, const scalar_constant *) = 0;
    int op_offset, a1_mask, a2_mask;
    if (!fexpr) return fexpr;
    switch(fexpr->common.kind) {
    case UNARY_N:
        base = SUBOP_GET_T(fexpr->un.subop);
        len = SUBOP_GET_S(fexpr->un.subop);
        if (fexpr->un.op == VECTOR_V_OP && IsConstList(fexpr->un.arg)) {
            constlist_iter      iter;
            DB (printf("fold VECTOR_V_OP[%d:%d]", len, base);
                DumpConstList(fexpr->un.arg, base);
                printf(" -> ");)
            InitConstList_iter(&iter, fexpr->un.arg);
            rv = NewConst(base, len);
            for (i=0; i<len; i++) {
                rv->co.val[i] = *ConstListNext(&iter);
                DB (if (i) printf(", ");
                    pconst(&rv->co.val[i], base);)
            }
            DB(printf("\n");)
            return rv;
        }
        if (!IsConstant(fexpr->un.arg)) break;
        if (!runtime_ops[base]) break;
        a1 = GetConstVal(fexpr->un.arg);
        switch (fexpr->un.op) {
        case SWIZZLE_Z_OP: {
            int mask = SUBOP_GET_MASK(fexpr->un.subop);
            len = SUBOP_GET_S2(fexpr->un.subop);
            DB (printf("fold SWIZ[%d:%d].", len, base);
                for (i=0; i<len; i++)
                    putchar("xyzw"[(mask>>(i*2))&3]);
                DumpConstList(fexpr->un.arg, base);
                printf(" -> ");)
            rv = NewConst(base, len);
            for (i=0; i==0 || i<len; i++) {
                rv->co.val[i] = a1[mask&3];
                mask >>= 2;
                DB (if (i) printf(", ");
                    pconst(&rv->co.val[i], base);)
            }
            DB(printf("\n");)
            break; }
        case SWIZMAT_Z_OP:
            break;
        case CAST_CS_OP:
        case CAST_CV_OP:
            target = SUBOP_GET_T2(fexpr->un.subop);
            DB (printf("fold CAST[%d:%d->%d]", len, base, target);
                DumpConstList(fexpr->un.arg, base);
                printf(" -> ");)
            unfn = runtime_ops[base]->cvtTo[target];
            if (!unfn && runtime_ops[target])
                unfn = runtime_ops[target]->cvtFrom[base];
            base = target;
            goto normal_unop;
        case CAST_CM_OP:
            break;
        case NEG_OP:
        case NEG_V_OP:
            DB (printf("fold NEG[%d:%d]", len, base);
                DumpConstList(fexpr->un.arg, base);
                printf(" -> ");)
            unfn = runtime_ops[base]->op_neg;
        normal_unop:
            if (!unfn) {
                DB(printf("no function, abort\n");)
                break;
            }
            rv = NewConst(base, len);
            for (i=0; i==0 || i<len; i++) {
                unfn(&rv->co.val[i], &a1[i]);
                DB (if (i) printf(", ");
                    pconst(&rv->co.val[i], base);)
            }
            DB(printf("\n");)
            break;
        case POS_OP:
        case POS_V_OP:
            rv = fexpr->un.arg;
            break;
        case NOT_OP:
        case NOT_V_OP:
            DB (printf("fold NOT[%d:%d]", len, base);
                DumpConstList(fexpr->un.arg, base);
                printf(" -> ");)
            unfn = runtime_ops[base]->op_not;
            goto normal_unop;
        case BNOT_OP:
        case BNOT_V_OP:
            DB (printf("fold BNOT[%d:%d]", len, base);
                DumpConstList(fexpr->un.arg, base);
                printf(" -> ");)
            unfn = runtime_ops[base]->op_bnot;
            goto normal_unop;
            break;
        default:
            break;
        }
        break;
    case BINARY_N:
        if (!IsConstant(fexpr->bin.left) ||
            !IsConstant(fexpr->bin.right)
        )
            break;
        base = SUBOP_GET_T(fexpr->bin.subop);
        if (!runtime_ops[base]) break;
        len = SUBOP_GET_S(fexpr->bin.subop);
        a1 = GetConstVal(fexpr->bin.left);
        a2 = GetConstVal(fexpr->bin.right);
        switch(fexpr->bin.op) {
        case MEMBER_SELECTOR_OP:
        case ARRAY_INDEX_OP:
        case FUN_CALL_OP:
        case FUN_BUILTIN_OP:
        case FUN_ARG_OP:
        case EXPR_LIST_OP:
            break;
        case MUL_OP:
        case MUL_V_OP:
        case MUL_SV_OP:
        case MUL_VS_OP:
            DB (printf("fold MUL");)
            binfn = runtime_ops[base]->op_mul;
            op_offset = fexpr->bin.op - MUL_OP;
        normal_binop:
            DB (printf("[%d:%d]", len, base);
                DumpConstList(fexpr->bin.left, base);
                DumpConstList(fexpr->bin.right, base);
                printf(" -> ");)
            if (!binfn) {
                DB(printf("no function, abort\n");)
                break;
            }
            rv = NewConst(base, len);
            // set a1_mask to all 0s or all 1s, depending on whether a1
            // (left arg) is scalar (all 0s) or vector (all 1s).  a2_mask
            // is set according to a2.  This is dependent on the ordering
            // of the OFFSET_ tags in supprt.h
            a1_mask = 0 - (op_offset&1);
            a2_mask = 0 - (((op_offset>>1)^op_offset)&1);
            for (i=0; i==0 || i<len; i++) {
                binfn(&rv->co.val[i], &a1[i & a1_mask], &a2[i & a2_mask]);
                DB (if (i) printf(", ");
                    pconst(&rv->co.val[i], base);)
            }
            DB(printf("\n");)
            break;
        case DIV_OP:
        case DIV_V_OP:
        case DIV_SV_OP:
        case DIV_VS_OP:
            DB (printf("fold DIV");)
            binfn = runtime_ops[base]->op_div;
            op_offset = fexpr->bin.op - DIV_OP;
            goto normal_binop;
        case MOD_OP:
        case MOD_V_OP:
        case MOD_SV_OP:
        case MOD_VS_OP:
            DB (printf("fold MOD");)
            binfn = runtime_ops[base]->op_mod;
            op_offset = fexpr->bin.op - MOD_OP;
            goto normal_binop;
        case ADD_OP:
        case ADD_V_OP:
        case ADD_SV_OP:
        case ADD_VS_OP:
            DB (printf("fold ADD");)
            binfn = runtime_ops[base]->op_add;
            op_offset = fexpr->bin.op - ADD_OP;
            goto normal_binop;
        case SUB_OP:
        case SUB_V_OP:
        case SUB_SV_OP:
        case SUB_VS_OP:
            DB (printf("fold SUB");)
            binfn = runtime_ops[base]->op_sub;
            op_offset = fexpr->bin.op - SUB_OP;
            goto normal_binop;
        case SHL_OP:
        case SHL_V_OP:
            DB (printf("fold SHL");)
            shfn = runtime_ops[base]->op_shl;
        normal_shiftop:
            DB (printf("[%d:%d]", len, base);
                DumpConstList(fexpr->bin.left, base);
                DumpConstList(fexpr->bin.right, TYPE_BASE_CINT);
                printf(" -> ");)
            if (!shfn) {
                DB(printf("no function, abort\n");)
                break;
            }
            rv = NewConst(base, len);
            for (i=0; i==0 || i<len; i++) {
                shfn(&rv->co.val[i], &a1[i], a2->i);
                DB (if (i) printf(", ");
                    pconst(&rv->co.val[i], base);)
            }
            DB(printf("\n");)
            break;
        case SHR_OP:
        case SHR_V_OP:
            DB (printf("fold SHR");)
            shfn = runtime_ops[base]->op_shr;
            goto normal_shiftop;
        case LT_OP:
        case LT_V_OP:
        case LT_SV_OP:
        case LT_VS_OP:
            DB (printf("fold LT");)
            cmpfn = runtime_ops[base]->op_lt;
            op_offset = fexpr->bin.op - LT_OP;
        normal_cmpop:
            DB (printf("[%d:%d]", len, base);
                DumpConstList(fexpr->bin.left, base);
                DumpConstList(fexpr->bin.right, TYPE_BASE_CINT);
                printf(" -> ");)
            if (!cmpfn) {
                DB(printf("no function, abort\n");)
                break;
            }
            rv = NewConst(TYPE_BASE_BOOLEAN, len);
            // set a1_mask to all 0s or all 1s, depending on whether a1
            // (left arg) is scalar (all 0s) or vector (all 1s).  a2_mask
            // is set according to a2.  This is dependent on the ordering
            // of the OFFSET_ tags in supprt.h
            a1_mask = 0 - (op_offset&1);
            a2_mask = 0 - (((op_offset>>1)^op_offset)&1);
            for (i=0; i==0 || i<len; i++) {
                rv->co.val[i].i = cmpfn(&a1[i & a1_mask], &a2[i & a2_mask]);
                DB (if (i) printf(", ");
                    pconst(&rv->co.val[i], TYPE_BASE_BOOLEAN);)
            }
            DB(printf("\n");)
            break;
        case GT_OP:
        case GT_V_OP:
        case GT_SV_OP:
        case GT_VS_OP:
            cmpfn = runtime_ops[base]->op_gt;
            op_offset = fexpr->bin.op - GT_OP;
            goto normal_cmpop;
        case LE_OP:
        case LE_V_OP:
        case LE_SV_OP:
        case LE_VS_OP:
            cmpfn = runtime_ops[base]->op_le;
            op_offset = fexpr->bin.op - LE_OP;
            goto normal_cmpop;
        case GE_OP:
        case GE_V_OP:
        case GE_SV_OP:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -