package com.oracle.truffle.llvm.runtime.nodes.asm;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.llvm.runtime.nodes.asm.support.LLVMAMD64UpdateFlagsNode.LLVMAMD64UpdateCPZSOFlagsNode;
import com.oracle.truffle.llvm.runtime.nodes.asm.support.LLVMAMD64WriteTupelNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMStatementNode;
@NodeChild(value = "left", type = LLVMExpressionNode.class)
@NodeChild(value = "right", type = LLVMExpressionNode.class)
public abstract class LLVMAMD64XaddNode extends LLVMStatementNode {
@Child protected LLVMAMD64UpdateCPZSOFlagsNode flags;
@Child protected LLVMAMD64WriteTupelNode out;
private LLVMAMD64XaddNode(LLVMAMD64UpdateCPZSOFlagsNode flags, LLVMAMD64WriteTupelNode out) {
this.flags = flags;
this.out = out;
}
public abstract static class LLVMAMD64XaddbNode extends LLVMAMD64XaddNode {
public LLVMAMD64XaddbNode(LLVMAMD64UpdateCPZSOFlagsNode flags, LLVMAMD64WriteTupelNode out) {
super(flags, out);
}
@Specialization
protected void doOp(VirtualFrame frame, byte left, byte right) {
byte result = (byte) (left + right);
boolean overflow = (result < 0 && left > 0 && right > 0) || (result > 0 && left < 0 && right < 0);
boolean carry = ((left < 0 || right < 0) && result > 0) || (left < 0 && right < 0);
flags.execute(frame, overflow, carry, result);
out.execute(frame, right, result);
}
}
public abstract static class LLVMAMD64XaddwNode extends LLVMAMD64XaddNode {
public LLVMAMD64XaddwNode(LLVMAMD64UpdateCPZSOFlagsNode flags, LLVMAMD64WriteTupelNode out) {
super(flags, out);
}
@Specialization
protected void doOp(VirtualFrame frame, short left, short right) {
short result = (short) (left + right);
boolean overflow = (result < 0 && left > 0 && right > 0) || (result > 0 && left < 0 && right < 0);
boolean carry = ((left < 0 || right < 0) && result > 0) || (left < 0 && right < 0);
flags.execute(frame, overflow, carry, result);
out.execute(frame, right, result);
}
}
public abstract static class LLVMAMD64XaddlNode extends LLVMAMD64XaddNode {
public LLVMAMD64XaddlNode(LLVMAMD64UpdateCPZSOFlagsNode flags, LLVMAMD64WriteTupelNode out) {
super(flags, out);
}
@Specialization
protected void doOp(VirtualFrame frame, int left, int right) {
int result = left + right;
boolean overflow = (result < 0 && left > 0 && right > 0) || (result > 0 && left < 0 && right < 0);
boolean carry = ((left < 0 || right < 0) && result > 0) || (left < 0 && right < 0);
flags.execute(frame, overflow, carry, result);
out.execute(frame, right, result);
}
}
public abstract static class LLVMAMD64XaddqNode extends LLVMAMD64XaddNode {
public LLVMAMD64XaddqNode(LLVMAMD64UpdateCPZSOFlagsNode flags, LLVMAMD64WriteTupelNode out) {
super(flags, out);
}
@Specialization
protected void doOp(VirtualFrame frame, long left, long right) {
long result = left + right;
boolean overflow = (result < 0 && left > 0 && right > 0) || (result > 0 && left < 0 && right < 0);
boolean carry = ((left < 0 || right < 0) && result > 0) || (left < 0 && right < 0);
flags.execute(frame, overflow, carry, result);
out.execute(frame, right, result);
}
}
}