Commit 99023682 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Trim graph before scheduling.

The scheduler expects a trimmed graph, so we have to trim the graph
before scheduling.

R=titzer@chromium.org, bmeurer@chromium.org
TEST=cctest/test-run-wasm/RunWasmCompiled_GraphTrimming

Review-Url: https://chromiumcodereview.appspot.com/2428443002
Cr-Commit-Position: refs/heads/master@{#40446}
parent 03b85541
......@@ -1084,33 +1084,42 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ mla(i.OutputRegister(1), i.InputRegister(2), i.InputRegister(1),
i.OutputRegister(1));
break;
case kArmLslPair:
case kArmLslPair: {
Register second_output =
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
if (instr->InputAt(2)->IsImmediate()) {
__ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ LslPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), i.InputInt32(2));
} else {
__ LslPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ LslPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), kScratchReg, i.InputRegister(2));
}
break;
case kArmLsrPair:
}
case kArmLsrPair: {
Register second_output =
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
if (instr->InputAt(2)->IsImmediate()) {
__ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ LsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), i.InputInt32(2));
} else {
__ LsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ LsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), kScratchReg, i.InputRegister(2));
}
break;
case kArmAsrPair:
}
case kArmAsrPair: {
Register second_output =
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
if (instr->InputAt(2)->IsImmediate()) {
__ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ AsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), i.InputInt32(2));
} else {
__ AsrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ AsrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), kScratchReg, i.InputRegister(2));
}
break;
}
case kArmVcmpF32:
if (instr->InputAt(1)->IsFPRegister()) {
__ VFPCompareAndSetFlags(i.InputFloat32Register(0),
......
......@@ -957,76 +957,83 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
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);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
// 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);
} else {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kArmAdd | AddressingModeField::encode(kMode_Operand2_R),
g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(2)));
}
}
void InstructionSelector::VisitInt32PairSub(Node* node) {
ArmOperandGenerator g(this);
// We use UseUniqueRegister here to avoid register sharing with the output
// register.
InstructionOperand inputs[] = {
g.UseRegister(node->InputAt(0)), g.UseUniqueRegister(node->InputAt(1)),
g.UseRegister(node->InputAt(2)), g.UseUniqueRegister(node->InputAt(3))};
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
// We use UseUniqueRegister here to avoid register sharing with the output
// 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.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Emit(kArmSubPair, 2, outputs, 4, inputs);
Emit(kArmSubPair, 2, outputs, 4, inputs);
} else {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kArmSub | AddressingModeField::encode(kMode_Operand2_R),
g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(2)));
}
}
void InstructionSelector::VisitInt32PairMul(Node* node) {
ArmOperandGenerator g(this);
InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
g.UseUniqueRegister(node->InputAt(1)),
g.UseUniqueRegister(node->InputAt(2)),
g.UseUniqueRegister(node->InputAt(3))};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Emit(kArmMulPair, 2, outputs, 4, inputs);
}
void InstructionSelector::VisitWord32PairShl(Node* node) {
ArmOperandGenerator g(this);
// We use g.UseUniqueRegister here for InputAt(0) to guarantee that there is
// no register aliasing with output registers.
Int32Matcher m(node->InputAt(2));
InstructionOperand shift_operand;
if (m.HasValue()) {
shift_operand = g.UseImmediate(m.node());
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
g.UseUniqueRegister(node->InputAt(1)),
g.UseUniqueRegister(node->InputAt(2)),
g.UseUniqueRegister(node->InputAt(3))};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Emit(kArmMulPair, 2, outputs, 4, inputs);
} else {
shift_operand = g.UseUniqueRegister(m.node());
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kArmMul | AddressingModeField::encode(kMode_Operand2_R),
g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(2)));
}
InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(1)),
shift_operand};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Emit(kArmLslPair, 2, outputs, 3, inputs);
}
void InstructionSelector::VisitWord32PairShr(Node* node) {
ArmOperandGenerator g(this);
// We use g.UseUniqueRegister here for InputAt(1) and InputAt(2) to to
// guarantee that there is no register aliasing with output register.
namespace {
// Shared routine for multiple shift operations.
void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
Node* node) {
ArmOperandGenerator g(selector);
// We use g.UseUniqueRegister here to guarantee that there is
// no register aliasing of input registers with output registers.
Int32Matcher m(node->InputAt(2));
InstructionOperand shift_operand;
if (m.HasValue()) {
......@@ -1035,38 +1042,37 @@ void InstructionSelector::VisitWord32PairShr(Node* node) {
shift_operand = g.UseUniqueRegister(m.node());
}
InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
g.UseUniqueRegister(node->InputAt(1)),
shift_operand};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Node* projection1 = NodeProperties::FindProjection(node, 1);
Emit(kArmLsrPair, 2, outputs, 3, inputs);
}
InstructionOperand outputs[2];
InstructionOperand temps[1];
int32_t output_count = 0;
int32_t temp_count = 0;
void InstructionSelector::VisitWord32PairSar(Node* node) {
ArmOperandGenerator g(this);
// We use g.UseUniqueRegister here for InputAt(1) and InputAt(2) to to
// guarantee that there is no register aliasing with output register.
Int32Matcher m(node->InputAt(2));
InstructionOperand shift_operand;
if (m.HasValue()) {
shift_operand = g.UseImmediate(m.node());
outputs[output_count++] = g.DefineAsRegister(node);
if (projection1) {
outputs[output_count++] = g.DefineAsRegister(projection1);
} else {
shift_operand = g.UseUniqueRegister(m.node());
temps[temp_count++] = g.TempRegister();
}
InstructionOperand inputs[] = {g.UseRegister(node->InputAt(0)),
g.UseUniqueRegister(node->InputAt(1)),
shift_operand};
selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
}
} // namespace
void InstructionSelector::VisitWord32PairShl(Node* node) {
VisitWord32PairShift(this, kArmLslPair, node);
}
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
void InstructionSelector::VisitWord32PairShr(Node* node) {
VisitWord32PairShift(this, kArmLsrPair, node);
}
Emit(kArmAsrPair, 2, outputs, 3, inputs);
void InstructionSelector::VisitWord32PairSar(Node* node) {
VisitWord32PairShift(this, kArmAsrPair, node);
}
void InstructionSelector::VisitWord32Ror(Node* node) {
......
......@@ -646,55 +646,78 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
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))};
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
// 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 outputs[] = {g.DefineSameAsFirst(node),
g.DefineAsRegister(projection1)};
InstructionOperand temps[] = {g.TempRegister()};
InstructionOperand temps[] = {g.TempRegister()};
Emit(kIA32AddPair, 2, outputs, 4, inputs, 1, temps);
Emit(kIA32AddPair, 2, outputs, 4, inputs, 1, temps);
} else {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kIA32Add, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
g.Use(node->InputAt(2)));
}
}
void InstructionSelector::VisitInt32PairSub(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))};
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
// 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 outputs[] = {g.DefineSameAsFirst(node),
g.DefineAsRegister(projection1)};
InstructionOperand temps[] = {g.TempRegister()};
InstructionOperand temps[] = {g.TempRegister()};
Emit(kIA32SubPair, 2, outputs, 4, inputs, 1, temps);
Emit(kIA32SubPair, 2, outputs, 4, inputs, 1, temps);
} else {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kIA32Sub, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
g.Use(node->InputAt(2)));
}
}
void InstructionSelector::VisitInt32PairMul(Node* node) {
IA32OperandGenerator g(this);
// InputAt(3) explicitly shares ecx with OutputRegister(1) to save one
// register and one mov instruction.
InstructionOperand inputs[] = {
g.UseUnique(node->InputAt(0)), g.UseUnique(node->InputAt(1)),
g.UseUniqueRegister(node->InputAt(2)), g.UseFixed(node->InputAt(3), ecx)};
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
// InputAt(3) explicitly shares ecx with OutputRegister(1) to save one
// register and one mov instruction.
InstructionOperand inputs[] = {g.UseUnique(node->InputAt(0)),
g.UseUnique(node->InputAt(1)),
g.UseUniqueRegister(node->InputAt(2)),
g.UseFixed(node->InputAt(3), ecx)};
InstructionOperand outputs[] = {
g.DefineAsFixed(node, eax),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)};
InstructionOperand outputs[] = {
g.DefineAsFixed(node, eax),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), ecx)};
InstructionOperand temps[] = {g.TempRegister(edx)};
InstructionOperand temps[] = {g.TempRegister(edx)};
Emit(kIA32MulPair, 2, outputs, 4, inputs, 1, temps);
Emit(kIA32MulPair, 2, outputs, 4, inputs, 1, temps);
} else {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
Emit(kIA32Imul, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)),
g.Use(node->InputAt(2)));
}
}
void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
......@@ -712,11 +735,19 @@ void VisitWord32PairShift(InstructionSelector* selector, InstructionCode opcode,
g.UseFixed(node->InputAt(1), edx),
shift_operand};
InstructionOperand outputs[] = {
g.DefineAsFixed(node, eax),
g.DefineAsFixed(NodeProperties::FindProjection(node, 1), edx)};
InstructionOperand outputs[2];
InstructionOperand temps[1];
int32_t output_count = 0;
int32_t temp_count = 0;
outputs[output_count++] = g.DefineAsFixed(node, eax);
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
outputs[output_count++] = g.DefineAsFixed(projection1, edx);
} else {
temps[temp_count++] = g.TempRegister(edx);
}
selector->Emit(opcode, 2, outputs, 3, inputs);
selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
}
void InstructionSelector::VisitWord32PairShl(Node* node) {
......
......@@ -933,6 +933,16 @@ void InstructionSelector::VisitControl(BasicBlock* block) {
}
}
void InstructionSelector::MarkPairProjectionsAsWord32(Node* node) {
Node* projection0 = NodeProperties::FindProjection(node, 0);
if (projection0) {
MarkAsWord32(projection0);
}
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
MarkAsWord32(projection1);
}
}
void InstructionSelector::VisitNode(Node* node) {
DCHECK_NOT_NULL(schedule()->block(node)); // should only use scheduled nodes.
......@@ -1340,28 +1350,28 @@ void InstructionSelector::VisitNode(Node* node) {
case IrOpcode::kCheckedStore:
return VisitCheckedStore(node);
case IrOpcode::kInt32PairAdd:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
MarkAsWord32(node);
MarkPairProjectionsAsWord32(node);
return VisitInt32PairAdd(node);
case IrOpcode::kInt32PairSub:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
MarkAsWord32(node);
MarkPairProjectionsAsWord32(node);
return VisitInt32PairSub(node);
case IrOpcode::kInt32PairMul:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
MarkAsWord32(node);
MarkPairProjectionsAsWord32(node);
return VisitInt32PairMul(node);
case IrOpcode::kWord32PairShl:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
MarkAsWord32(node);
MarkPairProjectionsAsWord32(node);
return VisitWord32PairShl(node);
case IrOpcode::kWord32PairShr:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
MarkAsWord32(node);
MarkPairProjectionsAsWord32(node);
return VisitWord32PairShr(node);
case IrOpcode::kWord32PairSar:
MarkAsWord32(NodeProperties::FindProjection(node, 0));
MarkAsWord32(NodeProperties::FindProjection(node, 1));
MarkAsWord32(node);
MarkPairProjectionsAsWord32(node);
return VisitWord32PairSar(node);
case IrOpcode::kAtomicLoad: {
LoadRepresentation type = LoadRepresentationOf(node->op());
......
......@@ -347,6 +347,8 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
}
bool instruction_selection_failed() { return instruction_selection_failed_; }
void MarkPairProjectionsAsWord32(Node* node);
// ===========================================================================
Zone* const zone_;
......
......@@ -976,32 +976,38 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
break;
case kMipsShlPair: {
Register second_output =
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
if (instr->InputAt(2)->IsRegister()) {
__ ShlPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), i.InputRegister(2));
} else {
uint32_t imm = i.InputOperand(2).immediate();
__ ShlPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ ShlPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), imm);
}
} break;
case kMipsShrPair: {
Register second_output =
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
if (instr->InputAt(2)->IsRegister()) {
__ ShrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), i.InputRegister(2));
} else {
uint32_t imm = i.InputOperand(2).immediate();
__ ShrPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ ShrPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), imm);
}
} break;
case kMipsSarPair: {
Register second_output =
instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
if (instr->InputAt(2)->IsRegister()) {
__ SarPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), i.InputRegister(2));
} else {
uint32_t imm = i.InputOperand(2).immediate();
__ SarPair(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
__ SarPair(i.OutputRegister(0), second_output, i.InputRegister(0),
i.InputRegister(1), imm);
}
} break;
......
......@@ -429,32 +429,43 @@ void InstructionSelector::VisitWord32Sar(Node* node) {
}
static void VisitInt32PairBinop(InstructionSelector* selector,
InstructionCode opcode, Node* node) {
InstructionCode pair_opcode,
InstructionCode single_opcode, Node* node) {
MipsOperandGenerator g(selector);
// We use UseUniqueRegister here to avoid register sharing with the output
// register.
InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
g.UseUniqueRegister(node->InputAt(1)),
g.UseUniqueRegister(node->InputAt(2)),
g.UseUniqueRegister(node->InputAt(3))};
Node* projection1 = NodeProperties::FindProjection(node, 1);
if (projection1) {
// We use UseUniqueRegister here to avoid register sharing with the output
// register.
InstructionOperand inputs[] = {g.UseUniqueRegister(node->InputAt(0)),
g.UseUniqueRegister(node->InputAt(1)),
g.UseUniqueRegister(node->InputAt(2)),
g.UseUniqueRegister(node->InputAt(3))};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
selector->Emit(opcode, 2, outputs, 4, inputs);
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
selector->Emit(pair_opcode, 2, outputs, 4, inputs);
} else {
// The high word of the result is not used, so we emit the standard 32 bit
// instruction.
selector->Emit(single_opcode, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(0)),
g.UseRegister(node->InputAt(2)));
}
}
void InstructionSelector::VisitInt32PairAdd(Node* node) {
VisitInt32PairBinop(this, kMipsAddPair, node);
VisitInt32PairBinop(this, kMipsAddPair, kMipsAdd, node);
}
void InstructionSelector::VisitInt32PairSub(Node* node) {
VisitInt32PairBinop(this, kMipsSubPair, node);
VisitInt32PairBinop(this, kMipsSubPair, kMipsSub, node);
}
void InstructionSelector::VisitInt32PairMul(Node* node) {
VisitInt32PairBinop(this, kMipsMulPair, node);
VisitInt32PairBinop(this, kMipsMulPair, kMipsMul, node);
}
// Shared routine for multiple shift operations.
......@@ -475,11 +486,21 @@ static void VisitWord32PairShift(InstructionSelector* selector,
g.UseUniqueRegister(node->InputAt(1)),
shift_operand};
InstructionOperand outputs[] = {
g.DefineAsRegister(node),
g.DefineAsRegister(NodeProperties::FindProjection(node, 1))};
Node* projection1 = NodeProperties::FindProjection(node, 1);
InstructionOperand outputs[2];
InstructionOperand temps[1];
int32_t output_count = 0;
int32_t temp_count = 0;
outputs[output_count++] = g.DefineAsRegister(node);
if (projection1) {
outputs[output_count++] = g.DefineAsRegister(projection1);
} else {
temps[temp_count++] = g.TempRegister();
}
selector->Emit(opcode, 2, outputs, 3, inputs);
selector->Emit(opcode, output_count, outputs, 3, inputs, temp_count, temps);
}
void InstructionSelector::VisitWord32PairShl(Node* node) {
......
......@@ -389,7 +389,7 @@ class PipelineImpl final {
// Perform the actual code generation and return handle to a code object.
Handle<Code> GenerateCode(Linkage* linkage);
bool ScheduleAndSelectInstructions(Linkage* linkage);
bool ScheduleAndSelectInstructions(Linkage* linkage, bool trim_graph);
void RunPrintAndVerify(const char* phase, bool untyped = false);
Handle<Code> ScheduleAndGenerateCode(CallDescriptor* call_descriptor);
void AllocateRegisters(const RegisterConfiguration* config,
......@@ -692,7 +692,7 @@ PipelineWasmCompilationJob::ExecuteJobImpl() {
pipeline_.RunPrintAndVerify("Machine", true);
if (!pipeline_.ScheduleAndSelectInstructions(&linkage_)) return FAILED;
if (!pipeline_.ScheduleAndSelectInstructions(&linkage_, true)) return FAILED;
return SUCCEEDED;
}
......@@ -1206,7 +1206,9 @@ struct LateGraphTrimmingPhase {
void Run(PipelineData* data, Zone* temp_zone) {
GraphTrimmer trimmer(temp_zone, data->graph());
NodeVector roots(temp_zone);
data->jsgraph()->GetCachedNodes(&roots);
if (data->jsgraph()) {
data->jsgraph()->GetCachedNodes(&roots);
}
trimmer.TrimGraph(roots.begin(), roots.end());
}
};
......@@ -1650,13 +1652,9 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
RunPrintAndVerify("Late optimized", true);
Run<LateGraphTrimmingPhase>();
// TODO(jarin, rossberg): Remove UNTYPED once machine typing works.
RunPrintAndVerify("Late trimmed", true);
data->source_positions()->RemoveDecorator();
return ScheduleAndSelectInstructions(linkage);
return ScheduleAndSelectInstructions(linkage, true);
}
Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
......@@ -1769,12 +1767,17 @@ bool Pipeline::AllocateRegistersForTesting(const RegisterConfiguration* config,
return !data.compilation_failed();
}
bool PipelineImpl::ScheduleAndSelectInstructions(Linkage* linkage) {
bool PipelineImpl::ScheduleAndSelectInstructions(Linkage* linkage,
bool trim_graph) {
CallDescriptor* call_descriptor = linkage->GetIncomingDescriptor();
PipelineData* data = this->data_;
DCHECK_NOT_NULL(data->graph());
if (trim_graph) {
Run<LateGraphTrimmingPhase>();
RunPrintAndVerify("Late trimmed", true);
}
if (data->schedule() == nullptr) Run<ComputeSchedulePhase>();
TraceSchedule(data->info(), data->schedule());
......@@ -1897,7 +1900,7 @@ Handle<Code> PipelineImpl::ScheduleAndGenerateCode(
Linkage linkage(call_descriptor);
// Schedule the graph, perform instruction selection and register allocation.
if (!ScheduleAndSelectInstructions(&linkage)) return Handle<Code>();
if (!ScheduleAndSelectInstructions(&linkage, false)) return Handle<Code>();
// Generate the final machine code.
return GenerateCode(&linkage);
......
......@@ -4161,6 +4161,25 @@ TEST(RunInt32PairAdd) {
}
}
TEST(RunInt32PairAddUseOnlyHighWord) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32(),
MachineType::Uint32());
m.Return(m.Projection(1, m.Int32PairAdd(m.Parameter(0), m.Parameter(1),
m.Parameter(2), m.Parameter(3))));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
CHECK_EQ(static_cast<uint32_t>((*i + *j) >> 32),
m.Call(static_cast<uint32_t>(*i & 0xffffffff),
static_cast<uint32_t>(*i >> 32),
static_cast<uint32_t>(*j & 0xffffffff),
static_cast<uint32_t>(*j >> 32)));
}
}
}
void TestInt32PairAddWithSharedInput(int a, int b, int c, int d) {
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
MachineType::Uint32());
......@@ -4224,6 +4243,25 @@ TEST(RunInt32PairSub) {
}
}
TEST(RunInt32PairSubUseOnlyHighWord) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32(),
MachineType::Uint32());
m.Return(m.Projection(1, m.Int32PairSub(m.Parameter(0), m.Parameter(1),
m.Parameter(2), m.Parameter(3))));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
CHECK_EQ(static_cast<uint32_t>((*i - *j) >> 32),
m.Call(static_cast<uint32_t>(*i & 0xffffffff),
static_cast<uint32_t>(*i >> 32),
static_cast<uint32_t>(*j & 0xffffffff),
static_cast<uint32_t>(*j >> 32)));
}
}
}
void TestInt32PairSubWithSharedInput(int a, int b, int c, int d) {
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
MachineType::Uint32());
......@@ -4287,6 +4325,25 @@ TEST(RunInt32PairMul) {
}
}
TEST(RunInt32PairMulUseOnlyHighWord) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32(),
MachineType::Uint32());
m.Return(m.Projection(1, m.Int32PairMul(m.Parameter(0), m.Parameter(1),
m.Parameter(2), m.Parameter(3))));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
CHECK_EQ(static_cast<uint32_t>((*i * *j) >> 32),
m.Call(static_cast<uint32_t>(*i & 0xffffffff),
static_cast<uint32_t>(*i >> 32),
static_cast<uint32_t>(*j & 0xffffffff),
static_cast<uint32_t>(*j >> 32)));
}
}
}
void TestInt32PairMulWithSharedInput(int a, int b, int c, int d) {
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
MachineType::Uint32());
......@@ -4330,13 +4387,13 @@ TEST(RunWord32PairShl) {
uint32_t high;
uint32_t low;
Node* PairAdd =
Node* PairShl =
m.Word32PairShl(m.Parameter(0), m.Parameter(1), m.Parameter(2));
m.StoreToPointer(&low, MachineRepresentation::kWord32,
m.Projection(0, PairAdd));
m.Projection(0, PairShl));
m.StoreToPointer(&high, MachineRepresentation::kWord32,
m.Projection(1, PairAdd));
m.Projection(1, PairShl));
m.Return(m.Int32Constant(74));
FOR_UINT64_INPUTS(i) {
......@@ -4348,6 +4405,22 @@ TEST(RunWord32PairShl) {
}
}
TEST(RunWord32PairShlUseOnlyHighWord) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32());
m.Return(m.Projection(
1, m.Word32PairShl(m.Parameter(0), m.Parameter(1), m.Parameter(2))));
FOR_UINT64_INPUTS(i) {
for (uint32_t j = 0; j < 64; j++) {
CHECK_EQ(static_cast<uint32_t>((*i << j) >> 32),
m.Call(static_cast<uint32_t>(*i & 0xffffffff),
static_cast<uint32_t>(*i >> 32), j));
}
}
}
void TestWord32PairShlWithSharedInput(int a, int b) {
BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
MachineType::Uint32());
......@@ -4405,6 +4478,22 @@ TEST(RunWord32PairShr) {
}
}
TEST(RunWord32PairShrUseOnlyHighWord) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32());
m.Return(m.Projection(
1, m.Word32PairShr(m.Parameter(0), m.Parameter(1), m.Parameter(2))));
FOR_UINT64_INPUTS(i) {
for (uint32_t j = 0; j < 64; j++) {
CHECK_EQ(static_cast<uint32_t>((*i >> j) >> 32),
m.Call(static_cast<uint32_t>(*i & 0xffffffff),
static_cast<uint32_t>(*i >> 32), j));
}
}
}
TEST(RunWord32PairSar) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32());
......@@ -4430,6 +4519,21 @@ TEST(RunWord32PairSar) {
}
}
TEST(RunWord32PairSarUseOnlyHighWord) {
BufferedRawMachineAssemblerTester<int32_t> m(
MachineType::Uint32(), MachineType::Uint32(), MachineType::Uint32());
m.Return(m.Projection(
1, m.Word32PairSar(m.Parameter(0), m.Parameter(1), m.Parameter(2))));
FOR_INT64_INPUTS(i) {
for (uint32_t j = 0; j < 64; j++) {
CHECK_EQ(static_cast<uint32_t>((*i >> j) >> 32),
m.Call(static_cast<uint32_t>(*i & 0xffffffff),
static_cast<uint32_t>(*i >> 32), j));
}
}
}
#endif
TEST(RunDeadChangeFloat64ToInt32) {
......
......@@ -147,6 +147,93 @@ WASM_EXEC_TEST(I64Sub) {
}
}
WASM_EXEC_TEST(I64AddUseOnlyLowWord) {
REQUIRE(I64Add);
REQUIRE(I32ConvertI64);
WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I32_CONVERT_I64(
WASM_I64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(static_cast<int32_t>(*i + *j), r.Call(*i, *j));
}
}
}
WASM_EXEC_TEST(I64SubUseOnlyLowWord) {
REQUIRE(I64Sub);
REQUIRE(I32ConvertI64);
WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I32_CONVERT_I64(
WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(static_cast<int32_t>(*i - *j), r.Call(*i, *j));
}
}
}
WASM_EXEC_TEST(I64MulUseOnlyLowWord) {
REQUIRE(I64Mul);
REQUIRE(I32ConvertI64);
WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I32_CONVERT_I64(
WASM_I64_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
CHECK_EQ(static_cast<int32_t>(*i * *j), r.Call(*i, *j));
}
}
}
WASM_EXEC_TEST(I64ShlUseOnlyLowWord) {
REQUIRE(I64Shl);
REQUIRE(I32ConvertI64);
WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I32_CONVERT_I64(
WASM_I64_SHL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
uint64_t expected = static_cast<int32_t>((*i) << (*j & 0x3f));
CHECK_EQ(expected, r.Call(*i, *j));
}
}
}
WASM_EXEC_TEST(I64ShrUseOnlyLowWord) {
REQUIRE(I64ShrU);
REQUIRE(I32ConvertI64);
WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I32_CONVERT_I64(
WASM_I64_SHR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_UINT64_INPUTS(i) {
FOR_UINT64_INPUTS(j) {
uint64_t expected = static_cast<int32_t>((*i) >> (*j & 0x3f));
CHECK_EQ(expected, r.Call(*i, *j));
}
}
}
WASM_EXEC_TEST(I64SarUseOnlyLowWord) {
REQUIRE(I64ShrS);
REQUIRE(I32ConvertI64);
WasmRunner<int32_t> r(execution_mode, MachineType::Int64(),
MachineType::Int64());
BUILD(r, WASM_I32_CONVERT_I64(
WASM_I64_SAR(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))));
FOR_INT64_INPUTS(i) {
FOR_INT64_INPUTS(j) {
uint64_t expected = static_cast<int32_t>((*i) >> (*j & 0x3f));
CHECK_EQ(expected, r.Call(*i, *j));
}
}
}
WASM_EXEC_TEST(I64DivS) {
REQUIRE(I64DivS);
WasmRunner<int64_t> r(execution_mode, MachineType::Int64(),
......
......@@ -79,6 +79,14 @@ WASM_EXEC_TEST(Int32Const_many) {
}
}
WASM_EXEC_TEST(GraphTrimming) {
// This WebAssembly code requires graph trimming in the TurboFan compiler.
WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
BUILD(r, kExprGetLocal, 0, kExprGetLocal, 0, kExprGetLocal, 0, kExprI32RemS,
kExprI32Eq, kExprGetLocal, 0, kExprI32DivS, kExprUnreachable);
r.Call(1);
}
WASM_EXEC_TEST(Int32Param0) {
WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
// return(local[0])
......
......@@ -300,10 +300,6 @@ inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
FATAL(str.str().c_str());
}
builder.Int64LoweringForTesting();
if (FLAG_trace_turbo_graph) {
OFStream os(stdout);
os << AsRPO(*jsgraph->graph());
}
}
template <typename ReturnType>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment