GLOBAL Node *ArrayType(Node *array) { Node *atype; assert(array->typ == Array); assert(array->u.array.name); atype = NodeDataType(array->u.array.name); if (atype->typ == Adcl) { Node *btype = atype, *item; ListMarker marker; /* Loop down the index operations to find the type */ IterateList(&marker, array->u.array.dims); while (NextOnList(&marker, (GenericREF) & item)) if (btype->typ == Adcl) btype = NodeDataType(btype->u.adcl.type); else if (btype->typ == Ptr) btype = NodeDataType(btype->u.ptr.type); else { SyntaxErrorCoord(array->coord, "3 cannot dereference non-pointer type"); return PrimVoid; } return btype; } else if (atype->typ == Ptr) { Node *btype = atype, *item; ListMarker marker; /* Loop down the index operations to find the type */ IterateList(&marker, array->u.array.dims); while (NextOnList(&marker, (GenericREF) & item)) if (btype->typ == Adcl) btype = NodeDataType(btype->u.adcl.type); else if (btype->typ == Ptr) btype = NodeDataType(btype->u.ptr.type); else { SyntaxErrorCoord(array->coord, "cannot dereference non-pointer type"); return PrimVoid; } return btype; } else { fprintf(stderr, "ArrayType: Node at "); PRINT_COORD(stderr, array->coord); fputc('\n', stderr); fPrintNode(stderr, array, 0); fprintf(stderr, "\n"); assert(FALSE); return (NULL); } }
GLOBAL Bool IsConstantZero(Node *node) { Node *val = NodeGetConstantValue(node); Node *type; if (val == NULL) return FALSE; type = NodeDataType(val); assert(type); if (type->typ == Prim) { switch (type->u.prim.basic) { case Sint: return val->u.Const.value.i == 0; case Uint: return val->u.Const.value.u == 0; case Slong: return val->u.Const.value.l == 0; case Ulong: return val->u.Const.value.ul == 0; case Float: return val->u.Const.value.f == 0; case Double: return val->u.Const.value.d == 0; default: break; } } else if (type->typ == Adcl) return FALSE; /* constant string, never 0 */ /*assert(("Unexpected constant type", FALSE));*/ assert(FALSE); UNREACHABLE; return FALSE; /* eliminates warning */ }
GLOBAL Bool NodeConstantBooleanValue(Node *node) { Node *val = NodeGetConstantValue(node); Node *type = NodeDataType(val); assert(val); assert(type); if (type->typ == Prim) { switch (type->u.prim.basic) { case Sint: return val->u.Const.value.i; case Uint: return val->u.Const.value.u; case Slong: return val->u.Const.value.l; case Ulong: return val->u.Const.value.ul; case Float: return val->u.Const.value.f; case Double: return val->u.Const.value.d; default: break; } } else if (type->typ == Adcl) return TRUE; /* constant string, always true */ /*assert(("Unexpected constant type", FALSE));*/ assert(FALSE); UNREACHABLE; return FALSE; /* eliminates warning */ }
GLOBAL unsigned long NodeConstantIntegralValue(Node *node) { Node *val = NodeGetConstantValue(node); Node *type = NodeDataType(val); assert(val); assert(type); if (type->typ == Prim) { switch (type->u.prim.basic) { case Sint: return val->u.Const.value.i; case Uint: return val->u.Const.value.u; case Slong: return val->u.Const.value.l; case Ulong: return val->u.Const.value.ul; #if 0 case Float: return val->u.Const.value.f; case Double: return val->u.Const.value.d; #endif default: break; } } /*assert(("Unexpected constant type", FALSE));*/ UNREACHABLE; return 0; /* eliminates warning */ }
GLOBAL Node *SdclFindField(Node *sdcl, Node *field_name) { if (sdcl->typ == Sdcl) return SUE_FindField(sdcl->u.sdcl.type, field_name); else if (sdcl->typ == Udcl) return SUE_FindField(sdcl->u.udcl.type, field_name); else if (sdcl->typ == Ptr) { assert(sdcl->u.ptr.type); return SdclFindField(NodeDataType(sdcl->u.ptr.type), field_name); } else if (sdcl->typ == Binop) if (sdcl->u.binop.op == '.' || sdcl->u.binop.op == ARROW) return (SdclFindField(sdcl->u.binop.type, field_name)); else { printf("SdclFindField(): not a supported binop\n"); fPrintNode(stdout, sdcl, 0); printf("\n"); fPrintNode(stdout, field_name, 0); printf("\n"); assert(FALSE); } else { printf("SdclFindField(): not a recognized type\n"); fPrintNode(stdout, sdcl, 0); printf("\n"); fPrintNode(stdout, field_name, 0); printf("\n"); assert(FALSE); } UNREACHABLE; return NULL; /* eliminates warning */ }
PRIVATE inline void PrintReturn(GBUF *out, UNUSED(Node *node), ReturnNode *u, int offset, Bool UNUSED(norecurse)) { gbputs("Return: ", out); #if 0 if (u->expr) { PrintCRSpaces(out, offset + 2); PrintNode(out, NodeDataType(u->expr), offset + 2); } #endif PrintCRSpaces(out, offset + 2); PrintNode(out, u->expr, offset + 2); }
GLOBAL Node *DemoteProcArgs(Node *fdcl) { Node *arg; ListMarker marker; assert(fdcl != NULL); IterateList(&marker, fdcl->u.fdcl.args); while (NextOnList(&marker, (GenericREF) & arg)) { if (arg->typ == Decl) { Node *decltype = NodeDataType(arg); /* convert Adcl to pointer */ if (decltype->typ == Adcl) { /* * ``If the specification of an array type * includes any type qualifiers, the element type * is so-qualified, not the array type. If the * specification of a function type includes any * type qualifiers, the behavior is * undefined.'' * * (WG14/N843 6.7.3.8) */ Node *t = decltype->u.adcl.type; /* the type qualifiers of the specification */ TypeQual tq = NodeTq(NodeDataTypeSuperior(arg)); if (tq_has_anything(tq)) { t = NodeCopy(t, NodeOnly); /* add qualifiers to the element type */ NodeUpdateTq2(t, tq_union, tq); } /* the pointer type is never qualified, hence EMPTY_TQ */ arg->u.decl.type = MakePtrCoord(EMPTY_TQ, t, decltype->coord); } } }
GLOBAL void ConstFoldCast(Node *node) { Node *expr; Node *from_type, *to_type; BasicType from_basic, to_basic; /* this function works on both casts and implicitcasts */ switch (node->typ) { case Cast: expr = node->u.cast.expr; break; case ImplicitCast: expr = node->u.implicitcast.expr; if (expr == NULL) return; break; default: UNREACHABLE; } if (!NodeIsConstant(expr)) return; to_type = NodeDataType(node); from_type = NodeDataType(expr); /* can only constant-fold scalar expressions (integral, floating, and pointer) */ if (IsScalarType(to_type) && IsScalarType(from_type)) { from_basic = BasicTypeOfConstantValue(from_type); to_basic = BasicTypeOfConstantValue(to_type); switch (to_basic) { case Slonglong: case Ulonglong: case Longdouble: /* fix: cannot represent these types internally, so no constant-folding occurs. */ return; default: break; } switch (from_basic) { case Sint: { int eval = NodeConstantSintValue(expr); switch (to_basic) { case Sint: NodeSetSintValue(node, eval); return; case Uint: NodeSetUintValue(node, eval); return; case Slong: NodeSetSlongValue(node, eval); return; case Ulong: NodeSetUlongValue(node, eval); return; case Float: NodeSetFloatValue(node, eval); return; case Double: NodeSetDoubleValue(node, eval); return; default: UNREACHABLE; } } case Uint: { unsigned eval = NodeConstantUintValue(expr); switch (to_basic) { case Sint: NodeSetSintValue(node, eval); return; case Uint: NodeSetUintValue(node, eval); return; case Slong: NodeSetSlongValue(node, eval); return; case Ulong: NodeSetUlongValue(node, eval); return; case Float: NodeSetFloatValue(node, eval); return; case Double: NodeSetDoubleValue(node, eval); return; default: UNREACHABLE; } } case Slong: { long eval = NodeConstantSlongValue(expr); switch (to_basic) { case Sint: NodeSetSintValue(node, eval); return; case Uint: NodeSetUintValue(node, eval); return; case Slong: NodeSetSlongValue(node, eval); return; case Ulong: NodeSetUlongValue(node, eval); return; case Float: NodeSetFloatValue(node, eval); return; case Double: NodeSetDoubleValue(node, eval); return; default: UNREACHABLE; } } case Ulong: { unsigned long eval = NodeConstantUlongValue(expr); switch (to_basic) { case Sint: NodeSetSintValue(node, eval); return; case Uint: NodeSetUintValue(node, eval); return; case Slong: NodeSetSlongValue(node, eval); return; case Ulong: NodeSetUlongValue(node, eval); return; case Float: NodeSetFloatValue(node, eval); return; case Double: NodeSetDoubleValue(node, eval); return; default: UNREACHABLE; } } case Float: { float eval = NodeConstantFloatValue(expr); switch (to_basic) { case Sint: NodeSetSintValue(node, eval); return; case Uint: NodeSetUintValue(node, eval); return; case Slong: NodeSetSlongValue(node, eval); return; case Ulong: NodeSetUlongValue(node, eval); return; case Float: NodeSetFloatValue(node, eval); return; case Double: NodeSetDoubleValue(node, eval); return; default: UNREACHABLE; } } case Double: { double eval = NodeConstantDoubleValue(expr); switch (to_basic) { case Sint: NodeSetSintValue(node, eval); return; case Uint: NodeSetUintValue(node, eval); return; case Slong: NodeSetSlongValue(node, eval); return; case Ulong: NodeSetUlongValue(node, eval); return; case Float: NodeSetFloatValue(node, eval); return; case Double: NodeSetDoubleValue(node, eval); return; default: UNREACHABLE; } } default: UNREACHABLE; } } }
/* Must mutate original if changes required for consistency */ GLOBAL void FunctionConflict(Node *orig, Node *create) { Node *ofdcl, *nfdcl; assert(orig); assert(create); assert(orig->typ == Decl); assert(create->typ == Decl); ofdcl = NodeDataType(orig); nfdcl = NodeDataType(create); if (ofdcl->typ != Fdcl || nfdcl->typ != Fdcl) goto Mismatch; /* * Check if one declaration is T_PROCEDURE and the other is not. * BUG: I think the whole way we treat 'cilk' and 'inlet' keywords * is broken. We treat 'cilk' like 'const', but * * const int foo() * * is not the same as * * cilk int foo() * * The former returns a 'const int', but the latter does not return a * 'cilk int' ! - athena * * BTW, the following line is a hack :-) * ((ofdcl->u.fdcl.tq ^ nfdcl->u.fdcl.tq) & (T_PROCEDURE | T_INLET)) * Bradley rewrote it has follows: */ if ((tq_has_procedure(ofdcl->u.fdcl.tq) != tq_has_procedure(nfdcl->u.fdcl.tq)) || (tq_has_inlet(ofdcl->u.fdcl.tq) != tq_has_inlet(nfdcl->u.fdcl.tq))) goto Mismatch; /* The Result Type must be equal */ if (!TypeEqual(ofdcl->u.fdcl.returns, nfdcl->u.fdcl.returns)) goto Mismatch; /* Inspect the parameter lists */ { List *optr = ofdcl->u.fdcl.args, *nptr = nfdcl->u.fdcl.args; /* Are both definitions in prototype form? */ if (optr && nptr) { /* Then every parameter must be compatible */ for (; optr && nptr; optr = Rest(optr), nptr = Rest(nptr)) { Node *oitem = FirstItem(optr), *otype = NodeDataType(oitem), *nitem = FirstItem(nptr), *ntype = NodeDataType(nitem); if (!TypeEqualFormals(otype, ntype)) { SetItem(optr, nitem); goto Mismatch; } } /* And the parameter lists must be of the same length */ if (optr || nptr) goto Mismatch; } /* Check for <Type> f(void) vs <Type> f() */ else if (IsVoidArglist(optr)); /* Check for <Type> f() vs <Type> f(void) */ else if (IsVoidArglist(nptr)) ofdcl->u.fdcl.args = MakeNewList(PrimVoid); /* Else the provided types must be the "usual unary conversions" */ else { /* Either this loop will run */ for (; optr; optr = Rest(optr)) { Node *oitem = FirstItem(optr), *otype = NodeDataType(oitem); if (!TypeEqual(otype, UsualUnaryConversionType(otype)) || IsEllipsis(otype)) goto Mismatch; } /* Or this one will */ for (; nptr; nptr = Rest(nptr)) { Node *nitem = FirstItem(nptr), *ntype = NodeDataType(nitem); if (!TypeEqual(ntype, UsualUnaryConversionType(ntype)) || IsEllipsis(ntype)) goto Mismatch; } } } return; Mismatch: SyntaxErrorCoord(create->coord, "identifier `%s' redeclared", VAR_NAME(orig)); fprintf(stderr, "\tPrevious declaration: "); PRINT_COORD(stderr, orig->coord); fputc('\n', stderr); return; }
/* DEAD CODE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ GLOBAL Bool IsCompatibleFdcls(Node *node1, Node *node2) { assert(node1->typ == Fdcl); assert(node2->typ == Fdcl); #if 0 printf("IsCompatibleFdcls\n"); PrintNode(stdout, node1, 0); printf("\n"); PrintNode(stdout, node2, 0); printf("\n"); #endif /* The Result Type must be equal */ if (!TypeEqual(node1->u.fdcl.returns, node2->u.fdcl.returns)) return FALSE; /* Inspect the parameter lists */ { List *optr = node1->u.fdcl.args, *nptr = node2->u.fdcl.args; /* Are both definitions in prototype form? */ if (optr && nptr) { /* Then every parameter must be compatible */ for (; optr && nptr; optr = Rest(optr), nptr = Rest(nptr)) { Node *oitem = FirstItem(optr), *otype = NodeDataType(oitem), *nitem = FirstItem(nptr), *ntype = NodeDataType(nitem); if (!TypeEqual(otype, ntype)) { #if 0 PrintNode(stdout, otype, 0); printf("\n"); PrintNode(stdout, ntype, 0); printf("\n"); #endif return FALSE; } } /* And the parameter lists must be of the same length */ if (optr || nptr) return FALSE; else return TRUE; } /* Check for <Type> f(void) vs <Type> f() */ else if (IsVoidArglist(optr)) return TRUE; /* Check for <Type> f() vs <Type> f(void) */ else if (IsVoidArglist(nptr)) return TRUE; /* Else the provided types must be the "usual unary conversions" */ else { /* Either this loop will run */ for (; optr; optr = Rest(optr)) { Node *oitem = FirstItem(optr), *otype = NodeDataType(oitem); if (!TypeEqual(otype, UsualUnaryConversionType(otype)) || IsEllipsis(otype)) return FALSE; } /* Or this one will */ for (; nptr; nptr = Rest(nptr)) { Node *nitem = FirstItem(nptr), *ntype = NodeDataType(nitem); if (!TypeEqual(ntype, UsualUnaryConversionType(ntype)) || IsEllipsis(ntype)) return FALSE; } return TRUE; } } }
Bool EqualImplicitCast(implicitcastNode *u1, implicitcastNode *u2) { return (NodeDataType(u1->type) == NodeDataType(u2->type)); }