#include "AST.h" #include "CtType.h" #include "code-call.h" #include "code-util.h" #include "decls.h" #include "errors.h" #include "lgMacro.h" const string ExprNode::emitBinOp( CodeContext &context, const char op[] ) { // Although we are only evaluating each operand once, the // temporaries are needed to guarantee evaluation order. const string operand0 = child(0)->emitExpression( context ); const string operand1 = child(1)->emitExpression( context ); return operand0 + ' ' + op + ' ' + operand1; } const string MultNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "*" ); } const string DivNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "/" ); } const string RemNode::emitExpression( CodeContext &context ) { const string operand0 = child(0)->emitExpression( context ); const string operand1 = child(1)->emitExpression( context ); if (child(0)->type()->isFloatType() || child(1)->type()->isFloatType()) return "fmod(" + operand0 + ", " + operand1 + ")"; else return operand0 + " % " + operand1; } const string PlusNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "+" ); } const string MinusNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "-" ); } const string LeftShiftLogNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "<<" ); } const string RightShiftLogNode::emitExpression( CodeContext &context ) { TypeNode *exprType = child(0)->type(); assert(exprType->isPrimitive()); // CM: Actually, the formula below is not quite right. Consider what // happens if n == 0 or if sizeof(x) == 8. Instead, use the following: // x >>> n = (x >> n) & ((~((julong) 0)) >> // (n + (sizeof(julong) - sizeof(x)) * 8)); // Note that this assumes that julong is the longest type. // CM // x >>> n = (x >> n) & ((1 << (sizeof(x) * 8 - n)) - 1) // The alternative is to cast to the unsigned version of x->type() by // defining methods in code-primitives.cc that do the type conversion. // Too bad you can't stick "unsigned" on user types in C. const string operand0 = child(0)->emitExpression( context ); const string operand1 = child(1)->emitExpression( context ); const string shiftExpr = operand0 + " >> " + operand1; const string sizeofType = "sizeof(" + string(((PrimitiveTypeNode *)exprType)->cPrimitiveTypeName()) + ")"; return string("(") + shiftExpr + ") & " + "((~((julong) 0)) >> (" + operand1 + " + (sizeof(julong) - " + sizeofType + ") * 8))"; } const string RightShiftArithNode::emitExpression( CodeContext &context ) { return emitBinOp( context, ">>" ); } const string LTNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "<" ); } const string GTNode::emitExpression( CodeContext &context ) { return emitBinOp( context, ">" ); } const string LENode::emitExpression( CodeContext &context ) { return emitBinOp( context, "<=" ); } const string GENode::emitExpression( CodeContext &context ) { return emitBinOp( context, ">=" ); } /* Returns whether t is "null" or a cast of "null." */ static bool isNull(TreeNode *t) { return t->type()->isNullType() || isCastNode(t) && isNull(t->opnd0()); } // opnd0 is a titanium array. Therefore, opnd1 must be null or we // signal an error. static const string TiArrayEQNode(TreeNode *opnd0, TreeNode *opnd1, CodeContext &context) { if (!isNull(opnd1)) { opnd1->error() << "Grids may be compared to null but not to anything else" << endl; return ""; } return callGridMethod(*opnd0->type(), "isnull", "(" + opnd0->emitExpression(context) + ")"); } static const string commonEQNode(TreeNode *opnd0, TreeNode *opnd1, CodeContext &context) { const TypeNode &type0 = *opnd0->type(); const TypeNode &type1 = *opnd1->type(); if (type0.isTitaniumArrayType()) return TiArrayEQNode(opnd0, opnd1, context); else if (type1.isTitaniumArrayType()) return TiArrayEQNode(opnd1, opnd0, context); const string operand0 = opnd0->emitExpression( context ); const string operand1 = opnd1->emitExpression( context ); if (type0.isPrimitive()) return operand0 + " == " + operand1; else { const string method = type0.isImmutable() ? (MANGLE_CLASS_EQUALS(+, ((TypeNameNode &)type0).decl()->cType())) : lgMacro( "EQUAL", type0 ); return method + '(' + operand0 + ", " + operand1 + ')'; } } const string EQNode::emitExpression( CodeContext &context ) { return commonEQNode(opnd0(), opnd1(), context); } const string TitaniumArrayEQNode::emitExpression( CodeContext &context ) { const string operand0 = opnd0()->emitExpression( context ); const string operand1 = opnd1()->emitExpression( context ); return "(memcmp(&" + operand0 + ", &" + operand1 + ", " "sizeof(" + operand0 + ")) == 0)"; } const string NENode::emitExpression( CodeContext &context ) { return "!(" + commonEQNode(opnd0(), opnd1(), context) + ")"; } const string BitAndNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "&" ); } const string BitOrNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "|" ); } const string BitXorNode::emitExpression( CodeContext &context ) { return emitBinOp( context, "^" ); }