public override AstNode Visit(BinaryOperation node) { // Process the left expression. Expression left = node.GetLeftExpression(); left = (Expression)left.Accept(this); node.SetLeftExpression(left); // Process the right expression. Expression right = node.GetRightExpression(); right = (Expression)right.Accept(this); node.SetRightExpression(node); // Get the node type. IChelaType nodeType = node.GetNodeType(); if(!nodeType.IsConstant()) return node; // Perform left constant coercion. ConstantValue leftConstant = (ConstantValue)left.GetNodeValue(); IChelaType leftType = left.GetNodeType(); IChelaType leftCoercion = node.GetCoercionType(); if(leftType != leftCoercion) leftConstant = leftConstant.Cast(leftCoercion); // Perform right constant coercion. ConstantValue rightConstant = (ConstantValue)right.GetNodeValue(); IChelaType rightType = right.GetNodeType(); IChelaType rightCoercion = node.GetSecondCoercion(); if(rightType != rightCoercion) rightConstant = rightConstant.Cast(rightCoercion); // Perform the constant operation. ConstantValue res = null; switch(node.GetOperation()) { case BinaryOperation.OpAdd: res = leftConstant + rightConstant; break; case BinaryOperation.OpSub: res = leftConstant - rightConstant; break; case BinaryOperation.OpMul: res = leftConstant * rightConstant; break; case BinaryOperation.OpDiv: res = leftConstant / rightConstant; break; case BinaryOperation.OpMod: res = leftConstant % rightConstant; break; case BinaryOperation.OpEQ: res = ConstantValue.Equals(leftConstant, rightConstant); break; case BinaryOperation.OpNEQ: res = ConstantValue.NotEquals(leftConstant, rightConstant); break; case BinaryOperation.OpLT: res = leftConstant < rightConstant; break; case BinaryOperation.OpLEQ: res = leftConstant <= rightConstant; break; case BinaryOperation.OpGT: res = leftConstant > rightConstant; break; case BinaryOperation.OpGEQ: res = leftConstant >= rightConstant; break; case BinaryOperation.OpBitAnd: res = leftConstant & rightConstant; break; case BinaryOperation.OpBitOr: res = leftConstant | rightConstant; break; case BinaryOperation.OpBitXor: res = leftConstant ^ rightConstant; break; case BinaryOperation.OpBitLeft: res = ConstantValue.BitLeft(leftConstant, rightConstant); break; case BinaryOperation.OpBitRight: res = ConstantValue.BitRight(leftConstant, rightConstant); break; case BinaryOperation.OpLAnd: res = new ConstantValue(leftConstant.GetBoolValue() && rightConstant.GetBoolValue()); break; case BinaryOperation.OpLOr: res = new ConstantValue(leftConstant.GetBoolValue() || rightConstant.GetBoolValue()); break; default: throw new System.NotImplementedException(); } // Return the result node. return res.ToAstNode(node.GetPosition()); }
public override AstNode Visit(BinaryOperation node) { // Begin the node. builder.BeginNode(node); // Get the expressions. Expression left = node.GetLeftExpression(); Expression right = node.GetRightExpression(); // Get the types. IChelaType leftType = left.GetNodeType(); IChelaType rightType = right.GetNodeType(); IChelaType coercionType = node.GetCoercionType(); IChelaType secondCoercion = node.GetSecondCoercion(); IChelaType operationType = node.GetOperationType(); IChelaType destType = node.GetNodeType(); // Special pipeline for operator overloading. Function overload = node.GetOverload(); if(overload != null) { FunctionType overloadType = overload.GetFunctionType(); coercionType = overloadType.GetArgument(0); secondCoercion = overloadType.GetArgument(1); // Send first the left operand. left.Accept(this); if(leftType != coercionType) Cast(node, left.GetNodeValue(), leftType, coercionType); // Now send the right operand. right.Accept(this); if(rightType != secondCoercion) Cast(node, right.GetNodeValue(), rightType, secondCoercion); // Perform the call. builder.CreateCall(overload, 2); // Return the node. return builder.EndNode(); } // Send the left operand. left.Accept(this); if(leftType != coercionType) Cast(node, left.GetNodeValue(), leftType, coercionType); // Short circuit operations has special evaluation orders. if(node.GetOperation() == BinaryOperation.OpLAnd || node.GetOperation() == BinaryOperation.OpLOr) { BasicBlock continueBlock = CreateBasicBlock(); continueBlock.SetName("shc"); BasicBlock stopBlock = CreateBasicBlock(); stopBlock.SetName("shs"); BasicBlock mergeBlock = CreateBasicBlock(); mergeBlock.SetName("shm"); // Perform left branch. if(node.GetOperation() == BinaryOperation.OpLAnd) builder.CreateBr(continueBlock, stopBlock); else builder.CreateBr(stopBlock, continueBlock); // Build stop. builder.SetBlock(stopBlock); builder.CreateLoadBool(node.GetOperation() == BinaryOperation.OpLOr); builder.CreateJmp(mergeBlock); // Build continue block. builder.SetBlock(continueBlock); // Send the right operand verbatim. right.Accept(this); if(rightType != secondCoercion) Cast(node, right.GetNodeValue(), rightType, secondCoercion); builder.CreateJmp(mergeBlock); // Continue with the control flow. builder.SetBlock(mergeBlock); return builder.EndNode(); } // Send the right operand. right.Accept(this); if(rightType != secondCoercion) Cast(node, right.GetNodeValue(), rightType, secondCoercion); switch(node.GetOperation()) { case BinaryOperation.OpAdd: builder.CreateAdd(); break; case BinaryOperation.OpSub: builder.CreateSub(); break; case BinaryOperation.OpMul: if(node.IsMatrixMul()) builder.CreateMatMul(); else builder.CreateMul(); break; case BinaryOperation.OpDiv: builder.CreateDiv(); break; case BinaryOperation.OpMod: builder.CreateMod(); break; case BinaryOperation.OpBitAnd: builder.CreateAnd(); break; case BinaryOperation.OpBitOr: builder.CreateOr(); break; case BinaryOperation.OpBitXor: builder.CreateXor(); break; case BinaryOperation.OpBitLeft: builder.CreateShLeft(); break; case BinaryOperation.OpBitRight: builder.CreateShRight(); break; case BinaryOperation.OpLT: builder.CreateCmpLT(); break; case BinaryOperation.OpGT: builder.CreateCmpGT(); break; case BinaryOperation.OpEQ: builder.CreateCmpEQ(); break; case BinaryOperation.OpNEQ: builder.CreateCmpNE(); break; case BinaryOperation.OpLEQ: builder.CreateCmpLE(); break; case BinaryOperation.OpGEQ: builder.CreateCmpGE(); break; case BinaryOperation.OpLAnd: case BinaryOperation.OpLOr: // Shouldn't reach here. break; } // Cast the result. if(operationType != destType) Cast(node, null, operationType, destType); return builder.EndNode(); }