#include "AST.h" #include "CodeContext.h" #include "CtReference.h" #include "PrimitiveDecl.h" #include "code-assign.h" #include "code-call.h" #include "code-foreach.h" #include "code-util.h" #include "ctBox.h" #include "lgMacro.h" #include "pseudocode.h" extern bool bounds_checking; const string ArrayAccessNode::cArrayHandler( const char [], bool canUseFast ) { undefined( "cArrayHandler" ); return ""; } /* * Java array handlers are of the form: * * JAVA_ARRAY_op_dist * * Where "op" is the operation being performed and "dist" is the * reference distance, either "LOCAL" or "GLOBAL". */ const string JavaArrayAccessNode::cArrayHandler( const char operation[], bool canUseFast ) { return "JAVA_ARRAY_" + lgMacro( operation, *array()->type() ); } /* * Titanium array handlers are of the form: * * TI_ARRAY_op_dist( elem, arity ) * * Where: * * - "op" is the operation being performed * - "dist" is the reference distance (either "LOCAL" or "GLOBAL") * - "elem" is the element type name * - "arity" is the array arity */ static const string buildTiArrayAccess( const TypeNode *arrayType, const char operation[], bool canUseFast) { string op = operation; if (!strcmp(operation,"ADDR") && canUseFast) { // can use the fast-path addressing, if and only if all arguments // to the arg function are C variables (and not expressions) op = "FASTADDR"; } return "TI_ARRAY_" + lgMacro( op, *arrayType ) + '(' + arrayType->elementType()->cType() + ", " + int2string( arrayType->tiArity() ) + ')'; } const string TitaniumArrayAccessNode::cArrayHandler( const char operation[], bool canUseFast ) { return buildTiArrayAccess(array()->type(), operation, canUseFast); } // Assume all strength-reduced accesses are to titanium arrays. const string SRArrayAccessNode::cArrayHandler( const char operation[], bool canUseFast ) { return buildTiArrayAccess(array()->type(), operation, canUseFast); } // Assume all offset strength-reduced accesses are to titanium arrays. const string OSRArrayAccessNode::cArrayHandler( const char operation[], bool canUseFast ) { return buildTiArrayAccess(array()->type(), operation, canUseFast); } /**********************************************************************/ bool ArrayAccessNode::isLocalLvalue() { return array()->type()->isLocal(); } /* * We want the address of the n'th element of an array. We may have * two possible ways of computing this. * * First, we can always compute it using the appropriate "ADDR" * handler. This handler will typically use some manner of standard * array math (base + size * offset). * * Second, if the array access has been strength-reduced, the element * address is already available to us in strengthReducedValue(). * * So. If the array has not been strength-reduced, we use the first * method. If the array has been strength-reduced, we use the second * method. If the array has been strength-reduced and we are testing * the strength reduction code, we use both methods and compare the * results. */ /* Return the name of a C variable that points to appropriate array element. */ static const string OSRaddr(CodeContext &context, OSRArrayAccessNode *t) { const TypeNode *ty = t->array()->type(); const CtType &eltType = ty->elementType()->cType(); bool isLocal = ty->isLocal(); const string result = t->offsetString() + 'Z' + int2string(unique2((void *) t->WRTloop(), (void *) t)); context.declare(result, ctBox(eltType, isLocal)); context << lgMacro("SUM", isLocal) << "(" << eltType << " *, " << result << ", " << t->codeString() << ", " << t->offsetString() << ");" << endCline; return result; } /* Strength reduced accesses still need a bounds check inside a "partial domain" foreach. */ static void outputBoundsCheck(ArrayAccessNode *t, CodeContext &context) { if (isSRArrayAccessNode(t) || isOSRArrayAccessNode(t)) { ForEachStmtNode *loop = (ForEachStmtNode *) t->WRTloop(); if (bounds_checking && loop->partialDomain()) { TreeNode *array = t->array(); TreeNode *index = t->index(); const string arr = array->emitExpression(context); const string ind = index->emitExpression(context); context << callGridMethod(*array->type(), "_BOUNDSCHECK", "(\"" + index->position().asString() + "\", " "&" + arr + ", " + ind + ")") << ";" << endCline; } } } const string ArrayAccessNode::getLvalue( CodeContext &context ) { const bool isReduced = isStrengthReduced(); const bool isLocal = array()->type()->isLocal(); string standard, reduced, result; // Compute the standard element address if (test_sr || !isReduced) { const CtType &elementType = array()->type()->elementType()->cType(); const CtReference &elementAddrType = ctBox( elementType, isLocalLvalue() ); const string arrayTemp = array()->simpleVar( context ); const string indexTemp = index()->emitExpression( context ); result = standard = declareTemporary( context, elementAddrType ); context << cArrayHandler( "ADDR", true /* arrayTemp && indexTemp both simpleLVals */) << '(' << result << ", " << arrayTemp << ", " << indexTemp << ", \"" << position().asString() << "\");" << endCline; } // Compute the strength-reduced element address if (isReduced) { outputBoundsCheck(this, context); result = reduced = isSRArrayAccessNode(this) ? static_cast(this)->codeString() : OSRaddr(context, static_cast(this)); } // They both better be the same if (test_sr && isReduced) context << "assert(" << lgMacro("EQUAL", isLocal) << "(" << standard << ", " << reduced << "));" << endCline; return result; } const string JavaArrayAccessNode::getLvalue( CodeContext &context ) { // temporary used to hold address of "length" field context.depend( ctBox(PrimitiveDecl::IntDecl.cType(), array()->type()->isLocal() ) ); // offsets of "length" and "data" fields context.depend( array()->type()->decl()->cType() ); return ArrayAccessNode::getLvalue( context ); } /**********************************************************************/ /* Output code equivalent to "dest = *address". The resulting code should be executed for side effects only. local indicates whether address is a local pointer. */ string load(const string &dest, const string &address, const TypeNode *type, bool local) { return lgMacro("DEREF", local) + assignSuffix(assignType(type), local) + '(' + dest + ", " + address + ")"; } const string ArrayAccessNode::emitExpression( CodeContext &context ) { const TypeNode &arrayType = *array()->type(); const bool arrayLocal = arrayType.isLocal(); const string address = getLvalue( context ); const TypeNode &elemType = *arrayType.elementType(); const string elemValue = declareTemporary( context, elemType.cType() ); arrayType.fencePreRead( context ); context << load(elemValue, address, (const TypeNode *) &elemType, arrayLocal) << ';' << endCline; arrayType.fencePostRead( context ); if (!arrayLocal && elemType.isLocal()) { // when accessing a global array of local elements, the // resulting element value must be widened from local to global const string box = "TO_BOX(" + address + ')'; return elemType.emitGlobalize( context, box, elemValue ); } else return elemValue; } void ArrayAccessNode::receiveAssign( ostream &out, const string &lvalue, const string &value, AssignKind kind, const TypeNode *type) { AssignType atype; assert(array()->type()->isArrayType()); atype = assignType(array()->type()->elementType()); type->fencePreWrite( out ); out << makeAssign( lvalue, value, array()->type()->isLocal(), kind, atype, false ) << ';' << endCline; type->fencePostWrite( out ); } /**********************************************************************/ const string ArrayInitNode::emitExpression( CodeContext &context ) { vector< string > elements; initializers()->emitExpressionList( context, elements ); const int length = elements.size(); const string array = declareTemporary( context ); context << "JAVA_ARRAY_ALLOC(" << array << ", NULL, " << length << ", " << type()->elementType()->cType() << ", " << type()->elementType()->isAtomic() << ", " << (type()->sharing() == Shared) << ");" << endCline; for (unsigned fill = 0; fill < elements.size(); ++fill) { type()->fencePreWrite( context ); context << array << "->data[" << fill << "] = " << elements[fill] << ';' << endCline; type()->fencePostWrite( context ); } context.depend( type()->decl()->cType() ); return array; } ///////////////////////////////////////////////////////////////////////////// bool ArrayAccessNode::isStrengthReduced() const { return false; } bool SRArrayAccessNode::isStrengthReduced() const { return true; } bool OSRArrayAccessNode::isStrengthReduced() const { return true; }