[wasm] Int64Lowering of Int64Add on ia32 and arm.
Int64Add is lowered to a new turbofan operator, Int32AddPair. The new operator takes 4 inputs an generates 2 outputs. The inputs are the low word of the left input, high word of the left input, the low word of the right input, and high word of the right input. The ouputs are the low and high word of the result of the addition. R=titzer@chromium.org, v8-arm-ports@googlegroups.com Review URL: https://codereview.chromium.org/1778493004 Cr-Commit-Position: refs/heads/master@{#34747}
This commit is contained in:
parent
2cd9877b6d
commit
1b23079936
@ -787,6 +787,17 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
__ teq(i.InputRegister(0), i.InputOperand2(1));
|
__ teq(i.InputRegister(0), i.InputOperand2(1));
|
||||||
DCHECK_EQ(SetCC, i.OutputSBit());
|
DCHECK_EQ(SetCC, i.OutputSBit());
|
||||||
break;
|
break;
|
||||||
|
case kArmAddPair:
|
||||||
|
// i.InputRegister(0) ... left low word.
|
||||||
|
// i.InputRegister(1) ... left high word.
|
||||||
|
// i.InputRegister(2) ... right low word.
|
||||||
|
// i.InputRegister(3) ... right high word.
|
||||||
|
__ add(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2),
|
||||||
|
SBit::SetCC);
|
||||||
|
__ adc(i.OutputRegister(1), i.InputRegister(1),
|
||||||
|
Operand(i.InputRegister(3)));
|
||||||
|
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
||||||
|
break;
|
||||||
case kArmPairLsl:
|
case kArmPairLsl:
|
||||||
if (instr->InputAt(2)->IsImmediate()) {
|
if (instr->InputAt(2)->IsImmediate()) {
|
||||||
__ PairLsl(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
|
__ PairLsl(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
|
||||||
|
@ -46,6 +46,7 @@ namespace compiler {
|
|||||||
V(ArmUxtab) \
|
V(ArmUxtab) \
|
||||||
V(ArmRbit) \
|
V(ArmRbit) \
|
||||||
V(ArmUxtah) \
|
V(ArmUxtah) \
|
||||||
|
V(ArmAddPair) \
|
||||||
V(ArmPairLsl) \
|
V(ArmPairLsl) \
|
||||||
V(ArmVcmpF32) \
|
V(ArmVcmpF32) \
|
||||||
V(ArmVaddF32) \
|
V(ArmVaddF32) \
|
||||||
|
@ -48,6 +48,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
|||||||
case kArmUxtab:
|
case kArmUxtab:
|
||||||
case kArmUxtah:
|
case kArmUxtah:
|
||||||
case kArmRbit:
|
case kArmRbit:
|
||||||
|
case kArmAddPair:
|
||||||
case kArmPairLsl:
|
case kArmPairLsl:
|
||||||
case kArmVcmpF32:
|
case kArmVcmpF32:
|
||||||
case kArmVaddF32:
|
case kArmVaddF32:
|
||||||
|
@ -767,6 +767,22 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
|
|||||||
VisitShift(this, node, TryMatchASR);
|
VisitShift(this, node, TryMatchASR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstructionSelector::VisitInt32PairAdd(Node* node) {
|
||||||
|
ArmOperandGenerator g(this);
|
||||||
|
|
||||||
|
// We use UseUniqueRegister here to avoid register sharing with the output
|
||||||
|
// registers.
|
||||||
|
InstructionOperand inputs[] = {
|
||||||
|
g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
|
||||||
|
g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
|
||||||
|
|
||||||
|
InstructionOperand outputs[] = {
|
||||||
|
g.DefineAsRegister(node),
|
||||||
|
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
|
||||||
|
|
||||||
|
Emit(kArmAddPair, 2, outputs, 4, inputs);
|
||||||
|
}
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShl(Node* node) {
|
void InstructionSelector::VisitWord32PairShl(Node* node) {
|
||||||
ArmOperandGenerator g(this);
|
ArmOperandGenerator g(this);
|
||||||
Int32Matcher m(node->InputAt(2));
|
Int32Matcher m(node->InputAt(2));
|
||||||
|
@ -677,6 +677,31 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
|
|||||||
__ sar_cl(i.OutputOperand());
|
__ sar_cl(i.OutputOperand());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case kIA32AddPair: {
|
||||||
|
// i.OutputRegister(0) == i.InputRegister(0) ... left low word.
|
||||||
|
// i.InputRegister(1) ... left high word.
|
||||||
|
// i.InputRegister(2) ... right low word.
|
||||||
|
// i.InputRegister(3) ... right high word.
|
||||||
|
bool use_temp = false;
|
||||||
|
if (i.OutputRegister(0).code() == i.InputRegister(1).code() ||
|
||||||
|
i.OutputRegister(0).code() == i.InputRegister(3).code()) {
|
||||||
|
// We cannot write to the output register directly, because it would
|
||||||
|
// overwrite an input for adc. We have to use the temp register.
|
||||||
|
use_temp = true;
|
||||||
|
__ Move(i.TempRegister(0), i.InputRegister(0));
|
||||||
|
__ add(i.TempRegister(0), i.InputRegister(2));
|
||||||
|
} else {
|
||||||
|
__ add(i.OutputRegister(0), i.InputRegister(2));
|
||||||
|
}
|
||||||
|
__ adc(i.InputRegister(1), Operand(i.InputRegister(3)));
|
||||||
|
if (i.OutputRegister(1).code() != i.InputRegister(1).code()) {
|
||||||
|
__ Move(i.OutputRegister(1), i.InputRegister(1));
|
||||||
|
}
|
||||||
|
if (use_temp) {
|
||||||
|
__ Move(i.OutputRegister(0), i.TempRegister(0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case kIA32ShlPair:
|
case kIA32ShlPair:
|
||||||
if (HasImmediateInput(instr, 2)) {
|
if (HasImmediateInput(instr, 2)) {
|
||||||
__ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
|
__ ShlPair(i.InputRegister(1), i.InputRegister(0), i.InputInt6(2));
|
||||||
|
@ -29,6 +29,7 @@ namespace compiler {
|
|||||||
V(IA32Shl) \
|
V(IA32Shl) \
|
||||||
V(IA32Shr) \
|
V(IA32Shr) \
|
||||||
V(IA32Sar) \
|
V(IA32Sar) \
|
||||||
|
V(IA32AddPair) \
|
||||||
V(IA32ShlPair) \
|
V(IA32ShlPair) \
|
||||||
V(IA32ShrPair) \
|
V(IA32ShrPair) \
|
||||||
V(IA32SarPair) \
|
V(IA32SarPair) \
|
||||||
|
@ -31,6 +31,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
|||||||
case kIA32Shl:
|
case kIA32Shl:
|
||||||
case kIA32Shr:
|
case kIA32Shr:
|
||||||
case kIA32Sar:
|
case kIA32Sar:
|
||||||
|
case kIA32AddPair:
|
||||||
case kIA32ShlPair:
|
case kIA32ShlPair:
|
||||||
case kIA32ShrPair:
|
case kIA32ShrPair:
|
||||||
case kIA32SarPair:
|
case kIA32SarPair:
|
||||||
|
@ -583,6 +583,24 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
|
|||||||
VisitShift(this, node, kIA32Sar);
|
VisitShift(this, node, kIA32Sar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstructionSelector::VisitInt32PairAdd(Node* node) {
|
||||||
|
IA32OperandGenerator g(this);
|
||||||
|
|
||||||
|
// We use UseUniqueRegister here to avoid register sharing with the temp
|
||||||
|
// register.
|
||||||
|
InstructionOperand inputs[] = {
|
||||||
|
g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
|
||||||
|
g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
|
||||||
|
|
||||||
|
InstructionOperand outputs[] = {
|
||||||
|
g.DefineSameAsFirst(node),
|
||||||
|
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
|
||||||
|
|
||||||
|
InstructionOperand temps[] = {g.TempRegister()};
|
||||||
|
|
||||||
|
Emit(kIA32AddPair, 2, outputs, 4, inputs, 1, temps);
|
||||||
|
}
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShl(Node* node) {
|
void InstructionSelector::VisitWord32PairShl(Node* node) {
|
||||||
IA32OperandGenerator g(this);
|
IA32OperandGenerator g(this);
|
||||||
|
|
||||||
|
@ -1150,6 +1150,10 @@ void InstructionSelector::VisitNode(Node* node) {
|
|||||||
}
|
}
|
||||||
case IrOpcode::kCheckedStore:
|
case IrOpcode::kCheckedStore:
|
||||||
return VisitCheckedStore(node);
|
return VisitCheckedStore(node);
|
||||||
|
case IrOpcode::kInt32PairAdd:
|
||||||
|
MarkAsWord32(NodeProperties::FindProjection(node, 0));
|
||||||
|
MarkAsWord32(NodeProperties::FindProjection(node, 1));
|
||||||
|
return VisitInt32PairAdd(node);
|
||||||
case IrOpcode::kWord32PairShl:
|
case IrOpcode::kWord32PairShl:
|
||||||
MarkAsWord32(NodeProperties::FindProjection(node, 0));
|
MarkAsWord32(NodeProperties::FindProjection(node, 0));
|
||||||
MarkAsWord32(NodeProperties::FindProjection(node, 1));
|
MarkAsWord32(NodeProperties::FindProjection(node, 1));
|
||||||
@ -1387,6 +1391,8 @@ void InstructionSelector::VisitBitcastInt64ToFloat64(Node* node) {
|
|||||||
|
|
||||||
// 32 bit targets do not implement the following instructions.
|
// 32 bit targets do not implement the following instructions.
|
||||||
#if V8_TARGET_ARCH_64_BIT
|
#if V8_TARGET_ARCH_64_BIT
|
||||||
|
void InstructionSelector::VisitInt32PairAdd(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
|
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); }
|
void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); }
|
||||||
@ -1471,6 +1477,7 @@ void InstructionSelector::VisitProjection(Node* node) {
|
|||||||
case IrOpcode::kTryTruncateFloat64ToInt64:
|
case IrOpcode::kTryTruncateFloat64ToInt64:
|
||||||
case IrOpcode::kTryTruncateFloat32ToUint64:
|
case IrOpcode::kTryTruncateFloat32ToUint64:
|
||||||
case IrOpcode::kTryTruncateFloat64ToUint64:
|
case IrOpcode::kTryTruncateFloat64ToUint64:
|
||||||
|
case IrOpcode::kInt32PairAdd:
|
||||||
case IrOpcode::kWord32PairShl:
|
case IrOpcode::kWord32PairShl:
|
||||||
case IrOpcode::kWord32PairShr:
|
case IrOpcode::kWord32PairShr:
|
||||||
case IrOpcode::kWord32PairSar:
|
case IrOpcode::kWord32PairSar:
|
||||||
|
@ -251,6 +251,25 @@ void Int64Lowering::LowerNode(Node* node) {
|
|||||||
// todo(ahaas): I added a list of missing instructions here to make merging
|
// todo(ahaas): I added a list of missing instructions here to make merging
|
||||||
// easier when I do them one by one.
|
// easier when I do them one by one.
|
||||||
// kExprI64Add:
|
// kExprI64Add:
|
||||||
|
case IrOpcode::kInt64Add: {
|
||||||
|
DCHECK(node->InputCount() == 2);
|
||||||
|
|
||||||
|
Node* right = node->InputAt(1);
|
||||||
|
node->ReplaceInput(1, GetReplacementLow(right));
|
||||||
|
node->AppendInput(zone(), GetReplacementHigh(right));
|
||||||
|
|
||||||
|
Node* left = node->InputAt(0);
|
||||||
|
node->ReplaceInput(0, GetReplacementLow(left));
|
||||||
|
node->InsertInput(zone(), 1, GetReplacementHigh(left));
|
||||||
|
|
||||||
|
NodeProperties::ChangeOp(node, machine()->Int32PairAdd());
|
||||||
|
// We access the additional return values through projections.
|
||||||
|
Node* low_node = graph()->NewNode(common()->Projection(0), node);
|
||||||
|
Node* high_node = graph()->NewNode(common()->Projection(1), node);
|
||||||
|
ReplaceNode(node, low_node, high_node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// kExprI64Sub:
|
// kExprI64Sub:
|
||||||
// kExprI64Mul:
|
// kExprI64Mul:
|
||||||
// kExprI64DivS:
|
// kExprI64DivS:
|
||||||
|
@ -196,6 +196,7 @@ MachineRepresentation StackSlotRepresentationOf(Operator const* op) {
|
|||||||
V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \
|
V(LoadStackPointer, Operator::kNoProperties, 0, 0, 1) \
|
||||||
V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \
|
V(LoadFramePointer, Operator::kNoProperties, 0, 0, 1) \
|
||||||
V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1) \
|
V(LoadParentFramePointer, Operator::kNoProperties, 0, 0, 1) \
|
||||||
|
V(Int32PairAdd, Operator::kNoProperties, 4, 0, 2) \
|
||||||
V(Word32PairShl, Operator::kNoProperties, 3, 0, 2) \
|
V(Word32PairShl, Operator::kNoProperties, 3, 0, 2) \
|
||||||
V(Word32PairShr, Operator::kNoProperties, 3, 0, 2) \
|
V(Word32PairShr, Operator::kNoProperties, 3, 0, 2) \
|
||||||
V(Word32PairSar, Operator::kNoProperties, 3, 0, 2)
|
V(Word32PairSar, Operator::kNoProperties, 3, 0, 2)
|
||||||
|
@ -179,6 +179,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
|||||||
const OptionalOperator Word64Ctz();
|
const OptionalOperator Word64Ctz();
|
||||||
const Operator* Word64Equal();
|
const Operator* Word64Equal();
|
||||||
|
|
||||||
|
const Operator* Int32PairAdd();
|
||||||
const Operator* Word32PairShl();
|
const Operator* Word32PairShl();
|
||||||
const Operator* Word32PairShr();
|
const Operator* Word32PairShr();
|
||||||
const Operator* Word32PairSar();
|
const Operator* Word32PairSar();
|
||||||
|
@ -395,6 +395,8 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
|
|||||||
VisitRRO(this, kMipsSar, node);
|
VisitRRO(this, kMipsSar, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstructionSelector::VisitInt32PairAdd(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
|
void InstructionSelector::VisitWord32PairShl(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); }
|
void InstructionSelector::VisitWord32PairShr(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
@ -334,6 +334,7 @@
|
|||||||
V(LoadParentFramePointer) \
|
V(LoadParentFramePointer) \
|
||||||
V(CheckedLoad) \
|
V(CheckedLoad) \
|
||||||
V(CheckedStore) \
|
V(CheckedStore) \
|
||||||
|
V(Int32PairAdd) \
|
||||||
V(Word32PairShl) \
|
V(Word32PairShl) \
|
||||||
V(Word32PairShr) \
|
V(Word32PairShr) \
|
||||||
V(Word32PairSar)
|
V(Word32PairSar)
|
||||||
|
@ -898,6 +898,9 @@ void InstructionSelector::VisitInt64Add(Node* node) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !V8_TARGET_ARCH_PPC64
|
||||||
|
void InstructionSelector::VisitInt32PairAdd(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
void InstructionSelector::VisitInt32Sub(Node* node) {
|
void InstructionSelector::VisitInt32Sub(Node* node) {
|
||||||
PPCOperandGenerator g(this);
|
PPCOperandGenerator g(this);
|
||||||
|
@ -324,6 +324,9 @@ class RawMachineAssembler {
|
|||||||
Node* Uint64Mod(Node* a, Node* b) {
|
Node* Uint64Mod(Node* a, Node* b) {
|
||||||
return AddNode(machine()->Uint64Mod(), a, b);
|
return AddNode(machine()->Uint64Mod(), a, b);
|
||||||
}
|
}
|
||||||
|
Node* Int32PairAdd(Node* a_low, Node* a_high, Node* b_low, Node* b_high) {
|
||||||
|
return AddNode(machine()->Int32PairAdd(), a_low, a_high, b_low, b_high);
|
||||||
|
}
|
||||||
Node* Word32PairShl(Node* low_word, Node* high_word, Node* shift) {
|
Node* Word32PairShl(Node* low_word, Node* high_word, Node* shift) {
|
||||||
return AddNode(machine()->Word32PairShl(), low_word, high_word, shift);
|
return AddNode(machine()->Word32PairShl(), low_word, high_word, shift);
|
||||||
}
|
}
|
||||||
|
@ -2441,6 +2441,8 @@ Type* Typer::Visitor::TypeCheckedStore(Node* node) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type* Typer::Visitor::TypeInt32PairAdd(Node* node) { return Type::Internal(); }
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeWord32PairShl(Node* node) { return Type::Internal(); }
|
Type* Typer::Visitor::TypeWord32PairShl(Node* node) { return Type::Internal(); }
|
||||||
|
|
||||||
Type* Typer::Visitor::TypeWord32PairShr(Node* node) { return Type::Internal(); }
|
Type* Typer::Visitor::TypeWord32PairShr(Node* node) { return Type::Internal(); }
|
||||||
|
@ -946,6 +946,7 @@ void Verifier::Visitor::Check(Node* node) {
|
|||||||
case IrOpcode::kFloat64ExtractHighWord32:
|
case IrOpcode::kFloat64ExtractHighWord32:
|
||||||
case IrOpcode::kFloat64InsertLowWord32:
|
case IrOpcode::kFloat64InsertLowWord32:
|
||||||
case IrOpcode::kFloat64InsertHighWord32:
|
case IrOpcode::kFloat64InsertHighWord32:
|
||||||
|
case IrOpcode::kInt32PairAdd:
|
||||||
case IrOpcode::kWord32PairShl:
|
case IrOpcode::kWord32PairShl:
|
||||||
case IrOpcode::kWord32PairShr:
|
case IrOpcode::kWord32PairShr:
|
||||||
case IrOpcode::kWord32PairSar:
|
case IrOpcode::kWord32PairSar:
|
||||||
|
@ -494,6 +494,9 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
|
|||||||
// todo(ahaas): I added a list of missing instructions here to make merging
|
// todo(ahaas): I added a list of missing instructions here to make merging
|
||||||
// easier when I do them one by one.
|
// easier when I do them one by one.
|
||||||
// kExprI64Add:
|
// kExprI64Add:
|
||||||
|
case wasm::kExprI64Add:
|
||||||
|
op = m->Int64Add();
|
||||||
|
break;
|
||||||
// kExprI64Sub:
|
// kExprI64Sub:
|
||||||
// kExprI64Mul:
|
// kExprI64Mul:
|
||||||
// kExprI64DivS:
|
// kExprI64DivS:
|
||||||
@ -559,9 +562,6 @@ Node* WasmGraphBuilder::Binop(wasm::WasmOpcode opcode, Node* left,
|
|||||||
#if WASM_64
|
#if WASM_64
|
||||||
// Opcodes only supported on 64-bit platforms.
|
// Opcodes only supported on 64-bit platforms.
|
||||||
// TODO(titzer): query the machine operator builder here instead of #ifdef.
|
// TODO(titzer): query the machine operator builder here instead of #ifdef.
|
||||||
case wasm::kExprI64Add:
|
|
||||||
op = m->Int64Add();
|
|
||||||
break;
|
|
||||||
case wasm::kExprI64Sub:
|
case wasm::kExprI64Sub:
|
||||||
op = m->Int64Sub();
|
op = m->Int64Sub();
|
||||||
break;
|
break;
|
||||||
|
@ -544,6 +544,8 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
|
|||||||
VisitShift(this, node, kX87Sar);
|
VisitShift(this, node, kX87Sar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstructionSelector::VisitInt32PairAdd(Node* node) { UNIMPLEMENTED(); }
|
||||||
|
|
||||||
void InstructionSelector::VisitWord32PairShl(Node* node) {
|
void InstructionSelector::VisitWord32PairShl(Node* node) {
|
||||||
X87OperandGenerator g(this);
|
X87OperandGenerator g(this);
|
||||||
|
|
||||||
|
@ -29,29 +29,18 @@ struct ByteMnemonic {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const ByteMnemonic two_operands_instr[] = {
|
static const ByteMnemonic two_operands_instr[] = {
|
||||||
{0x01, "add", OPER_REG_OP_ORDER},
|
{0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
|
||||||
{0x03, "add", REG_OPER_OP_ORDER},
|
{0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER},
|
||||||
{0x09, "or", OPER_REG_OP_ORDER},
|
{0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER},
|
||||||
{0x0B, "or", REG_OPER_OP_ORDER},
|
{0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER},
|
||||||
{0x1B, "sbb", REG_OPER_OP_ORDER},
|
{0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER},
|
||||||
{0x21, "and", OPER_REG_OP_ORDER},
|
{0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
|
||||||
{0x23, "and", REG_OPER_OP_ORDER},
|
{0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
|
||||||
{0x29, "sub", OPER_REG_OP_ORDER},
|
{0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
|
||||||
{0x2A, "subb", REG_OPER_OP_ORDER},
|
{0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
|
||||||
{0x2B, "sub", REG_OPER_OP_ORDER},
|
{0x85, "test", REG_OPER_OP_ORDER}, {0x87, "xchg", REG_OPER_OP_ORDER},
|
||||||
{0x31, "xor", OPER_REG_OP_ORDER},
|
{0x8A, "mov_b", REG_OPER_OP_ORDER}, {0x8B, "mov", REG_OPER_OP_ORDER},
|
||||||
{0x33, "xor", REG_OPER_OP_ORDER},
|
{0x8D, "lea", REG_OPER_OP_ORDER}, {-1, "", UNSET_OP_ORDER}};
|
||||||
{0x38, "cmpb", OPER_REG_OP_ORDER},
|
|
||||||
{0x39, "cmp", OPER_REG_OP_ORDER},
|
|
||||||
{0x3A, "cmpb", REG_OPER_OP_ORDER},
|
|
||||||
{0x3B, "cmp", REG_OPER_OP_ORDER},
|
|
||||||
{0x84, "test_b", REG_OPER_OP_ORDER},
|
|
||||||
{0x85, "test", REG_OPER_OP_ORDER},
|
|
||||||
{0x87, "xchg", REG_OPER_OP_ORDER},
|
|
||||||
{0x8A, "mov_b", REG_OPER_OP_ORDER},
|
|
||||||
{0x8B, "mov", REG_OPER_OP_ORDER},
|
|
||||||
{0x8D, "lea", REG_OPER_OP_ORDER},
|
|
||||||
{-1, "", UNSET_OP_ORDER}};
|
|
||||||
|
|
||||||
static const ByteMnemonic zero_operands_instr[] = {
|
static const ByteMnemonic zero_operands_instr[] = {
|
||||||
{0xC3, "ret", UNSET_OP_ORDER},
|
{0xC3, "ret", UNSET_OP_ORDER},
|
||||||
|
@ -4197,6 +4197,74 @@ TEST(RunTruncateFloat64ToFloat32) {
|
|||||||
FOR_FLOAT64_INPUTS(i) { CHECK_FLOAT_EQ(DoubleToFloat32(*i), m.Call(*i)); }
|
FOR_FLOAT64_INPUTS(i) { CHECK_FLOAT_EQ(DoubleToFloat32(*i), m.Call(*i)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t ToInt64(uint32_t low, uint32_t high) {
|
||||||
|
return (static_cast<int64_t>(high) << 32) | static_cast<int64_t>(low);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if V8_TARGET_ARCH_32_BIT
|
||||||
|
TEST(RunInt32PairAdd) {
|
||||||
|
BufferedRawMachineAssemblerTester<int32_t> m(
|
||||||
|
MachineType::Int32(), MachineType::Int32(), MachineType::Int32(),
|
||||||
|
MachineType::Int32());
|
||||||
|
|
||||||
|
uint32_t high;
|
||||||
|
uint32_t low;
|
||||||
|
|
||||||
|
Node* PairAdd = m.Int32PairAdd(m.Parameter(0), m.Parameter(1), m.Parameter(2),
|
||||||
|
m.Parameter(3));
|
||||||
|
|
||||||
|
m.StoreToPointer(&low, MachineRepresentation::kWord32,
|
||||||
|
m.Projection(0, PairAdd));
|
||||||
|
m.StoreToPointer(&high, MachineRepresentation::kWord32,
|
||||||
|
m.Projection(1, PairAdd));
|
||||||
|
m.Return(m.Int32Constant(74));
|
||||||
|
|
||||||
|
FOR_INT64_INPUTS(i) {
|
||||||
|
FOR_INT64_INPUTS(j) {
|
||||||
|
m.Call(static_cast<int32_t>(*i & 0xffffffff),
|
||||||
|
static_cast<int32_t>(*i >> 32),
|
||||||
|
static_cast<int32_t>(*j & 0xffffffff),
|
||||||
|
static_cast<int32_t>(*j >> 32));
|
||||||
|
CHECK_EQ(*i + *j, ToInt64(low, high));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestInt32PairAddWithSharedInput(int a, int b, int c, int d) {
|
||||||
|
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
|
||||||
|
MachineType::Uint32());
|
||||||
|
|
||||||
|
uint32_t high;
|
||||||
|
uint32_t low;
|
||||||
|
|
||||||
|
Node* PairAdd = m.Int32PairAdd(m.Parameter(a), m.Parameter(b), m.Parameter(c),
|
||||||
|
m.Parameter(d));
|
||||||
|
|
||||||
|
m.StoreToPointer(&low, MachineRepresentation::kWord32,
|
||||||
|
m.Projection(0, PairAdd));
|
||||||
|
m.StoreToPointer(&high, MachineRepresentation::kWord32,
|
||||||
|
m.Projection(1, PairAdd));
|
||||||
|
m.Return(m.Int32Constant(74));
|
||||||
|
|
||||||
|
FOR_UINT32_INPUTS(i) {
|
||||||
|
FOR_UINT32_INPUTS(j) {
|
||||||
|
m.Call(*i, *j);
|
||||||
|
uint32_t inputs[] = {*i, *j};
|
||||||
|
CHECK_EQ(ToInt64(inputs[a], inputs[b]) + ToInt64(inputs[c], inputs[d]),
|
||||||
|
ToInt64(low, high));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RunInt32PairAddWithSharedInput) {
|
||||||
|
TestInt32PairAddWithSharedInput(0, 0, 0, 0);
|
||||||
|
TestInt32PairAddWithSharedInput(1, 0, 0, 0);
|
||||||
|
TestInt32PairAddWithSharedInput(0, 1, 0, 0);
|
||||||
|
TestInt32PairAddWithSharedInput(0, 0, 1, 0);
|
||||||
|
TestInt32PairAddWithSharedInput(0, 0, 0, 1);
|
||||||
|
TestInt32PairAddWithSharedInput(1, 1, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(RunDeadChangeFloat64ToInt32) {
|
TEST(RunDeadChangeFloat64ToInt32) {
|
||||||
RawMachineAssemblerTester<int32_t> m;
|
RawMachineAssemblerTester<int32_t> m;
|
||||||
|
@ -96,6 +96,7 @@ TEST(DisasmIa320) {
|
|||||||
__ nop();
|
__ nop();
|
||||||
__ add(ebx, Immediate(12));
|
__ add(ebx, Immediate(12));
|
||||||
__ nop();
|
__ nop();
|
||||||
|
__ adc(edx, Operand(ebx));
|
||||||
__ adc(ecx, 12);
|
__ adc(ecx, 12);
|
||||||
__ adc(ecx, 1000);
|
__ adc(ecx, 1000);
|
||||||
__ nop();
|
__ nop();
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
V(I64Return, true) \
|
V(I64Return, true) \
|
||||||
V(I64Param, true) \
|
V(I64Param, true) \
|
||||||
V(I64LoadStore, true) \
|
V(I64LoadStore, true) \
|
||||||
V(I64Add, false) \
|
V(I64Add, true) \
|
||||||
V(I64Sub, false) \
|
V(I64Sub, false) \
|
||||||
V(I64Mul, false) \
|
V(I64Mul, false) \
|
||||||
V(I64DivS, false) \
|
V(I64DivS, false) \
|
||||||
@ -118,6 +118,14 @@ TEST(Run_Wasm_Return_I64) {
|
|||||||
// todo(ahaas): I added a list of missing instructions here to make merging
|
// todo(ahaas): I added a list of missing instructions here to make merging
|
||||||
// easier when I do them one by one.
|
// easier when I do them one by one.
|
||||||
// kExprI64Add:
|
// kExprI64Add:
|
||||||
|
TEST(Run_WasmI64Add) {
|
||||||
|
REQUIRE(I64Add);
|
||||||
|
WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64());
|
||||||
|
BUILD(r, WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
|
||||||
|
FOR_INT64_INPUTS(i) {
|
||||||
|
FOR_INT64_INPUTS(j) { CHECK_EQ(*i + *j, r.Call(*i, *j)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
// kExprI64Sub:
|
// kExprI64Sub:
|
||||||
// kExprI64Mul:
|
// kExprI64Mul:
|
||||||
// kExprI64DivS:
|
// kExprI64DivS:
|
||||||
|
@ -302,6 +302,21 @@ TEST_F(Int64LoweringTest, CallI64Parameter) {
|
|||||||
// todo(ahaas): I added a list of missing instructions here to make merging
|
// todo(ahaas): I added a list of missing instructions here to make merging
|
||||||
// easier when I do them one by one.
|
// easier when I do them one by one.
|
||||||
// kExprI64Add:
|
// kExprI64Add:
|
||||||
|
TEST_F(Int64LoweringTest, Int64Add) {
|
||||||
|
LowerGraph(graph()->NewNode(machine()->Int64Add(), Int64Constant(value(0)),
|
||||||
|
Int64Constant(value(1))),
|
||||||
|
MachineRepresentation::kWord64);
|
||||||
|
|
||||||
|
Capture<Node*> add;
|
||||||
|
Matcher<Node*> add_matcher = IsInt32PairAdd(
|
||||||
|
IsInt32Constant(low_word_value(0)), IsInt32Constant(high_word_value(0)),
|
||||||
|
IsInt32Constant(low_word_value(1)), IsInt32Constant(high_word_value(1)));
|
||||||
|
|
||||||
|
EXPECT_THAT(graph()->end()->InputAt(1),
|
||||||
|
IsReturn2(IsProjection(0, AllOf(CaptureEq(&add), add_matcher)),
|
||||||
|
IsProjection(1, AllOf(CaptureEq(&add), add_matcher)),
|
||||||
|
start(), start()));
|
||||||
|
}
|
||||||
// kExprI64Sub:
|
// kExprI64Sub:
|
||||||
// kExprI64Mul:
|
// kExprI64Mul:
|
||||||
// kExprI64DivS:
|
// kExprI64DivS:
|
||||||
|
@ -1406,6 +1406,50 @@ class IsLoadContextMatcher final : public NodeMatcher {
|
|||||||
const Matcher<Node*> context_matcher_;
|
const Matcher<Node*> context_matcher_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IsQuadopMatcher final : public NodeMatcher {
|
||||||
|
public:
|
||||||
|
IsQuadopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& a_matcher,
|
||||||
|
const Matcher<Node*>& b_matcher,
|
||||||
|
const Matcher<Node*>& c_matcher,
|
||||||
|
const Matcher<Node*>& d_matcher)
|
||||||
|
: NodeMatcher(opcode),
|
||||||
|
a_matcher_(a_matcher),
|
||||||
|
b_matcher_(b_matcher),
|
||||||
|
c_matcher_(c_matcher),
|
||||||
|
d_matcher_(d_matcher) {}
|
||||||
|
|
||||||
|
void DescribeTo(std::ostream* os) const final {
|
||||||
|
NodeMatcher::DescribeTo(os);
|
||||||
|
*os << " whose a (";
|
||||||
|
a_matcher_.DescribeTo(os);
|
||||||
|
*os << ") and b (";
|
||||||
|
b_matcher_.DescribeTo(os);
|
||||||
|
*os << ") and c (";
|
||||||
|
c_matcher_.DescribeTo(os);
|
||||||
|
*os << ") and d (";
|
||||||
|
d_matcher_.DescribeTo(os);
|
||||||
|
*os << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatchAndExplain(Node* node, MatchResultListener* listener) const final {
|
||||||
|
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||||
|
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "a",
|
||||||
|
a_matcher_, listener) &&
|
||||||
|
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "b",
|
||||||
|
b_matcher_, listener) &&
|
||||||
|
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2), "c",
|
||||||
|
c_matcher_, listener) &&
|
||||||
|
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 3), "d",
|
||||||
|
d_matcher_, listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Matcher<Node*> a_matcher_;
|
||||||
|
const Matcher<Node*> b_matcher_;
|
||||||
|
const Matcher<Node*> c_matcher_;
|
||||||
|
const Matcher<Node*> d_matcher_;
|
||||||
|
};
|
||||||
|
|
||||||
class IsTernopMatcher final : public NodeMatcher {
|
class IsTernopMatcher final : public NodeMatcher {
|
||||||
public:
|
public:
|
||||||
IsTernopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
|
IsTernopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
|
||||||
@ -2104,6 +2148,16 @@ Matcher<Node*> IsLoadFramePointer() {
|
|||||||
return MakeMatcher(new NodeMatcher(IrOpcode::kLoadFramePointer));
|
return MakeMatcher(new NodeMatcher(IrOpcode::kLoadFramePointer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define IS_QUADOP_MATCHER(Name) \
|
||||||
|
Matcher<Node*> Is##Name( \
|
||||||
|
const Matcher<Node*>& a_matcher, const Matcher<Node*>& b_matcher, \
|
||||||
|
const Matcher<Node*>& c_matcher, const Matcher<Node*>& d_matcher) { \
|
||||||
|
return MakeMatcher(new IsQuadopMatcher(IrOpcode::k##Name, a_matcher, \
|
||||||
|
b_matcher, c_matcher, d_matcher)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
IS_QUADOP_MATCHER(Int32PairAdd)
|
||||||
|
|
||||||
#define IS_TERNOP_MATCHER(Name) \
|
#define IS_TERNOP_MATCHER(Name) \
|
||||||
Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \
|
Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \
|
||||||
const Matcher<Node*>& mid_matcher, \
|
const Matcher<Node*>& mid_matcher, \
|
||||||
|
@ -358,6 +358,10 @@ Matcher<Node*> IsNumberToUint32(const Matcher<Node*>& input_matcher);
|
|||||||
Matcher<Node*> IsParameter(const Matcher<int> index_matcher);
|
Matcher<Node*> IsParameter(const Matcher<int> index_matcher);
|
||||||
Matcher<Node*> IsLoadFramePointer();
|
Matcher<Node*> IsLoadFramePointer();
|
||||||
|
|
||||||
|
Matcher<Node*> IsInt32PairAdd(const Matcher<Node*>& a_matcher,
|
||||||
|
const Matcher<Node*>& b_matcher,
|
||||||
|
const Matcher<Node*>& c_matcher,
|
||||||
|
const Matcher<Node*>& d_matcher);
|
||||||
Matcher<Node*> IsWord32PairShl(const Matcher<Node*>& lhs_matcher,
|
Matcher<Node*> IsWord32PairShl(const Matcher<Node*>& lhs_matcher,
|
||||||
const Matcher<Node*>& mid_matcher,
|
const Matcher<Node*>& mid_matcher,
|
||||||
const Matcher<Node*>& rhs_matcher);
|
const Matcher<Node*>& rhs_matcher);
|
||||||
|
Loading…
Reference in New Issue
Block a user