$$ = newNode($2,$1,$3);
break;
case MUL_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('*',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '*', $3);
break;
case DIV_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('/',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '/', $3);
break;
case MOD_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('%',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '%', $3);
break;
case ADD_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('+',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '+', $3);
break;
case SUB_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('-',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '-', $3);
break;
case LEFT_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode(LEFT_OP,removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, LEFT_OP, $3);
break;
case RIGHT_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode(RIGHT_OP,removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, RIGHT_OP, $3);
break;
case AND_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('&',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '&', $3);
break;
case XOR_ASSIGN:
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('^',removePreIncDecOps(copyAst($1)),$3));
+ $$ = createRMW($1, '^', $3);
break;
case OR_ASSIGN:
- /* $$ = newNode('=',$1,newNode('|',removeIncDecOps(copyAst($1)),$3)); */
- $$ = newNode('=',removePostIncDecOps(copyAst($1)),
- newNode('|',removePreIncDecOps(copyAst($1)),$3));
+/* $$ = newNode('=',$1,newNode('|',removeIncDecOps(copyAst($1)),$3)); */
+/* $$ = newNode('=',removePostIncDecOps(copyAst($1)),
+ newNode('|',removePreIncDecOps(copyAst($1)),$3)); */
+ $$ = createRMW($1, '|', $3);
break;
default :
$$ = NULL;
return dest;
}
-
+#if 0
/*-----------------------------------------------------------------*/
/* removeIncDecOps: remove for side effects in *_ASSIGN's */
/* "*s++ += 3" -> "*s++ = *s++ + 3" */
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)
}
}
+/*------------------------------------------------------------------*/
+/* 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. */
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;
}
changePointer(LTYPE(tree));
checkTypeSanity(LETYPE(tree), "(cast)");
- /* if 'from' and 'to' are the same remove the superflous cast, */
+ /* if 'from' and 'to' are the same remove the superfluous cast, */
/* this helps other optimizations */
if (compareTypeExact (LTYPE(tree), RTYPE(tree), -1) == 1)
{
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);
} 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 (");
options.out_fmt ? ".S19" : ".ihx",
sizeof(scratchFileName));
if (strcmp (fullDstFileName, scratchFileName))
- unlink (fullDstFileName);
+ remove (fullDstFileName);
rename (scratchFileName, fullDstFileName);
strncpyz (buffer, fullDstFileName, sizeof(buffer));
*q = 0;
strncatz(buffer, ".map", sizeof(buffer));
if (strcmp (scratchFileName, buffer))
- unlink (buffer);
+ remove (buffer);
rename (scratchFileName, buffer);
*p = 0;
strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
*q = 0;
strncatz(buffer, ".mem", sizeof(buffer));
if (strcmp (scratchFileName, buffer))
- unlink (buffer);
+ remove (buffer);
rename (scratchFileName, buffer);
if (options.debug)
{
*q = 0;
strncatz(buffer, ".cdb", sizeof(buffer));
if (strcmp (scratchFileName, buffer))
- unlink (buffer);
+ remove (buffer);
rename (scratchFileName, buffer);
/* and the OMF file without extension: */
*p = 0;
*q = 0;
if (strcmp (scratchFileName, buffer))
- unlink (buffer);
+ remove (buffer);
rename (scratchFileName, buffer);
}
}
port->linker.rel_ext,
sizeof(scratchFileName));
if (strcmp (scratchFileName, fullDstFileName))
- unlink (fullDstFileName);
+ remove (fullDstFileName);
rename (scratchFileName, fullDstFileName);
}
}