X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2FSDCCast.c;h=f57bc1489db9bd8de82c98f483d28b920f2a1b94;hb=90bdb43b342189fcb94a398855d43f3f47f96738;hp=86fad20a2c504b803c58a6f1326c60858f92d4ca;hpb=a8b6b80ff9fcad4aba5bb339e95db62f75f9eb61;p=fw%2Fsdcc diff --git a/src/SDCCast.c b/src/SDCCast.c index 86fad20a..f57bc148 100644 --- a/src/SDCCast.c +++ b/src/SDCCast.c @@ -254,7 +254,7 @@ exit: return dest; } - +#if 0 /*-----------------------------------------------------------------*/ /* removeIncDecOps: remove for side effects in *_ASSIGN's */ /* "*s++ += 3" -> "*s++ = *s++ + 3" */ @@ -325,9 +325,91 @@ ast *removePostIncDecOps (ast * tree) { return tree; } +#endif +/*-----------------------------------------------------------------*/ +/* replaceAstWithTemporary: Replace the AST pointed to by the arg */ +/* with a reference to a new temporary variable. Returns*/ +/* an AST which assigns the original value to the */ +/* temporary. */ +/*-----------------------------------------------------------------*/ +static ast *replaceAstWithTemporary(ast **treeptr) +{ + symbol *sym = newSymbol (genSymName(NestLevel), NestLevel ); + ast *tempvar; + + /* Tell gatherImplicitVariables() to automatically give the + symbol the correct type */ + sym->infertype = 1; + sym->type = NULL; + sym->etype = NULL; + + tempvar = newNode('=', newAst_VALUE(symbolVal(sym)), *treeptr); + *treeptr = newAst_VALUE(symbolVal(sym)); + + addSymChain(&sym); + + return tempvar; +} + +/*-----------------------------------------------------------------*/ +/* createRMW: Create a read-modify-write expression, using a */ +/* temporary variable if necessary to avoid duplicating */ +/* any side effects, for use in e.g. */ +/* foo()->count += 5; becomes */ +/* tmp = foo(); tmp->count = tmp->count + 5; */ +/*-----------------------------------------------------------------*/ +ast * createRMW (ast *target, unsigned op, ast *operand) +{ + ast *readval, *writeval; + ast *tempvar1 = NULL; + ast *tempvar2 = NULL; + ast *result; + + if (!target || !operand) { + return NULL; + } + + /* we need to create two copies of target: one to read from and + one to write to. but we need to do this without duplicating + any side effects that may be contained in the tree. */ + + if (IS_AST_OP(target)) { + /* if this is a dereference, put the referenced item in the temporary */ + if (IS_DEREF_OP(target) || target->opval.op == PTR_OP) { + /* create a new temporary containing the item being dereferenced */ + if (hasSEFcalls(target->left)) + tempvar1 = replaceAstWithTemporary(&(target->left)); + } else if (target->opval.op == '[') { + /* Array access is similar, but we have to avoid side effects in + both values [WIML: Why not transform a[b] to *(a+b) in parser?] */ + if (hasSEFcalls(target->left)) + tempvar1 = replaceAstWithTemporary(&(target->left)); + if (hasSEFcalls(target->right)) + tempvar2 = replaceAstWithTemporary(&(target->right)); + } else { + /* we would have to handle '.', but it is not generated any more */ + wassertl(target->opval.op != '.', "obsolete opcode in tree"); + + /* no other kinds of ASTs are lvalues and can contain side effects */ + } + } + + readval = target; + writeval = copyAst(target); + + result = newNode('=', writeval, newNode(op, readval, operand)); + if (tempvar2) + result = newNode(',', tempvar2, result); + if (tempvar1) + result = newNode(',', tempvar1, result); + + return result; + +} /*-----------------------------------------------------------------*/ -/* hasSEFcalls - returns TRUE if tree has a function call */ +/* hasSEFcalls - returns TRUE if tree has a function call, */ +/* inc/decrement, or other side effect */ /*-----------------------------------------------------------------*/ bool hasSEFcalls (ast * tree) @@ -747,7 +829,7 @@ processParms (ast *func, } /* decorate parameter */ - resultType = defParm ? getResultTypeFromType (defParm->etype) : + resultType = defParm ? getResultTypeFromType (defParm->type) : RESULT_TYPE_NONE; *actParm = decorateType (*actParm, resultType); @@ -1467,8 +1549,11 @@ constExprValue (ast * cexpr, int check) } /* return the value */ - return cexpr->opval.val; - + if (IS_AST_VALUE (cexpr)) + { + return cexpr->opval.val; + } + return NULL; } /*-----------------------------------------------------------------*/ @@ -1494,7 +1579,7 @@ isLabelInAst (symbol * label, ast * tree) /* isLoopCountable - return true if the loop count can be determi- */ /* -ned at compile time . */ /*-----------------------------------------------------------------*/ -bool +static bool isLoopCountable (ast * initExpr, ast * condExpr, ast * loopExpr, symbol ** sym, ast ** init, ast ** end) { @@ -1519,6 +1604,10 @@ isLoopCountable (ast * initExpr, ast * condExpr, ast * loopExpr, else return FALSE; + /* don't reverse loop with volatile counter */ + if (IS_VOLATILE ((*sym)->type)) + return FALSE; + /* for now the symbol has to be of integral type */ if (!IS_INTEGRAL ((*sym)->type)) @@ -1924,7 +2013,7 @@ isConformingBody (ast * pbody, symbol * sym, ast * body) /* if the for loop is reversible. If yes will set the value of */ /* the loop control var & init value & termination value */ /*-----------------------------------------------------------------*/ -bool +static bool isLoopReversible (ast * loop, symbol ** loopCntrl, ast ** init, ast ** end) { @@ -2034,7 +2123,7 @@ reverseLoop (ast * loop, symbol * sym, ast * init, ast * end) /* searchLitOp - search tree (*ops only) for an ast with literal */ /*-----------------------------------------------------------------*/ static ast * -searchLitOp (ast *tree, ast **parent, const unsigned char *ops) +searchLitOp (ast *tree, ast **parent, const char *ops) { ast *ret; @@ -2247,10 +2336,77 @@ getLeftResultType (ast *tree, RESULT_TYPE resultType) } } +/*------------------------------------------------------------------*/ +/* gatherImplicitVariables: assigns correct type information to */ +/* symbols and values created by replaceAstWithTemporary */ +/* and adds the symbols to the declarations list of the */ +/* innermost block that contains them */ +/*------------------------------------------------------------------*/ +void +gatherImplicitVariables (ast * tree, ast * block) +{ + if (!tree) + return; + + if (tree->type == EX_OP && tree->opval.op == BLOCK) + { + /* keep track of containing scope */ + block = tree; + } + if (tree->type == EX_OP && tree->opval.op == '=' && + tree->left->type == EX_VALUE && tree->left->opval.val->sym) + { + symbol *assignee = tree->left->opval.val->sym; + + /* special case for assignment to compiler-generated temporary variable: + compute type of RHS, and set the symbol's type to match */ + if (assignee->type == NULL && assignee->infertype) { + ast *dtr = decorateType (resolveSymbols(tree->right), RESULT_TYPE_NONE); + + if (dtr != tree->right) + tree->right = dtr; + + assignee->type = copyLinkChain(TTYPE(dtr)); + assignee->etype = getSpec(assignee->type); + SPEC_SCLS (assignee->etype) = S_AUTO; + SPEC_OCLS (assignee->etype) = NULL; + SPEC_EXTR (assignee->etype) = 0; + SPEC_STAT (assignee->etype) = 0; + SPEC_VOLATILE (assignee->etype) = 0; + SPEC_ABSA (assignee->etype) = 0; + + wassertl(block != NULL, "implicit variable not contained in block"); + wassert(assignee->next == NULL); + if (block != NULL) { + symbol **decl = &(block->values.sym); + + while (*decl) { + wassert(*decl != assignee); /* should not already be in list */ + decl = &( (*decl)->next ); + } + + *decl = assignee; + } + } + } + if (tree->type == EX_VALUE && !(IS_LITERAL(tree->opval.val->etype)) && + tree->opval.val->type == NULL && + tree->opval.val->sym && + tree->opval.val->sym->infertype) + { + /* fixup type of value for compiler-inferred temporary var */ + tree->opval.val->type = tree->opval.val->sym->type; + tree->opval.val->etype = tree->opval.val->sym->etype; + } + + gatherImplicitVariables(tree->left, block); + gatherImplicitVariables(tree->right, block); +} + /*--------------------------------------------------------------------*/ /* decorateType - compute type for this tree, also does type checking.*/ /* This is done bottom up, since type has to flow upwards. */ -/* resultType flows top-down and forces e.g. char-arithmetik, if the */ +/* resultType flows top-down and forces e.g. char-arithmetic, if the */ /* result is a char and the operand(s) are int's. */ /* It also does constant folding, and parameter checking. */ /*--------------------------------------------------------------------*/ @@ -2323,24 +2479,22 @@ decorateType (ast * tree, RESULT_TYPE resultType) tree->opval.val->etype = tree->opval.val->sym->etype = copyLinkChain (INTTYPE); } + else if (tree->opval.val->sym->implicit) + { + /* if implicit i.e. struct/union member then no type */ + TTYPE (tree) = TETYPE (tree) = NULL; + } else { + /* copy the type from the value into the ast */ + COPYTYPE (TTYPE (tree), TETYPE (tree), tree->opval.val->type); - /* if impilicit i.e. struct/union member then no type */ - if (tree->opval.val->sym->implicit) - TTYPE (tree) = TETYPE (tree) = NULL; - - else - { - - /* else copy the type */ - COPYTYPE (TTYPE (tree), TETYPE (tree), tree->opval.val->type); - - /* and mark it as referenced */ - tree->opval.val->sym->isref = 1; - } + /* and mark the symbol as referenced */ + tree->opval.val->sym->isref = 1; } } + else + wassert(0); /* unreached: all values are literals or symbols */ return tree; } @@ -2939,7 +3093,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) /* rearrange the tree */ if (IS_LITERAL (RTYPE (tree)) /* avoid infinite loop */ - && (TYPE_UDWORD) floatFromVal (tree->right->opval.val) != 1) + && (TYPE_TARGET_ULONG) floatFromVal (tree->right->opval.val) != 1) { ast *parent; ast *litTree = searchLitOp (tree, &parent, "/"); @@ -3383,7 +3537,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) /* rearrange the tree */ if (IS_LITERAL (RTYPE (tree)) /* avoid infinite loop */ - && (TYPE_UDWORD) floatFromVal (tree->right->opval.val) != 0) + && (TYPE_TARGET_ULONG) floatFromVal (tree->right->opval.val) != 0) { ast *litTree, *litParent; litTree = searchLitOp (tree, &litParent, "+-"); @@ -3485,6 +3639,20 @@ decorateType (ast * tree, RESULT_TYPE resultType) goto errorTreeReturn; } + /* if left is another '!' */ + if (tree->left->opval.op == '!') + { + /* remove double '!!X' by 'X ? 1 : 0' */ + tree->opval.op = '?'; + tree->left = tree->left->left; + tree->right = newNode (':', + newAst_VALUE (constVal ("1")), + newAst_VALUE (constVal ("0"))); + tree->right->lineno = tree->lineno; + tree->decorated = 0; + return decorateType (tree, resultType); + } + /* if left is a literal then do it */ if (IS_LITERAL (LTYPE (tree))) { @@ -3591,7 +3759,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) /* if only the right side is a literal & we are shifting more than size of the left operand then zero */ if (IS_LITERAL (RTYPE (tree)) && - ((TYPE_UDWORD) floatFromVal (valFromType (RETYPE (tree)))) >= + ((TYPE_TARGET_ULONG) floatFromVal (valFromType (RETYPE (tree)))) >= (getSize (TETYPE (tree)) * 8)) { if (tree->opval.op==LEFT_OP || @@ -3626,6 +3794,13 @@ decorateType (ast * tree, RESULT_TYPE resultType) changePointer(LTYPE(tree)); checkTypeSanity(LETYPE(tree), "(cast)"); + /* if 'from' and 'to' are the same remove the superfluous cast, */ + /* this helps other optimizations */ + if (compareTypeExact (LTYPE(tree), RTYPE(tree), -1) == 1) + { + return tree->right; + } + /* If code memory is read only, then pointers to code memory */ /* implicitly point to constants -- make this explicit */ { @@ -3691,7 +3866,8 @@ decorateType (ast * tree, RESULT_TYPE resultType) unsigned int gptype = 0; unsigned int addr = SPEC_ADDR (sym->etype); - if (IS_GENPTR (LTYPE (tree)) && GPTRSIZE > FPTRSIZE) + if (IS_GENPTR (LTYPE (tree)) && ((GPTRSIZE > FPTRSIZE) + || TARGET_IS_PIC16) ) { switch (SPEC_SCLS (sym->etype)) { @@ -3710,6 +3886,9 @@ decorateType (ast * tree, RESULT_TYPE resultType) break; default: gptype = 0; + + if(TARGET_IS_PIC16 && (SPEC_SCLS(sym->etype) == S_FIXED)) + gptype = GPTYPE_NEAR; } addr |= gptype << (8*(GPTRSIZE - 1)); } @@ -3913,36 +4092,71 @@ decorateType (ast * tree, RESULT_TYPE resultType) goto errorTreeReturn; } } - /* if unsigned value < 0 then always false */ + + { + CCR_RESULT ccr_result = CCR_OK; + + /* if left is integral and right is literal + then check constant range */ + if (IS_INTEGRAL(LTYPE(tree)) && IS_LITERAL(RTYPE(tree))) + ccr_result = checkConstantRange (LTYPE (tree), RTYPE (tree), + tree->opval.op, FALSE); + if (ccr_result == CCR_OK && + IS_INTEGRAL(RTYPE(tree)) && IS_LITERAL(LTYPE(tree))) + ccr_result = checkConstantRange (RTYPE (tree), LTYPE (tree), + tree->opval.op, TRUE); + switch (ccr_result) + { + case CCR_ALWAYS_TRUE: + case CCR_ALWAYS_FALSE: + if (!options.lessPedantic) + werror (W_COMP_RANGE, + ccr_result == CCR_ALWAYS_TRUE ? "true" : "false"); + return decorateType (newAst_VALUE (constVal ( + ccr_result == CCR_ALWAYS_TRUE ? "1" : "0")), + resultType); + case CCR_OK: + default: + break; + } + } + /* if (unsigned value) > 0 then '(unsigned value) ? 1 : 0' */ - if (SPEC_USIGN(LETYPE(tree)) && - !IS_CHAR(LETYPE(tree)) && /* promotion to signed int */ + if (tree->opval.op == '>' && + SPEC_USIGN(LETYPE(tree)) && IS_LITERAL(RTYPE(tree)) && ((int) floatFromVal (valFromType (RETYPE (tree)))) == 0) { - if (tree->opval.op == '<') + if (resultType == RESULT_TYPE_IFX) { - return tree->right; + /* the parent is an ifx: */ + /* if (unsigned value) */ + return tree->left; } - if (tree->opval.op == '>') - { - if (resultType == RESULT_TYPE_IFX) - { - /* the parent is an ifx: */ - /* if (unsigned value) */ - return tree->left; - } - /* (unsigned value) ? 1 : 0 */ - tree->opval.op = '?'; - tree->right = newNode (':', - newAst_VALUE (constVal ("1")), - tree->right); /* val 0 */ - tree->right->lineno = tree->lineno; - tree->right->left->lineno = tree->lineno; - decorateType (tree->right, RESULT_TYPE_NONE); - } + /* (unsigned value) ? 1 : 0 */ + tree->opval.op = '?'; + tree->right = newNode (':', + newAst_VALUE (constVal ("1")), + tree->right); /* val 0 */ + tree->right->lineno = tree->lineno; + tree->right->left->lineno = tree->lineno; + tree->decorated = 0; + return decorateType (tree, resultType); } + + /* 'ifx (op == 0)' -> 'ifx (!(op))' */ + if (IS_LITERAL(RTYPE(tree)) && + floatFromVal (valFromType (RETYPE (tree))) == 0 && + tree->opval.op == EQ_OP && + resultType == RESULT_TYPE_IFX) + { + tree->opval.op = '!'; + tree->right = NULL; + tree->decorated = 0; + return decorateType (tree, resultType); + } + /* if they are both literal then */ /* rewrite the tree */ if (IS_LITERAL (RTYPE (tree)) && @@ -3957,6 +4171,7 @@ decorateType (ast * tree, RESULT_TYPE resultType) tree->opval.val->type); return tree; } + /* if one is 'signed char ' and the other one is 'unsigned char' */ /* it's necessary to promote to int */ if (IS_CHAR (RTYPE (tree)) && IS_CHAR (LTYPE (tree)) && @@ -3989,7 +4204,51 @@ decorateType (ast * tree, RESULT_TYPE resultType) } LRVAL (tree) = RRVAL (tree) = 1; - TTYPE (tree) = TETYPE (tree) = newCharLink (); + TTYPE (tree) = TETYPE (tree) = newBoolLink (); + + /* condition transformations */ + { + unsigned transformedOp = 0; + + switch (tree->opval.op) + { + case '<': /* transform (a < b) to !(a >= b) */ + if (port->lt_nge) + transformedOp = GE_OP; + break; + case '>': /* transform (a > b) to !(a <= b) */ + if (port->gt_nle) + transformedOp = LE_OP; + break; + case LE_OP: /* transform (a <= b) to !(a > b) */ + if (port->le_ngt) + transformedOp = '>'; + break; + case GE_OP: /* transform (a >= b) to !(a < b) */ + if (port->ge_nlt) + transformedOp = '<'; + break; + case NE_OP: /* transform (a != b) to !(a == b) */ + if (port->ne_neq) + transformedOp = EQ_OP; + break; + case EQ_OP: /* transform (a == b) to !(a != b) */ + if (port->eq_nne) + transformedOp = NE_OP; + break; + default: + break; + } + if (transformedOp) + { + tree->opval.op = transformedOp; + tree->decorated = 0; + tree = newNode ('!', tree, NULL); + tree->lineno = tree->left->lineno; + return decorateType (tree, resultType); + } + } + return tree; /*------------------------------------------------------------------*/ @@ -4451,9 +4710,12 @@ decorateType (ast * tree, RESULT_TYPE resultType) /*----------------------------*/ case FOR: - decorateType (resolveSymbols (AST_FOR (tree, initExpr)), RESULT_TYPE_NONE); - decorateType (resolveSymbols (AST_FOR (tree, condExpr)), RESULT_TYPE_NONE); - decorateType (resolveSymbols (AST_FOR (tree, loopExpr)), RESULT_TYPE_NONE); + AST_FOR (tree, initExpr) = decorateType ( + resolveSymbols (AST_FOR (tree, initExpr)), RESULT_TYPE_NONE); + AST_FOR (tree, condExpr) = decorateType ( + resolveSymbols (AST_FOR (tree, condExpr)), RESULT_TYPE_NONE); + AST_FOR (tree, loopExpr) = decorateType ( + resolveSymbols (AST_FOR (tree, loopExpr)), RESULT_TYPE_NONE); /* if the for loop is reversible then reverse it otherwise do what we normally @@ -4533,6 +4795,16 @@ backPatchLabels (ast * tree, symbol * trueLabel, symbol * falseLabel) if (!tree) return NULL; + /* while-loops insert a label between the IFX and the condition, + therefore look behind the label too */ + if (tree->opval.op == LABEL && + tree->right && + IS_ANDORNOT (tree->right)) + { + tree->right = backPatchLabels (tree->right, trueLabel, falseLabel); + return tree; + } + if (!(IS_ANDORNOT (tree))) return tree; @@ -5052,7 +5324,7 @@ isBitAndPow2 (ast * tree) if (!IS_AST_LIT_VALUE (tree->right)) return -1; - return powof2 ((TYPE_UDWORD)AST_LIT_VALUE (tree->right)); + return powof2 ((TYPE_TARGET_ULONG)AST_LIT_VALUE (tree->right)); } /*-----------------------------------------------------------------*/ @@ -5220,12 +5492,12 @@ optimizeRRCRLC (ast * root) into a RRC operation note : by 7 I mean (number of bits required to hold the variable -1 ) */ - /* if the root operations is not a | operation the not */ + /* if the root operation is not a | operation then not */ if (!IS_BITOR (root)) return root; /* I have to think of a better way to match patterns this sucks */ - /* that aside let start looking for the first case : I use a the + /* that aside let's start looking for the first case : I use a negative check a lot to improve the efficiency */ /* (?expr << 1) | (?expr >> 7) */ if (IS_LEFT_OP (root->left) && @@ -5383,7 +5655,7 @@ optimizeSWAP (ast * root) into a SWAP : operation .. note : by 4 I mean (number of bits required to hold the variable /2 ) */ - /* if the root operations is not a | operation the not */ + /* if the root operation is not a | operation then not */ if (!IS_BITOR (root)) return root; @@ -5679,21 +5951,23 @@ createFunction (symbol * name, ast * body) stackPtr = 0; xstackPtr = -1; + gatherImplicitVariables (body, NULL); /* move implicit variables into blocks */ + /* allocate & autoinit the block variables */ processBlockVars (body, &stack, ALLOCATE); - /* save the stack information */ - if (options.useXstack) - name->xstack = SPEC_STAK (fetype) = stack; - else - name->stack = SPEC_STAK (fetype) = stack; - /* name needs to be mangled */ SNPRINTF (name->rname, sizeof(name->rname), "%s%s", port->fun_prefix, name->name); body = resolveSymbols (body); /* resolve the symbols */ body = decorateType (body, RESULT_TYPE_NONE); /* propagateType & do semantic checks */ + /* save the stack information */ + if (options.useXstack) + name->xstack = SPEC_STAK (fetype) = stack; + else + name->stack = SPEC_STAK (fetype) = stack; + ex = newAst_VALUE (symbolVal (name)); /* create name */ ex = newNode (FUNCTION, ex, body); ex->values.args = FUNC_ARGS(name->type); @@ -5844,10 +6118,10 @@ void ast_print (ast * tree, FILE *outfile, int indent) if (IS_LITERAL (tree->opval.val->etype)) { fprintf(outfile,"CONSTANT (%p) value = ", tree); if (SPEC_USIGN (tree->opval.val->etype)) - fprintf(outfile,"%u", (TYPE_UDWORD) floatFromVal(tree->opval.val)); + fprintf(outfile,"%u", (TYPE_TARGET_ULONG) floatFromVal(tree->opval.val)); else - fprintf(outfile,"%d", (TYPE_DWORD) floatFromVal(tree->opval.val)); - fprintf(outfile,", 0x%x, %f", (TYPE_UDWORD) floatFromVal(tree->opval.val), + fprintf(outfile,"%d", (TYPE_TARGET_LONG) floatFromVal(tree->opval.val)); + fprintf(outfile,", 0x%x, %f", (TYPE_TARGET_ULONG) floatFromVal(tree->opval.val), floatFromVal(tree->opval.val)); } else if (tree->opval.val->sym) { /* if the undefined flag is set then give error message */ @@ -5856,8 +6130,8 @@ void ast_print (ast * tree, FILE *outfile, int indent) } else { fprintf(outfile,"SYMBOL "); } - fprintf(outfile,"(%s=%p)", - tree->opval.val->sym->name,tree); + fprintf(outfile,"(%s=%p @ %p)", + tree->opval.val->sym->name, tree, tree->opval.val->sym); } if (tree->ftype) { fprintf(outfile," type (");