/** * \brief * judge e is unreducable value * * @param e * target node * @param allowSymbolAddr * set to 1 and symbol address will be treated as constant * @return * 0:no, 1:yes */ PRIVATE_STATIC int isUnreducableConst(CExpr *e, int allowSymbolAddr) { if(EXPR_CODE(e) == EC_GCC_BLTIN_OFFSET_OF) return 1; if(EXPR_CODE(e) == EC_FUNCTION_CALL) { CExprOfTypeDesc *td = resolveType(EXPR_B(e)->e_nodes[0]); if(td == NULL) return 0; td = getRefType(td); if(ETYP_IS_POINTER(td)) td = EXPR_T(td->e_typeExpr); if(ETYP_IS_FUNC(td) == 0) return 0; //treat static+inline+const func with //constant argument as constant. //this code needs to compile the linux kernel. //ex) case __fswab16(0x0800): int isConst = (td->e_sc.esc_isStatic && td->e_tq.etq_isInline && (td->e_tq.etq_isConst || td->e_isGccConst)); if(isConst && isConstExpr(EXPR_B(e)->e_nodes[1], allowSymbolAddr)) return 1; } return 0; }
CvType getCvTypeAsRef (CvType const & cv_type) { CvType res_cv_type = cv_type; if (res_cv_type.getType ()->getKind () != REF_TYPE) { res_cv_type = CvType (getRefType (res_cv_type)); } return res_cv_type; }
/** * \brief * judge e is constant value * * @param e * target node * @param allowSymbolAddr * set to 1 and symbol address will be treated as constant * @return * 0:no, 1:yes */ int isConstExpr(CExpr *e, int allowSymbolAddr) { if(e == NULL) return 1; if(EXPR_ISCONSTVALUECHECKED(e) || EXPR_ISERROR(e)) return EXPR_ISCONSTVALUE(e); EXPR_ISCONSTVALUECHECKED(e) = 1; switch(EXPR_CODE(e)) { case EC_SIZE_OF: case EC_GCC_ALIGN_OF: case EC_XMP_DESC_OF: goto end; case EC_FUNCTION_CALL: { if(isUnreducableConst(e, allowSymbolAddr) == 0) return 0; goto end; } case EC_GCC_BLTIN_VA_ARG: case EC_POINTER_REF: case EC_POINTS_AT: case EC_MEMBER_REF: { assert(EXPRS_TYPE(e)); CExprOfTypeDesc *tdo = getRefType(EXPRS_TYPE(e)); if(ETYP_IS_ARRAY(tdo)) goto end; CExpr *parent = EXPR_PARENT(e); if(isExprCodeChildOf(e, EC_ADDR_OF, parent, NULL) == 0) return 0; goto end; } case EC_IDENT: switch(EXPR_SYMBOL(e)->e_symType) { case ST_ENUM: case ST_MEMBER: goto end; default: if(allowSymbolAddr) { CExprOfTypeDesc *td = EXPRS_TYPE(e); CExprOfTypeDesc *tdo = getRefType(EXPRS_TYPE(e)); assert(td); CExpr *parent = EXPR_PARENT(e); if(ETYP_IS_FUNC(tdo)) { if(isExprCodeChildOf(e, EC_FUNCTION_CALL, parent, NULL)) return 0; CExprOfTypeDesc *ptd = allocPointerTypeDesc(td); exprSetExprsType(e, ptd); addTypeDesc(ptd); } else if(ETYP_IS_ARRAY(tdo)) { CExpr *pp; if(isExprCodeChildOf(e, EC_ARRAY_REF, parent, &pp)) { if(isExprCodeChildOf(e, EC_ARRAY_REF, pp, NULL) == 0 && isExprCodeChildOf(e, EC_ADDR_OF, parent, NULL) == 0) return 0; } } else if(ETYP_IS_POINTER(tdo) == 0) { if(isExprCodeChildOf(e, EC_ADDR_OF, parent, NULL) == 0) return 0; } } else { return 0; } } break; case EC_CONDEXPR: { CExpr *cond = exprListHeadData(e); if(isConstExpr(cond, allowSymbolAddr) == 0) return 0; goto end; } default: break; } CExprIterator ite; EXPR_FOREACH_MULTI(ite, e) { if(isConstExpr(ite.node, allowSymbolAddr) == 0) return 0; } end: EXPR_ISCONSTVALUE(e) = 1; return 1; }
/** * \brief * do constant folding * * @param expr * target node * @param[out] result * result value * @return * 0:is not constant, 1:constant */ int getConstNumValue(CExpr *expr, CNumValueWithType *result) { memset(result, 0, sizeof(CNumValueWithType)); if(EXPR_ISNULL(expr) || EXPR_ISERROR(expr)) { result->nvt_numValue.ll = 0; result->nvt_basicType = BT_INT; result->nvt_numKind = getNumValueKind(result->nvt_basicType); return 1; } if(EXPR_CODE(expr) == EC_XMP_DESC_OF) return 0; /* not constant */ CNumValueWithType n1, n2, n3; int use2 = 0, use3 = 0, isConst2 = 0, isConst3 = 0; switch(EXPR_STRUCT(expr)) { case STRUCT_CExprOfUnaryNode: { CExpr *node = EXPR_U(expr)->e_node; if(EXPR_CODE(expr) == EC_SIZE_OF || EXPR_CODE(expr) == EC_GCC_ALIGN_OF) { CExprOfTypeDesc *td = resolveType(node); if(td == NULL) return 0; result->nvt_isConstButMutable = 1; result->nvt_basicType = BT_INT; result->nvt_numKind = getNumValueKind(result->nvt_basicType); if(EXPR_CODE(expr) == EC_SIZE_OF) result->nvt_numValue.ll = getTypeSize(td); else { assertExpr((CExpr*)td, getTypeAlign(td)); result->nvt_numValue.ll = getTypeAlign(td); } return 1; } if(getConstNumValue(node, &n1) == 0) { mergeConstFlag(result, &n1); return 0; } } break; case STRUCT_CExprOfBinaryNode: { if(isUnreducableConst(expr, 1)) { result->nvt_isConstButUnreducable = 1; return 0; } CExpr *node1 = EXPR_B(expr)->e_nodes[0]; CExpr *node2 = EXPR_B(expr)->e_nodes[1]; if(EXPR_CODE(node1) == EC_TYPE_DESC) { if(getConstNumValue(node2, &n2) == 0) return 0; else n1 = n2; } else { if(getConstNumValue(node1, &n1) == 0) { mergeConstFlag(result, &n1); return 0; } if(getConstNumValue(node2, &n2) == 0) { mergeConstFlag(result, &n1); mergeConstFlag(result, &n2); return 0; } use2 = 1; } } break; case STRUCT_CExprOfList: if(EXPR_CODE(expr) == EC_CONDEXPR) { if(getConstNumValue(exprListNextNData(expr, 0), &n1) == 0) { mergeConstFlag(result, &n1); return 0; } isConst2 = getConstNumValue(exprListNextNData(expr, 1), &n2); isConst3 = getConstNumValue(exprListNextNData(expr, 2), &n3); use2 = use3 = 1; } else { //maybe comma expr if(getConstNumValue(exprListTailData(expr), &n1) == 0) { mergeConstFlag(result, &n1); return 0; } } break; case STRUCT_CExprOfCharConst: //wide char is not supported result->nvt_numValue.ll = EXPR_CHARCONST(expr)->e_token[0]; result->nvt_basicType = BT_CHAR; result->nvt_numKind = getNumValueKind(result->nvt_basicType); return 1; case STRUCT_CExprOfNumberConst: constToNumValueWithType(EXPR_NUMBERCONST(expr), result); return 1; case STRUCT_CExprOfSymbol: { CExprOfSymbol *tsym = findSymbolByGroup(EXPR_SYMBOL(expr)->e_symName, STB_IDENT); if(tsym == NULL || (tsym->e_symType != ST_ENUM) || tsym->e_isConstButUnreducable || (tsym && getConstNumValue(tsym->e_valueExpr, &n1) == 0)) { if(tsym && tsym->e_isConstButUnreducable) result->nvt_isConstButUnreducable = 1; mergeConstFlag(result, &n1); return 0; } } break; case STRUCT_CExprOfArrayDecl: case STRUCT_CExprOfTypeDesc: case STRUCT_CExprOfErrorNode: case STRUCT_CExprOfGeneralCode: case STRUCT_CExprOfNull: return 0; default: assertExpr(expr, 0); ABORT(); } int r = 1; int isCondExpr = (EXPR_CODE(expr) == EC_CONDEXPR); //for lshift/rshift int ni2 = 0; mergeConstFlag(result, &n1); if(use2) { ni2 = (int)getCastedLongValue(&n2); if(fixNumValueType(&n1, &n2) == 0 && isCondExpr == 0) return 0; mergeConstFlag(result, &n2); } if(use3) { if(fixNumValueType(&n1, &n3) == 0 && isCondExpr == 0) return 0; mergeConstFlag(result, &n3); } //now n1/n2/n3 have same basicType and numKind CNumValueKind nk = n1.nvt_numKind; CNumValue *nvr = &result->nvt_numValue; CNumValue *nv1 = &n1.nvt_numValue; CNumValue *nv2 = &n2.nvt_numValue; CNumValue *nv3 = &n3.nvt_numValue; switch(EXPR_CODE(expr)) { case EC_EXPRS: //last expression switch(nk) { case NK_LL: nvr->ll = nv1->ll; break; case NK_ULL: nvr->ull = nv1->ull; break; case NK_LD: nvr->ld = nv1->ld; break; } break; case EC_BRACED_EXPR: case EC_IDENT: // enumerator switch(nk) { case NK_LL: nvr->ll = nv1->ll; break; case NK_ULL: nvr->ull = nv1->ull; break; case NK_LD: nvr->ld = nv1->ld; break; } break; case EC_UNARY_MINUS: switch(nk) { case NK_LL: nvr->ll = -nv1->ll; break; case NK_ULL: nvr->ull = -nv1->ull; break; case NK_LD: nvr->ld = -nv1->ld; break; } break; case EC_BIT_NOT: switch(nk) { case NK_LL: nvr->ll = ~nv1->ll; break; case NK_ULL: nvr->ull = ~nv1->ull; break; case NK_LD: return 0; } break; case EC_LOG_NOT: switch(nk) { case NK_LL: nvr->ll = !nv1->ll; break; case NK_ULL: nvr->ull = !nv1->ull; break; case NK_LD: nvr->ld = !nv1->ld; break; } break; case EC_CAST: { CExprOfTypeDesc *td = resolveType(EXPR_B(expr)->e_nodes[0]); if(td == NULL) return 0; CExprOfTypeDesc *tdo = getRefType(td); if(castNumValue(&n1, tdo->e_basicType) == 0) { addError(expr, CERR_016); EXPR_ISERROR(expr) = 1; return 0; } switch(n1.nvt_numKind) { case NK_LL: nvr->ll = nv1->ll; break; case NK_ULL: nvr->ull = nv1->ull; break; case NK_LD: nvr->ld = nv1->ld; break; } } break; case EC_LSHIFT: switch(nk) { case NK_LL: nvr->ll = nv1->ll << ni2; break; case NK_ULL: nvr->ull = nv1->ull << ni2; break; case NK_LD: return 0; } break; case EC_RSHIFT: switch(nk) { case NK_LL: nvr->ll = nv1->ll >> ni2; break; case NK_ULL: nvr->ull = nv1->ull >> ni2; break; case NK_LD: return 0; } break; case EC_PLUS: switch(nk) { case NK_LL: nvr->ll = nv1->ll + nv2->ll; break; case NK_ULL: nvr->ull = nv1->ull + nv2->ull; break; case NK_LD: nvr->ld = nv1->ld + nv2->ld; break; } break; case EC_MINUS: switch(nk) { case NK_LL: nvr->ll = nv1->ll - nv2->ll; break; case NK_ULL: nvr->ull = nv1->ull - nv2->ull; break; case NK_LD: nvr->ld = nv1->ld - nv2->ld; break; } break; case EC_MUL: switch(nk) { case NK_LL: nvr->ll = nv1->ll * nv2->ll; break; case NK_ULL: nvr->ull = nv1->ull * nv2->ull; break; case NK_LD: nvr->ld = nv1->ld * nv2->ld; break; } break; case EC_DIV: if(checkDivisionByZero(expr, nk, nv2)) return 0; switch(nk) { case NK_LL: nvr->ll = nv1->ll / nv2->ll; break; case NK_ULL: nvr->ull = nv1->ull / nv2->ull; break; case NK_LD: nvr->ld = nv1->ld / nv2->ld; break; } break; case EC_MOD: if(checkDivisionByZero(expr, nk, nv2)) return 0; switch(nk) { case NK_LL: nvr->ll = nv1->ll % nv2->ll; break; case NK_ULL: nvr->ull = nv1->ull % nv2->ull; break; case NK_LD: return 0; } break; case EC_ARITH_EQ: switch(nk) { case NK_LL: nvr->ll = (nv1->ll == nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull == nv2->ull); break; case NK_LD: nvr->ld = (nv1->ld == nv2->ld); break; } break; case EC_ARITH_NE: switch(nk) { case NK_LL: nvr->ll = (nv1->ll != nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull != nv2->ull); break; case NK_LD: nvr->ld = (nv1->ld != nv2->ld); break; } break; case EC_ARITH_GE: switch(nk) { case NK_LL: nvr->ll = (nv1->ll >= nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull >= nv2->ull); break; case NK_LD: nvr->ld = (nv1->ld >= nv2->ld); break; } break; case EC_ARITH_GT: switch(nk) { case NK_LL: nvr->ll = (nv1->ll > nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull > nv2->ull); break; case NK_LD: nvr->ld = (nv1->ld > nv2->ld); break; } break; case EC_ARITH_LE: switch(nk) { case NK_LL: nvr->ll = (nv1->ll <= nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull <= nv2->ull); break; case NK_LD: nvr->ld = (nv1->ld <= nv2->ld); break; } break; case EC_ARITH_LT: switch(nk) { case NK_LL: nvr->ll = (nv1->ll < nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull < nv2->ull); break; case NK_LD: nvr->ld = (nv1->ld < nv2->ld); break; } break; case EC_LOG_AND: switch(nk) { case NK_LL: nvr->ll = (nv1->ll && nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull && nv2->ull); break; case NK_LD: return 0; } break; case EC_LOG_OR: switch(nk) { case NK_LL: nvr->ll = (nv1->ll || nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull || nv2->ull); break; case NK_LD: return 0; } break; case EC_BIT_AND: switch(nk) { case NK_LL: nvr->ll = (nv1->ll & nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull & nv2->ull); break; case NK_LD: return 0; } break; case EC_BIT_OR: switch(nk) { case NK_LL: nvr->ll = (nv1->ll | nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull | nv2->ull); break; case NK_LD: return 0; } break; case EC_BIT_XOR: switch(nk) { case NK_LL: nvr->ll = (nv1->ll ^ nv2->ll); break; case NK_ULL: nvr->ull = (nv1->ull ^ nv2->ull); break; case NK_LD: return 0; } break; case EC_CONDEXPR: switch(nk) { case NK_LL: nvr->ll = nv1->ll ? nv2->ll : nv3->ll; r = (nv1->ll) ? isConst2 : isConst3; break; case NK_ULL: nvr->ull = nv1->ull ? nv2->ull : nv3->ull; r = (nv1->ull) ? isConst2 : isConst3; break; case NK_LD: nvr->ld = nv1->ld ? nv2->ld : nv3->ld; r = (nv1->ld) ? isConst2 : isConst3; break; } break; default: return 0; } result->nvt_basicType = n1.nvt_basicType; result->nvt_numKind = n1.nvt_numKind; return r; }