Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc
index 1ec174d..cfa4de9 100644
--- a/src/compiler/arm/code-generator-arm.cc
+++ b/src/compiler/arm/code-generator-arm.cc
@@ -22,11 +22,35 @@
// Adds Arm-specific methods to convert InstructionOperands.
-class ArmOperandConverter : public InstructionOperandConverter {
+class ArmOperandConverter FINAL : public InstructionOperandConverter {
public:
ArmOperandConverter(CodeGenerator* gen, Instruction* instr)
: InstructionOperandConverter(gen, instr) {}
+ SwVfpRegister OutputFloat32Register(int index = 0) {
+ return ToFloat32Register(instr_->OutputAt(index));
+ }
+
+ SwVfpRegister InputFloat32Register(int index) {
+ return ToFloat32Register(instr_->InputAt(index));
+ }
+
+ SwVfpRegister ToFloat32Register(InstructionOperand* op) {
+ return ToFloat64Register(op).low();
+ }
+
+ LowDwVfpRegister OutputFloat64Register(int index = 0) {
+ return ToFloat64Register(instr_->OutputAt(index));
+ }
+
+ LowDwVfpRegister InputFloat64Register(int index) {
+ return ToFloat64Register(instr_->InputAt(index));
+ }
+
+ LowDwVfpRegister ToFloat64Register(InstructionOperand* op) {
+ return LowDwVfpRegister::from_code(ToDoubleRegister(op).code());
+ }
+
SBit OutputSBit() const {
switch (instr_->flags_mode()) {
case kFlags_branch:
@@ -44,12 +68,16 @@
switch (constant.type()) {
case Constant::kInt32:
return Operand(constant.ToInt32());
+ case Constant::kFloat32:
+ return Operand(
+ isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
case Constant::kFloat64:
return Operand(
isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
case Constant::kInt64:
case Constant::kExternalReference:
case Constant::kHeapObject:
+ case Constant::kRpoNumber:
break;
}
UNREACHABLE();
@@ -114,9 +142,8 @@
return MemOperand(r0);
}
- MemOperand InputOffset() {
- int index = 0;
- return InputOffset(&index);
+ MemOperand InputOffset(int first_index = 0) {
+ return InputOffset(&first_index);
}
MemOperand ToMemOperand(InstructionOperand* op) const {
@@ -131,6 +158,112 @@
};
+namespace {
+
+class OutOfLineLoadFloat32 FINAL : public OutOfLineCode {
+ public:
+ OutOfLineLoadFloat32(CodeGenerator* gen, SwVfpRegister result)
+ : OutOfLineCode(gen), result_(result) {}
+
+ void Generate() FINAL {
+ __ vmov(result_, std::numeric_limits<float>::quiet_NaN());
+ }
+
+ private:
+ SwVfpRegister const result_;
+};
+
+
+class OutOfLineLoadFloat64 FINAL : public OutOfLineCode {
+ public:
+ OutOfLineLoadFloat64(CodeGenerator* gen, DwVfpRegister result)
+ : OutOfLineCode(gen), result_(result) {}
+
+ void Generate() FINAL {
+ __ vmov(result_, std::numeric_limits<double>::quiet_NaN(), kScratchReg);
+ }
+
+ private:
+ DwVfpRegister const result_;
+};
+
+
+class OutOfLineLoadInteger FINAL : public OutOfLineCode {
+ public:
+ OutOfLineLoadInteger(CodeGenerator* gen, Register result)
+ : OutOfLineCode(gen), result_(result) {}
+
+ void Generate() FINAL { __ mov(result_, Operand::Zero()); }
+
+ private:
+ Register const result_;
+};
+
+} // namespace
+
+
+#define ASSEMBLE_CHECKED_LOAD_FLOAT(width) \
+ do { \
+ auto result = i.OutputFloat##width##Register(); \
+ auto offset = i.InputRegister(0); \
+ if (instr->InputAt(1)->IsRegister()) { \
+ __ cmp(offset, i.InputRegister(1)); \
+ } else { \
+ __ cmp(offset, i.InputImmediate(1)); \
+ } \
+ auto ool = new (zone()) OutOfLineLoadFloat##width(this, result); \
+ __ b(hs, ool->entry()); \
+ __ vldr(result, i.InputOffset(2)); \
+ __ bind(ool->exit()); \
+ DCHECK_EQ(LeaveCC, i.OutputSBit()); \
+ } while (0)
+
+
+#define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr) \
+ do { \
+ auto result = i.OutputRegister(); \
+ auto offset = i.InputRegister(0); \
+ if (instr->InputAt(1)->IsRegister()) { \
+ __ cmp(offset, i.InputRegister(1)); \
+ } else { \
+ __ cmp(offset, i.InputImmediate(1)); \
+ } \
+ auto ool = new (zone()) OutOfLineLoadInteger(this, result); \
+ __ b(hs, ool->entry()); \
+ __ asm_instr(result, i.InputOffset(2)); \
+ __ bind(ool->exit()); \
+ DCHECK_EQ(LeaveCC, i.OutputSBit()); \
+ } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_FLOAT(width) \
+ do { \
+ auto offset = i.InputRegister(0); \
+ if (instr->InputAt(1)->IsRegister()) { \
+ __ cmp(offset, i.InputRegister(1)); \
+ } else { \
+ __ cmp(offset, i.InputImmediate(1)); \
+ } \
+ auto value = i.InputFloat##width##Register(2); \
+ __ vstr(value, i.InputOffset(3), lo); \
+ DCHECK_EQ(LeaveCC, i.OutputSBit()); \
+ } while (0)
+
+
+#define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr) \
+ do { \
+ auto offset = i.InputRegister(0); \
+ if (instr->InputAt(1)->IsRegister()) { \
+ __ cmp(offset, i.InputRegister(1)); \
+ } else { \
+ __ cmp(offset, i.InputImmediate(1)); \
+ } \
+ auto value = i.InputRegister(2); \
+ __ asm_instr(value, i.InputOffset(3), lo); \
+ DCHECK_EQ(LeaveCC, i.OutputSBit()); \
+ } while (0)
+
+
// Assembles an instruction after register allocation, producing machine code.
void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
ArmOperandConverter i(this, instr);
@@ -166,7 +299,7 @@
break;
}
case kArchJmp:
- __ b(code_->GetLabel(i.InputBlock(0)));
+ AssembleArchJump(i.InputRpo(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArchNop:
@@ -177,8 +310,12 @@
AssembleReturn();
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
+ case kArchStackPointer:
+ __ mov(i.OutputRegister(), sp);
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArchTruncateDoubleToI:
- __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+ __ TruncateDoubleToI(i.OutputRegister(), i.InputFloat64Register(0));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmAdd:
@@ -208,6 +345,19 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
+ case kArmSmmul:
+ __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmSmmla:
+ __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+ i.InputRegister(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmUmull:
+ __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
+ i.InputRegister(1), i.OutputSBit());
+ break;
case kArmSdiv: {
CpuFeatureScope scope(masm(), SUDIV);
__ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
@@ -255,6 +405,42 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
+ case kArmSxtb:
+ __ sxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmSxth:
+ __ sxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmSxtab:
+ __ sxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+ i.InputInt32(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmSxtah:
+ __ sxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+ i.InputInt32(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmUxtb:
+ __ uxtb(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmUxth:
+ __ uxth(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmUxtab:
+ __ uxtab(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+ i.InputInt32(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ case kArmUxtah:
+ __ uxtah(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+ i.InputInt32(2));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
case kArmCmp:
__ cmp(i.InputRegister(0), i.InputOperand2(1));
DCHECK_EQ(SetCC, i.OutputSBit());
@@ -272,38 +458,38 @@
DCHECK_EQ(SetCC, i.OutputSBit());
break;
case kArmVcmpF64:
- __ VFPCompareAndSetFlags(i.InputDoubleRegister(0),
- i.InputDoubleRegister(1));
+ __ VFPCompareAndSetFlags(i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
DCHECK_EQ(SetCC, i.OutputSBit());
break;
case kArmVaddF64:
- __ vadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
- i.InputDoubleRegister(1));
+ __ vadd(i.OutputFloat64Register(), i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVsubF64:
- __ vsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
- i.InputDoubleRegister(1));
+ __ vsub(i.OutputFloat64Register(), i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmulF64:
- __ vmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
- i.InputDoubleRegister(1));
+ __ vmul(i.OutputFloat64Register(), i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmlaF64:
- __ vmla(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
- i.InputDoubleRegister(2));
+ __ vmla(i.OutputFloat64Register(), i.InputFloat64Register(1),
+ i.InputFloat64Register(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmlsF64:
- __ vmls(i.OutputDoubleRegister(), i.InputDoubleRegister(1),
- i.InputDoubleRegister(2));
+ __ vmls(i.OutputFloat64Register(), i.InputFloat64Register(1),
+ i.InputFloat64Register(2));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVdivF64:
- __ vdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
- i.InputDoubleRegister(1));
+ __ vdiv(i.OutputFloat64Register(), i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
case kArmVmodF64: {
@@ -311,45 +497,67 @@
// and generate a CallAddress instruction instead.
FrameScope scope(masm(), StackFrame::MANUAL);
__ PrepareCallCFunction(0, 2, kScratchReg);
- __ MovToFloatParameters(i.InputDoubleRegister(0),
- i.InputDoubleRegister(1));
+ __ MovToFloatParameters(i.InputFloat64Register(0),
+ i.InputFloat64Register(1));
__ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
0, 2);
// Move the result in the double result register.
- __ MovFromFloatResult(i.OutputDoubleRegister());
+ __ MovFromFloatResult(i.OutputFloat64Register());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
- case kArmVnegF64:
- __ vneg(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
- break;
case kArmVsqrtF64:
- __ vsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+ __ vsqrt(i.OutputFloat64Register(), i.InputFloat64Register(0));
break;
+ case kArmVfloorF64:
+ __ vrintm(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVceilF64:
+ __ vrintp(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVroundTruncateF64:
+ __ vrintz(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVroundTiesAwayF64:
+ __ vrinta(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVnegF64:
+ __ vneg(i.OutputFloat64Register(), i.InputFloat64Register(0));
+ break;
+ case kArmVcvtF32F64: {
+ __ vcvt_f32_f64(i.OutputFloat32Register(), i.InputFloat64Register(0));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ }
+ case kArmVcvtF64F32: {
+ __ vcvt_f64_f32(i.OutputFloat64Register(), i.InputFloat32Register(0));
+ DCHECK_EQ(LeaveCC, i.OutputSBit());
+ break;
+ }
case kArmVcvtF64S32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vmov(scratch, i.InputRegister(0));
- __ vcvt_f64_s32(i.OutputDoubleRegister(), scratch);
+ __ vcvt_f64_s32(i.OutputFloat64Register(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtF64U32: {
SwVfpRegister scratch = kScratchDoubleReg.low();
__ vmov(scratch, i.InputRegister(0));
- __ vcvt_f64_u32(i.OutputDoubleRegister(), scratch);
+ __ vcvt_f64_u32(i.OutputFloat64Register(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtS32F64: {
SwVfpRegister scratch = kScratchDoubleReg.low();
- __ vcvt_s32_f64(scratch, i.InputDoubleRegister(0));
+ __ vcvt_s32_f64(scratch, i.InputFloat64Register(0));
__ vmov(i.OutputRegister(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
case kArmVcvtU32F64: {
SwVfpRegister scratch = kScratchDoubleReg.low();
- __ vcvt_u32_f64(scratch, i.InputDoubleRegister(0));
+ __ vcvt_u32_f64(scratch, i.InputFloat64Register(0));
__ vmov(i.OutputRegister(), scratch);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
@@ -392,30 +600,26 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
- case kArmVldr32: {
- SwVfpRegister scratch = kScratchDoubleReg.low();
- __ vldr(scratch, i.InputOffset());
- __ vcvt_f64_f32(i.OutputDoubleRegister(), scratch);
+ case kArmVldrF32: {
+ __ vldr(i.OutputFloat32Register(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
- case kArmVstr32: {
+ case kArmVstrF32: {
int index = 0;
- SwVfpRegister scratch = kScratchDoubleReg.low();
MemOperand operand = i.InputOffset(&index);
- __ vcvt_f32_f64(scratch, i.InputDoubleRegister(index));
- __ vstr(scratch, operand);
+ __ vstr(i.InputFloat32Register(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
- case kArmVldr64:
- __ vldr(i.OutputDoubleRegister(), i.InputOffset());
+ case kArmVldrF64:
+ __ vldr(i.OutputFloat64Register(), i.InputOffset());
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
- case kArmVstr64: {
+ case kArmVstrF64: {
int index = 0;
MemOperand operand = i.InputOffset(&index);
- __ vstr(i.InputDoubleRegister(index), operand);
+ __ vstr(i.InputFloat64Register(index), operand);
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
@@ -436,33 +640,62 @@
DCHECK_EQ(LeaveCC, i.OutputSBit());
break;
}
+ case kCheckedLoadInt8:
+ ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsb);
+ break;
+ case kCheckedLoadUint8:
+ ASSEMBLE_CHECKED_LOAD_INTEGER(ldrb);
+ break;
+ case kCheckedLoadInt16:
+ ASSEMBLE_CHECKED_LOAD_INTEGER(ldrsh);
+ break;
+ case kCheckedLoadUint16:
+ ASSEMBLE_CHECKED_LOAD_INTEGER(ldrh);
+ break;
+ case kCheckedLoadWord32:
+ ASSEMBLE_CHECKED_LOAD_INTEGER(ldr);
+ break;
+ case kCheckedLoadFloat32:
+ ASSEMBLE_CHECKED_LOAD_FLOAT(32);
+ break;
+ case kCheckedLoadFloat64:
+ ASSEMBLE_CHECKED_LOAD_FLOAT(64);
+ break;
+ case kCheckedStoreWord8:
+ ASSEMBLE_CHECKED_STORE_INTEGER(strb);
+ break;
+ case kCheckedStoreWord16:
+ ASSEMBLE_CHECKED_STORE_INTEGER(strh);
+ break;
+ case kCheckedStoreWord32:
+ ASSEMBLE_CHECKED_STORE_INTEGER(str);
+ break;
+ case kCheckedStoreFloat32:
+ ASSEMBLE_CHECKED_STORE_FLOAT(32);
+ break;
+ case kCheckedStoreFloat64:
+ ASSEMBLE_CHECKED_STORE_FLOAT(64);
+ break;
}
}
// Assembles branches after an instruction.
-void CodeGenerator::AssembleArchBranch(Instruction* instr,
- FlagsCondition condition) {
+void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
ArmOperandConverter i(this, instr);
- Label done;
-
- // Emit a branch. The true and false targets are always the last two inputs
- // to the instruction.
- BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
- BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
- bool fallthru = IsNextInAssemblyOrder(fblock);
- Label* tlabel = code()->GetLabel(tblock);
- Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
- switch (condition) {
+ Label* tlabel = branch->true_label;
+ Label* flabel = branch->false_label;
+ switch (branch->condition) {
case kUnorderedEqual:
- __ b(vs, flabel);
- // Fall through.
+ // The "eq" condition will not catch the unordered case.
+ // The jump/fall through to false label will be used if the comparison
+ // was unordered.
case kEqual:
__ b(eq, tlabel);
break;
case kUnorderedNotEqual:
- __ b(vs, tlabel);
- // Fall through.
+ // Unordered or not equal can be tested with "ne" condtion.
+ // See ARMv7 manual A8.3 - Conditional execution.
case kNotEqual:
__ b(ne, tlabel);
break;
@@ -479,26 +712,28 @@
__ b(gt, tlabel);
break;
case kUnorderedLessThan:
- __ b(vs, flabel);
- // Fall through.
+ // The "lo" condition will not catch the unordered case.
+ // The jump/fall through to false label will be used if the comparison
+ // was unordered.
case kUnsignedLessThan:
__ b(lo, tlabel);
break;
case kUnorderedGreaterThanOrEqual:
- __ b(vs, tlabel);
- // Fall through.
+ // Unordered, greater than or equal can be tested with "hs" condtion.
+ // See ARMv7 manual A8.3 - Conditional execution.
case kUnsignedGreaterThanOrEqual:
__ b(hs, tlabel);
break;
case kUnorderedLessThanOrEqual:
- __ b(vs, flabel);
- // Fall through.
+ // The "ls" condition will not catch the unordered case.
+ // The jump/fall through to false label will be used if the comparison
+ // was unordered.
case kUnsignedLessThanOrEqual:
__ b(ls, tlabel);
break;
case kUnorderedGreaterThan:
- __ b(vs, tlabel);
- // Fall through.
+ // Unordered or greater than can be tested with "hi" condtion.
+ // See ARMv7 manual A8.3 - Conditional execution.
case kUnsignedGreaterThan:
__ b(hi, tlabel);
break;
@@ -509,8 +744,12 @@
__ b(vc, tlabel);
break;
}
- if (!fallthru) __ b(flabel); // no fallthru to flabel.
- __ bind(&done);
+ if (!branch->fallthru) __ b(flabel); // no fallthru to flabel.
+}
+
+
+void CodeGenerator::AssembleArchJump(BasicBlock::RpoNumber target) {
+ if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
}
@@ -634,28 +873,10 @@
__ stm(db_w, sp, saves);
}
} else if (descriptor->IsJSFunctionCall()) {
- CompilationInfo* info = linkage()->info();
+ CompilationInfo* info = this->info();
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
-
- // Sloppy mode functions and builtins need to replace the receiver with the
- // global proxy when called as functions (without an explicit receiver
- // object).
- // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
- if (info->strict_mode() == SLOPPY && !info->is_native()) {
- Label ok;
- // +2 for return address and saved frame pointer.
- int receiver_slot = info->scope()->num_parameters() + 2;
- __ ldr(r2, MemOperand(fp, receiver_slot * kPointerSize));
- __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
- __ b(ne, &ok);
- __ ldr(r2, GlobalObjectOperand());
- __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalProxyOffset));
- __ str(r2, MemOperand(fp, receiver_slot * kPointerSize));
- __ bind(&ok);
- }
-
} else {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
@@ -720,10 +941,10 @@
__ str(temp, g.ToMemOperand(destination));
}
} else if (source->IsConstant()) {
+ Constant src = g.ToConstant(source);
if (destination->IsRegister() || destination->IsStackSlot()) {
Register dst =
destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
- Constant src = g.ToConstant(source);
switch (src.type()) {
case Constant::kInt32:
__ mov(dst, Operand(src.ToInt32()));
@@ -731,6 +952,10 @@
case Constant::kInt64:
UNREACHABLE();
break;
+ case Constant::kFloat32:
+ __ Move(dst,
+ isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
+ break;
case Constant::kFloat64:
__ Move(dst,
isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
@@ -741,16 +966,29 @@
case Constant::kHeapObject:
__ Move(dst, src.ToHeapObject());
break;
+ case Constant::kRpoNumber:
+ UNREACHABLE(); // TODO(dcarney): loading RPO constants on arm.
+ break;
}
if (destination->IsStackSlot()) __ str(dst, g.ToMemOperand(destination));
- } else if (destination->IsDoubleRegister()) {
- DwVfpRegister result = g.ToDoubleRegister(destination);
- __ vmov(result, g.ToDouble(source));
+ } else if (src.type() == Constant::kFloat32) {
+ if (destination->IsDoubleStackSlot()) {
+ MemOperand dst = g.ToMemOperand(destination);
+ __ mov(ip, Operand(bit_cast<int32_t>(src.ToFloat32())));
+ __ str(ip, dst);
+ } else {
+ SwVfpRegister dst = g.ToFloat32Register(destination);
+ __ vmov(dst, src.ToFloat32());
+ }
} else {
- DCHECK(destination->IsDoubleStackSlot());
- DwVfpRegister temp = kScratchDoubleReg;
- __ vmov(temp, g.ToDouble(source));
- __ vstr(temp, g.ToMemOperand(destination));
+ DCHECK_EQ(Constant::kFloat64, src.type());
+ DwVfpRegister dst = destination->IsDoubleRegister()
+ ? g.ToFloat64Register(destination)
+ : kScratchDoubleReg;
+ __ vmov(dst, src.ToFloat64(), kScratchReg);
+ if (destination->IsDoubleStackSlot()) {
+ __ vstr(dst, g.ToMemOperand(destination));
+ }
}
} else if (source->IsDoubleRegister()) {
DwVfpRegister src = g.ToDoubleRegister(source);
@@ -851,7 +1089,7 @@
void CodeGenerator::EnsureSpaceForLazyDeopt() {
int space_needed = Deoptimizer::patch_size();
- if (!linkage()->info()->IsStub()) {
+ if (!info()->IsStub()) {
// Ensure that we have enough space after the previous lazy-bailout
// instruction for patching the code here.
int current_pc = masm()->pc_offset();
diff --git a/src/compiler/arm/instruction-codes-arm.h b/src/compiler/arm/instruction-codes-arm.h
index 7849ca9..ecd0b2d 100644
--- a/src/compiler/arm/instruction-codes-arm.h
+++ b/src/compiler/arm/instruction-codes-arm.h
@@ -26,12 +26,23 @@
V(ArmMul) \
V(ArmMla) \
V(ArmMls) \
+ V(ArmSmmul) \
+ V(ArmSmmla) \
+ V(ArmUmull) \
V(ArmSdiv) \
V(ArmUdiv) \
V(ArmMov) \
V(ArmMvn) \
V(ArmBfc) \
V(ArmUbfx) \
+ V(ArmSxtb) \
+ V(ArmSxth) \
+ V(ArmSxtab) \
+ V(ArmSxtah) \
+ V(ArmUxtb) \
+ V(ArmUxth) \
+ V(ArmUxtab) \
+ V(ArmUxtah) \
V(ArmVcmpF64) \
V(ArmVaddF64) \
V(ArmVsubF64) \
@@ -42,14 +53,20 @@
V(ArmVmodF64) \
V(ArmVnegF64) \
V(ArmVsqrtF64) \
+ V(ArmVfloorF64) \
+ V(ArmVceilF64) \
+ V(ArmVroundTruncateF64) \
+ V(ArmVroundTiesAwayF64) \
+ V(ArmVcvtF32F64) \
+ V(ArmVcvtF64F32) \
V(ArmVcvtF64S32) \
V(ArmVcvtF64U32) \
V(ArmVcvtS32F64) \
V(ArmVcvtU32F64) \
- V(ArmVldr32) \
- V(ArmVstr32) \
- V(ArmVldr64) \
- V(ArmVstr64) \
+ V(ArmVldrF32) \
+ V(ArmVstrF32) \
+ V(ArmVldrF64) \
+ V(ArmVstrF64) \
V(ArmLdrb) \
V(ArmLdrsb) \
V(ArmStrb) \
diff --git a/src/compiler/arm/instruction-selector-arm-unittest.cc b/src/compiler/arm/instruction-selector-arm-unittest.cc
deleted file mode 100644
index 208d2e9..0000000
--- a/src/compiler/arm/instruction-selector-arm-unittest.cc
+++ /dev/null
@@ -1,1900 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/compiler/instruction-selector-unittest.h"
-
-namespace v8 {
-namespace internal {
-namespace compiler {
-
-namespace {
-
-typedef RawMachineAssembler::Label MLabel;
-typedef Node* (RawMachineAssembler::*Constructor)(Node*, Node*);
-
-
-// Data processing instructions.
-struct DPI {
- Constructor constructor;
- const char* constructor_name;
- ArchOpcode arch_opcode;
- ArchOpcode reverse_arch_opcode;
- ArchOpcode test_arch_opcode;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const DPI& dpi) {
- return os << dpi.constructor_name;
-}
-
-
-static const DPI kDPIs[] = {
- {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmAnd, kArmTst},
- {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr, kArmOrr},
- {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmEor, kArmTeq},
- {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmAdd, kArmCmn},
- {&RawMachineAssembler::Int32Sub, "Int32Sub", kArmSub, kArmRsb, kArmCmp}};
-
-
-// Data processing instructions with overflow.
-struct ODPI {
- Constructor constructor;
- const char* constructor_name;
- ArchOpcode arch_opcode;
- ArchOpcode reverse_arch_opcode;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const ODPI& odpi) {
- return os << odpi.constructor_name;
-}
-
-
-static const ODPI kODPIs[] = {{&RawMachineAssembler::Int32AddWithOverflow,
- "Int32AddWithOverflow", kArmAdd, kArmAdd},
- {&RawMachineAssembler::Int32SubWithOverflow,
- "Int32SubWithOverflow", kArmSub, kArmRsb}};
-
-
-// Shifts.
-struct Shift {
- Constructor constructor;
- const char* constructor_name;
- int32_t i_low; // lowest possible immediate
- int32_t i_high; // highest possible immediate
- AddressingMode i_mode; // Operand2_R_<shift>_I
- AddressingMode r_mode; // Operand2_R_<shift>_R
-};
-
-
-std::ostream& operator<<(std::ostream& os, const Shift& shift) {
- return os << shift.constructor_name;
-}
-
-
-static const Shift kShifts[] = {
- {&RawMachineAssembler::Word32Sar, "Word32Sar", 1, 32,
- kMode_Operand2_R_ASR_I, kMode_Operand2_R_ASR_R},
- {&RawMachineAssembler::Word32Shl, "Word32Shl", 0, 31,
- kMode_Operand2_R_LSL_I, kMode_Operand2_R_LSL_R},
- {&RawMachineAssembler::Word32Shr, "Word32Shr", 1, 32,
- kMode_Operand2_R_LSR_I, kMode_Operand2_R_LSR_R},
- {&RawMachineAssembler::Word32Ror, "Word32Ror", 1, 31,
- kMode_Operand2_R_ROR_I, kMode_Operand2_R_ROR_R}};
-
-
-// Immediates (random subset).
-static const int32_t kImmediates[] = {
- -2147483617, -2147483606, -2113929216, -2080374784, -1996488704,
- -1879048192, -1459617792, -1358954496, -1342177265, -1275068414,
- -1073741818, -1073741777, -855638016, -805306368, -402653184,
- -268435444, -16777216, 0, 35, 61,
- 105, 116, 171, 245, 255,
- 692, 1216, 1248, 1520, 1600,
- 1888, 3744, 4080, 5888, 8384,
- 9344, 9472, 9792, 13312, 15040,
- 15360, 20736, 22272, 23296, 32000,
- 33536, 37120, 45824, 47872, 56320,
- 59392, 65280, 72704, 101376, 147456,
- 161792, 164864, 167936, 173056, 195584,
- 209920, 212992, 356352, 655360, 704512,
- 716800, 851968, 901120, 1044480, 1523712,
- 2572288, 3211264, 3588096, 3833856, 3866624,
- 4325376, 5177344, 6488064, 7012352, 7471104,
- 14090240, 16711680, 19398656, 22282240, 28573696,
- 30408704, 30670848, 43253760, 54525952, 55312384,
- 56623104, 68157440, 115343360, 131072000, 187695104,
- 188743680, 195035136, 197132288, 203423744, 218103808,
- 267386880, 268435470, 285212672, 402653185, 415236096,
- 595591168, 603979776, 603979778, 629145600, 1073741835,
- 1073741855, 1073741861, 1073741884, 1157627904, 1476395008,
- 1476395010, 1610612741, 2030043136, 2080374785, 2097152000};
-
-} // namespace
-
-
-// -----------------------------------------------------------------------------
-// Data processing instructions.
-
-
-typedef InstructionSelectorTestWithParam<DPI> InstructionSelectorDPITest;
-
-
-TEST_P(InstructionSelectorDPITest, Parameters) {
- const DPI dpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorDPITest, Immediate) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, ShiftByParameter) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
- m.Parameter(2)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, ShiftByImmediate) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return((m.*dpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
- m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithParameters) {
- const DPI dpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithImmediate) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)), &a,
- &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)), &a,
- &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithShiftByParameter) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
- m.Parameter(2)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchWithShiftByImmediate) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(m.Parameter(0),
- (m.*shift.constructor)(
- m.Parameter(1), m.Int32Constant(imm))),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(5U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch((m.*dpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
- m.Parameter(1)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(5U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfZeroWithParameters) {
- const DPI dpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch(m.Word32Equal((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
- m.Int32Constant(0)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithParameters) {
- const DPI dpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch(
- m.Word32NotEqual((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)),
- m.Int32Constant(0)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfZeroWithImmediate) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch(m.Word32Equal(
- (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
- m.Int32Constant(0)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch(m.Word32Equal(
- (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
- m.Int32Constant(0)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorDPITest, BranchIfNotZeroWithImmediate) {
- const DPI dpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch(m.Word32NotEqual(
- (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm)),
- m.Int32Constant(0)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- m.Branch(m.Word32NotEqual(
- (m.*dpi.constructor)(m.Int32Constant(imm), m.Parameter(0)),
- m.Int32Constant(0)),
- &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(1));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(dpi.test_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotEqual, s[0]->flags_condition());
- }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorDPITest,
- ::testing::ValuesIn(kDPIs));
-
-
-// -----------------------------------------------------------------------------
-// Data processing instructions with overflow.
-
-
-typedef InstructionSelectorTestWithParam<ODPI> InstructionSelectorODPITest;
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithParameters) {
- const ODPI odpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Projection(1, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 1, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 1, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithShiftByParameter) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 1, (m.*odpi.constructor)(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 1, (m.*odpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
- m.Parameter(0))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, OvfWithShiftByImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 1, (m.*odpi.constructor)(m.Parameter(0),
- (m.*shift.constructor)(
- m.Parameter(1), m.Int32Constant(imm)))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 1, (m.*odpi.constructor)(
- (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
- m.Parameter(0))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithParameters) {
- const ODPI odpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Projection(0, (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 0, (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 0, (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithShiftByParameter) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 0, (m.*odpi.constructor)(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 0, (m.*odpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)),
- m.Parameter(0))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, ValWithShiftByImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 0, (m.*odpi.constructor)(m.Parameter(0),
- (m.*shift.constructor)(
- m.Parameter(1), m.Int32Constant(imm)))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
- }
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Projection(
- 0, (m.*odpi.constructor)(
- (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
- m.Parameter(0))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_LE(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_none, s[0]->flags_mode());
- }
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithParameters) {
- const ODPI odpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithShiftByParameter) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(
- m.Parameter(0), (m.*shift.constructor)(m.Parameter(1), m.Parameter(2)));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Parameter(1)), m.Parameter(2));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BothWithShiftByImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- }
- TRACED_FOREACH(Shift, shift, kShifts) {
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- Node* n = (m.*odpi.constructor)(
- (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)),
- m.Parameter(1));
- m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
- Stream s = m.Build();
- ASSERT_LE(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchWithParameters) {
- const ODPI odpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
- m.Branch(m.Projection(1, n), &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(0));
- m.Bind(&b);
- m.Return(m.Projection(0, n));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchWithImmediate) {
- const ODPI odpi = GetParam();
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
- m.Branch(m.Projection(1, n), &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(0));
- m.Bind(&b);
- m.Return(m.Projection(0, n));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- MLabel a, b;
- Node* n = (m.*odpi.constructor)(m.Int32Constant(imm), m.Parameter(0));
- m.Branch(m.Projection(1, n), &a, &b);
- m.Bind(&a);
- m.Return(m.Int32Constant(0));
- m.Bind(&b);
- m.Return(m.Projection(0, n));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.reverse_arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchIfZeroWithParameters) {
- const ODPI odpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
- m.Branch(m.Word32Equal(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
- m.Bind(&a);
- m.Return(m.Projection(0, n));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kNotOverflow, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorODPITest, BranchIfNotZeroWithParameters) {
- const ODPI odpi = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- MLabel a, b;
- Node* n = (m.*odpi.constructor)(m.Parameter(0), m.Parameter(1));
- m.Branch(m.Word32NotEqual(m.Projection(1, n), m.Int32Constant(0)), &a, &b);
- m.Bind(&a);
- m.Return(m.Projection(0, n));
- m.Bind(&b);
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(odpi.arch_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(4U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
- EXPECT_EQ(kOverflow, s[0]->flags_condition());
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorODPITest,
- ::testing::ValuesIn(kODPIs));
-
-
-// -----------------------------------------------------------------------------
-// Shifts.
-
-
-typedef InstructionSelectorTestWithParam<Shift> InstructionSelectorShiftTest;
-
-
-TEST_P(InstructionSelectorShiftTest, Parameters) {
- const Shift shift = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return((m.*shift.constructor)(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMov, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Immediate) {
- const Shift shift = GetParam();
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return((m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMov, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameter) {
- const Shift shift = GetParam();
- {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Word32Equal(m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Parameter(2))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
- {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Word32Equal((m.*shift.constructor)(m.Parameter(1), m.Parameter(2)),
- m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualWithParameterAndImmediate) {
- const Shift shift = GetParam();
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(
- (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm)),
- m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(
- m.Parameter(0),
- (m.*shift.constructor)(m.Parameter(1), m.Int32Constant(imm))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithParameters) {
- const Shift shift = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Word32Equal(m.Int32Constant(0),
- (m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMov, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32EqualToZeroWithImmediate) {
- const Shift shift = GetParam();
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(
- m.Int32Constant(0),
- (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMov, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(2U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32NotWithParameters) {
- const Shift shift = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32Not((m.*shift.constructor)(m.Parameter(0), m.Parameter(1))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32NotWithImmediate) {
- const Shift shift = GetParam();
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Not(
- (m.*shift.constructor)(m.Parameter(0), m.Int32Constant(imm))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithParameters) {
- const Shift shift = GetParam();
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Parameter(0), m.Word32Not((m.*shift.constructor)(
- m.Parameter(1), m.Parameter(2)))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmBic, s[0]->arch_opcode());
- EXPECT_EQ(shift.r_mode, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorShiftTest, Word32AndWithWord32NotWithImmediate) {
- const Shift shift = GetParam();
- TRACED_FORRANGE(int32_t, imm, shift.i_low, shift.i_high) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Parameter(0),
- m.Word32Not((m.*shift.constructor)(
- m.Parameter(1), m.Int32Constant(imm)))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmBic, s[0]->arch_opcode());
- EXPECT_EQ(shift.i_mode, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorShiftTest,
- ::testing::ValuesIn(kShifts));
-
-
-// -----------------------------------------------------------------------------
-// Memory access instructions.
-
-
-namespace {
-
-struct MemoryAccess {
- MachineType type;
- ArchOpcode ldr_opcode;
- ArchOpcode str_opcode;
- bool (InstructionSelectorTest::Stream::*val_predicate)(
- const InstructionOperand*) const;
- const int32_t immediates[40];
-};
-
-
-std::ostream& operator<<(std::ostream& os, const MemoryAccess& memacc) {
- OStringStream ost;
- ost << memacc.type;
- return os << ost.c_str();
-}
-
-
-static const MemoryAccess kMemoryAccesses[] = {
- {kMachInt8,
- kArmLdrsb,
- kArmStrb,
- &InstructionSelectorTest::Stream::IsInteger,
- {-4095, -3340, -3231, -3224, -3088, -1758, -1203, -123, -117, -91, -89,
- -87, -86, -82, -44, -23, -3, 0, 7, 10, 39, 52, 69, 71, 91, 92, 107, 109,
- 115, 124, 286, 655, 1362, 1569, 2587, 3067, 3096, 3462, 3510, 4095}},
- {kMachUint8,
- kArmLdrb,
- kArmStrb,
- &InstructionSelectorTest::Stream::IsInteger,
- {-4095, -3914, -3536, -3234, -3185, -3169, -1073, -990, -859, -720, -434,
- -127, -124, -122, -105, -91, -86, -64, -55, -53, -30, -10, -3, 0, 20, 28,
- 39, 58, 64, 73, 75, 100, 108, 121, 686, 963, 1363, 2759, 3449, 4095}},
- {kMachInt16,
- kArmLdrsh,
- kArmStrh,
- &InstructionSelectorTest::Stream::IsInteger,
- {-255, -251, -232, -220, -144, -138, -130, -126, -116, -115, -102, -101,
- -98, -69, -59, -56, -39, -35, -23, -19, -7, 0, 22, 26, 37, 68, 83, 87, 98,
- 102, 108, 111, 117, 171, 195, 203, 204, 245, 246, 255}},
- {kMachUint16,
- kArmLdrh,
- kArmStrh,
- &InstructionSelectorTest::Stream::IsInteger,
- {-255, -230, -201, -172, -125, -119, -118, -105, -98, -79, -54, -42, -41,
- -32, -12, -11, -5, -4, 0, 5, 9, 25, 28, 51, 58, 60, 89, 104, 108, 109,
- 114, 116, 120, 138, 150, 161, 166, 172, 228, 255}},
- {kMachInt32,
- kArmLdr,
- kArmStr,
- &InstructionSelectorTest::Stream::IsInteger,
- {-4095, -1898, -1685, -1562, -1408, -1313, -344, -128, -116, -100, -92,
- -80, -72, -71, -56, -25, -21, -11, -9, 0, 3, 5, 27, 28, 42, 52, 63, 88,
- 93, 97, 125, 846, 1037, 2102, 2403, 2597, 2632, 2997, 3935, 4095}},
- {kMachFloat32,
- kArmVldr32,
- kArmVstr32,
- &InstructionSelectorTest::Stream::IsDouble,
- {-1020, -928, -896, -772, -728, -680, -660, -488, -372, -112, -100, -92,
- -84, -80, -72, -64, -60, -56, -52, -48, -36, -32, -20, -8, -4, 0, 8, 20,
- 24, 40, 64, 112, 204, 388, 516, 852, 856, 976, 988, 1020}},
- {kMachFloat64,
- kArmVldr64,
- kArmVstr64,
- &InstructionSelectorTest::Stream::IsDouble,
- {-1020, -948, -796, -696, -612, -364, -320, -308, -128, -112, -108, -104,
- -96, -84, -80, -56, -48, -40, -20, 0, 24, 28, 36, 48, 64, 84, 96, 100,
- 108, 116, 120, 140, 156, 408, 432, 444, 772, 832, 940, 1020}}};
-
-} // namespace
-
-
-typedef InstructionSelectorTestWithParam<MemoryAccess>
- InstructionSelectorMemoryAccessTest;
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithParameters) {
- const MemoryAccess memacc = GetParam();
- StreamBuilder m(this, memacc.type, kMachPtr, kMachInt32);
- m.Return(m.Load(memacc.type, m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, LoadWithImmediateIndex) {
- const MemoryAccess memacc = GetParam();
- TRACED_FOREACH(int32_t, index, memacc.immediates) {
- StreamBuilder m(this, memacc.type, kMachPtr);
- m.Return(m.Load(memacc.type, m.Parameter(0), m.Int32Constant(index)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(memacc.ldr_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
- EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_TRUE((s.*memacc.val_predicate)(s[0]->Output()));
- }
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithParameters) {
- const MemoryAccess memacc = GetParam();
- StreamBuilder m(this, kMachInt32, kMachPtr, kMachInt32, memacc.type);
- m.Store(memacc.type, m.Parameter(0), m.Parameter(1), m.Parameter(2));
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Offset_RR, s[0]->addressing_mode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(0U, s[0]->OutputCount());
-}
-
-
-TEST_P(InstructionSelectorMemoryAccessTest, StoreWithImmediateIndex) {
- const MemoryAccess memacc = GetParam();
- TRACED_FOREACH(int32_t, index, memacc.immediates) {
- StreamBuilder m(this, kMachInt32, kMachPtr, memacc.type);
- m.Store(memacc.type, m.Parameter(0), m.Int32Constant(index),
- m.Parameter(1));
- m.Return(m.Int32Constant(0));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(memacc.str_opcode, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Offset_RI, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- ASSERT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind());
- EXPECT_EQ(index, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(0U, s[0]->OutputCount());
- }
-}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
- InstructionSelectorMemoryAccessTest,
- ::testing::ValuesIn(kMemoryAccesses));
-
-
-// -----------------------------------------------------------------------------
-// Miscellaneous.
-
-
-TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
- {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMla, s[0]->arch_opcode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Int32Add(m.Int32Mul(m.Parameter(1), m.Parameter(2)), m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMla, s[0]->arch_opcode());
- EXPECT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Int32DivWithParameters) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(4U, s.size());
- EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
- ASSERT_EQ(2U, s[2]->InputCount());
- ASSERT_EQ(1U, s[2]->OutputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
- EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
- ASSERT_EQ(1U, s[3]->InputCount());
- EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32DivWithParametersForSUDIV) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build(SUDIV);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32ModWithParameters) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(6U, s.size());
- EXPECT_EQ(kArmVcvtF64S32, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kArmVcvtF64S32, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
- ASSERT_EQ(2U, s[2]->InputCount());
- ASSERT_EQ(1U, s[2]->OutputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
- EXPECT_EQ(kArmVcvtS32F64, s[3]->arch_opcode());
- ASSERT_EQ(1U, s[3]->InputCount());
- EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
- EXPECT_EQ(kArmMul, s[4]->arch_opcode());
- ASSERT_EQ(1U, s[4]->OutputCount());
- ASSERT_EQ(2U, s[4]->InputCount());
- EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
- EXPECT_EQ(kArmSub, s[5]->arch_opcode());
- ASSERT_EQ(1U, s[5]->OutputCount());
- ASSERT_EQ(2U, s[5]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIV) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build(SUDIV);
- ASSERT_EQ(3U, s.size());
- EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(kArmMul, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- ASSERT_EQ(2U, s[1]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
- EXPECT_EQ(kArmSub, s[2]->arch_opcode());
- ASSERT_EQ(1U, s[2]->OutputCount());
- ASSERT_EQ(2U, s[2]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32ModWithParametersForSUDIVAndMLS) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32Mod(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build(MLS, SUDIV);
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArmSdiv, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(kArmMls, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- ASSERT_EQ(3U, s[1]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32MulWithParameters) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32Mul(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMul, s[0]->arch_opcode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
- // x * (2^k + 1) -> x + (x >> k)
- TRACED_FORRANGE(int32_t, k, 1, 30) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) + 1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
- EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- // x * (2^k - 1) -> -x + (x >> k)
- TRACED_FORRANGE(int32_t, k, 3, 30) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Int32Mul(m.Parameter(0), m.Int32Constant((1 << k) - 1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
- EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- // (2^k + 1) * x -> x + (x >> k)
- TRACED_FORRANGE(int32_t, k, 1, 30) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Int32Mul(m.Int32Constant((1 << k) + 1), m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmAdd, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
- EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- // x * (2^k - 1) -> -x + (x >> k)
- TRACED_FORRANGE(int32_t, k, 3, 30) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Int32Mul(m.Int32Constant((1 << k) - 1), m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmRsb, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
- EXPECT_EQ(k, s.ToInt32(s[0]->InputAt(2)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
- Stream s = m.Build();
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArmMul, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kArmSub, s[1]->arch_opcode());
- ASSERT_EQ(2U, s[1]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
- m.Return(
- m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
- Stream s = m.Build(MLS);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMls, s[0]->arch_opcode());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(3U, s[0]->InputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UDivWithParameters) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(4U, s.size());
- EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
- ASSERT_EQ(2U, s[2]->InputCount());
- ASSERT_EQ(1U, s[2]->OutputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
- EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
- ASSERT_EQ(1U, s[3]->InputCount());
- EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UDivWithParametersForSUDIV) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32UDiv(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build(SUDIV);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UModWithParameters) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(6U, s.size());
- EXPECT_EQ(kArmVcvtF64U32, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kArmVcvtF64U32, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- EXPECT_EQ(kArmVdivF64, s[2]->arch_opcode());
- ASSERT_EQ(2U, s[2]->InputCount());
- ASSERT_EQ(1U, s[2]->OutputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[2]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
- EXPECT_EQ(kArmVcvtU32F64, s[3]->arch_opcode());
- ASSERT_EQ(1U, s[3]->InputCount());
- EXPECT_EQ(s.ToVreg(s[2]->Output()), s.ToVreg(s[3]->InputAt(0)));
- EXPECT_EQ(kArmMul, s[4]->arch_opcode());
- ASSERT_EQ(1U, s[4]->OutputCount());
- ASSERT_EQ(2U, s[4]->InputCount());
- EXPECT_EQ(s.ToVreg(s[3]->Output()), s.ToVreg(s[4]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->InputAt(0)), s.ToVreg(s[4]->InputAt(1)));
- EXPECT_EQ(kArmSub, s[5]->arch_opcode());
- ASSERT_EQ(1U, s[5]->OutputCount());
- ASSERT_EQ(2U, s[5]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[5]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[4]->Output()), s.ToVreg(s[5]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UModWithParametersForSUDIV) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build(SUDIV);
- ASSERT_EQ(3U, s.size());
- EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(kArmMul, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- ASSERT_EQ(2U, s[1]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
- EXPECT_EQ(kArmSub, s[2]->arch_opcode());
- ASSERT_EQ(1U, s[2]->OutputCount());
- ASSERT_EQ(2U, s[2]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[2]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[1]->Output()), s.ToVreg(s[2]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32UModWithParametersForSUDIVAndMLS) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Int32UMod(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build(MLS, SUDIV);
- ASSERT_EQ(2U, s.size());
- EXPECT_EQ(kArmUdiv, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(kArmMls, s[1]->arch_opcode());
- ASSERT_EQ(1U, s[1]->OutputCount());
- ASSERT_EQ(3U, s[1]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(1)), s.ToVreg(s[1]->InputAt(1)));
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[1]->InputAt(2)));
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) {
- TRACED_FORRANGE(int32_t, width, 1, 32) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Parameter(0),
- m.Int32Constant(0xffffffffu >> (32 - width))));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- TRACED_FORRANGE(int32_t, width, 1, 32) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
- m.Parameter(0)));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) {
- TRACED_FORRANGE(int32_t, lsb, 0, 31) {
- TRACED_FORRANGE(int32_t, width, 1, (32 - lsb) - 1) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32And(
- m.Parameter(0),
- m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb))));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_TRUE(
- UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- }
- TRACED_FORRANGE(int32_t, lsb, 0, 31) {
- TRACED_FORRANGE(int32_t, width, 1, (32 - lsb) - 1) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(
- m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)),
- m.Parameter(0)));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmBfc, s[0]->arch_opcode());
- ASSERT_EQ(1U, s[0]->OutputCount());
- EXPECT_TRUE(
- UnallocatedOperand::cast(s[0]->Output())->HasSameAsInputPolicy());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32ShrWithWord32AndWithImmediateForARMv7) {
- TRACED_FORRANGE(int32_t, lsb, 0, 31) {
- TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
- uint32_t max = 1 << lsb;
- if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
- uint32_t jnk = rng()->NextInt(max);
- uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Shr(m.Word32And(m.Parameter(0), m.Int32Constant(msk)),
- m.Int32Constant(lsb)));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- }
- TRACED_FORRANGE(int32_t, lsb, 0, 31) {
- TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
- uint32_t max = 1 << lsb;
- if (max > static_cast<uint32_t>(kMaxInt)) max -= 1;
- uint32_t jnk = rng()->NextInt(max);
- uint32_t msk = ((0xffffffffu >> (32 - width)) << lsb) | jnk;
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Shr(m.Word32And(m.Int32Constant(msk), m.Parameter(0)),
- m.Int32Constant(lsb)));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithWord32Not) {
- {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Parameter(0), m.Word32Not(m.Parameter(1))));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmBic, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
- {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Word32Not(m.Parameter(0)), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmBic, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithParameters) {
- StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(m.Parameter(0), m.Parameter(1)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
-}
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithImmediate) {
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- if (imm == 0) continue;
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(imm)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
- TRACED_FOREACH(int32_t, imm, kImmediates) {
- if (imm == 0) continue;
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(m.Int32Constant(imm), m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmCmp, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_I, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32EqualWithZero) {
- {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmTst, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
- {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmTst, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- ASSERT_EQ(2U, s[0]->InputCount());
- EXPECT_EQ(s.ToVreg(s[0]->InputAt(0)), s.ToVreg(s[0]->InputAt(1)));
- EXPECT_EQ(1U, s[0]->OutputCount());
- EXPECT_EQ(kFlags_set, s[0]->flags_mode());
- EXPECT_EQ(kEqual, s[0]->flags_condition());
- }
-}
-
-
-TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32Not(m.Parameter(0)));
- Stream s = m.Build();
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmMvn, s[0]->arch_opcode());
- EXPECT_EQ(kMode_Operand2_R, s[0]->addressing_mode());
- EXPECT_EQ(1U, s[0]->InputCount());
- EXPECT_EQ(1U, s[0]->OutputCount());
-}
-
-
-TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) {
- TRACED_FORRANGE(int32_t, lsb, 0, 31) {
- TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)),
- m.Int32Constant(0xffffffffu >> (32 - width))));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- }
- TRACED_FORRANGE(int32_t, lsb, 0, 31) {
- TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) {
- StreamBuilder m(this, kMachInt32, kMachInt32);
- m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)),
- m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb))));
- Stream s = m.Build(ARMv7);
- ASSERT_EQ(1U, s.size());
- EXPECT_EQ(kArmUbfx, s[0]->arch_opcode());
- ASSERT_EQ(3U, s[0]->InputCount());
- EXPECT_EQ(lsb, s.ToInt32(s[0]->InputAt(1)));
- EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2)));
- }
- }
-}
-} // namespace compiler
-} // namespace internal
-} // namespace v8
diff --git a/src/compiler/arm/instruction-selector-arm.cc b/src/compiler/arm/instruction-selector-arm.cc
index ae93b27..ef9e89e 100644
--- a/src/compiler/arm/instruction-selector-arm.cc
+++ b/src/compiler/arm/instruction-selector-arm.cc
@@ -11,16 +11,17 @@
namespace compiler {
// Adds Arm-specific methods for generating InstructionOperands.
-class ArmOperandGenerator FINAL : public OperandGenerator {
+class ArmOperandGenerator : public OperandGenerator {
public:
explicit ArmOperandGenerator(InstructionSelector* selector)
: OperandGenerator(selector) {}
- InstructionOperand* UseOperand(Node* node, InstructionCode opcode) {
- if (CanBeImmediate(node, opcode)) {
- return UseImmediate(node);
- }
- return UseRegister(node);
+ bool CanBeImmediate(int32_t value) const {
+ return Assembler::ImmediateFitsAddrMode1Instruction(value);
+ }
+
+ bool CanBeImmediate(uint32_t value) const {
+ return CanBeImmediate(bit_cast<int32_t>(value));
}
bool CanBeImmediate(Node* node, InstructionCode opcode) {
@@ -32,27 +33,25 @@
case kArmMov:
case kArmMvn:
case kArmBic:
- return ImmediateFitsAddrMode1Instruction(value) ||
- ImmediateFitsAddrMode1Instruction(~value);
+ return CanBeImmediate(value) || CanBeImmediate(~value);
case kArmAdd:
case kArmSub:
case kArmCmp:
case kArmCmn:
- return ImmediateFitsAddrMode1Instruction(value) ||
- ImmediateFitsAddrMode1Instruction(-value);
+ return CanBeImmediate(value) || CanBeImmediate(-value);
case kArmTst:
case kArmTeq:
case kArmOrr:
case kArmEor:
case kArmRsb:
- return ImmediateFitsAddrMode1Instruction(value);
+ return CanBeImmediate(value);
- case kArmVldr32:
- case kArmVstr32:
- case kArmVldr64:
- case kArmVstr64:
+ case kArmVldrF32:
+ case kArmVstrF32:
+ case kArmVldrF64:
+ case kArmVstrF64:
return value >= -1020 && value <= 1020 && (value % 4) == 0;
case kArmLdrb:
@@ -68,49 +67,26 @@
case kArmStrh:
return value >= -255 && value <= 255;
- case kArchCallCodeObject:
- case kArchCallJSFunction:
- case kArchJmp:
- case kArchNop:
- case kArchRet:
- case kArchTruncateDoubleToI:
- case kArmMul:
- case kArmMla:
- case kArmMls:
- case kArmSdiv:
- case kArmUdiv:
- case kArmBfc:
- case kArmUbfx:
- case kArmVcmpF64:
- case kArmVaddF64:
- case kArmVsubF64:
- case kArmVmulF64:
- case kArmVmlaF64:
- case kArmVmlsF64:
- case kArmVdivF64:
- case kArmVmodF64:
- case kArmVnegF64:
- case kArmVsqrtF64:
- case kArmVcvtF64S32:
- case kArmVcvtF64U32:
- case kArmVcvtS32F64:
- case kArmVcvtU32F64:
- case kArmPush:
- return false;
+ default:
+ break;
}
- UNREACHABLE();
return false;
}
-
- private:
- bool ImmediateFitsAddrMode1Instruction(int32_t imm) const {
- return Assembler::ImmediateFitsAddrMode1Instruction(imm);
- }
};
-static void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
- Node* node) {
+namespace {
+
+void VisitRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+ Node* node) {
+ ArmOperandGenerator g(selector);
+ selector->Emit(opcode, g.DefineAsRegister(node),
+ g.UseRegister(node->InputAt(0)));
+}
+
+
+void VisitRRRFloat64(InstructionSelector* selector, ArchOpcode opcode,
+ Node* node) {
ArmOperandGenerator g(selector);
selector->Emit(opcode, g.DefineAsRegister(node),
g.UseRegister(node->InputAt(0)),
@@ -118,86 +94,69 @@
}
-static bool TryMatchROR(InstructionSelector* selector,
- InstructionCode* opcode_return, Node* node,
- InstructionOperand** value_return,
- InstructionOperand** shift_return) {
+template <IrOpcode::Value kOpcode, int kImmMin, int kImmMax,
+ AddressingMode kImmMode, AddressingMode kRegMode>
+bool TryMatchShift(InstructionSelector* selector,
+ InstructionCode* opcode_return, Node* node,
+ InstructionOperand** value_return,
+ InstructionOperand** shift_return) {
ArmOperandGenerator g(selector);
- if (node->opcode() != IrOpcode::kWord32Ror) return false;
- Int32BinopMatcher m(node);
- *value_return = g.UseRegister(m.left().node());
- if (m.right().IsInRange(1, 31)) {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_I);
- *shift_return = g.UseImmediate(m.right().node());
- } else {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ROR_R);
- *shift_return = g.UseRegister(m.right().node());
+ if (node->opcode() == kOpcode) {
+ Int32BinopMatcher m(node);
+ *value_return = g.UseRegister(m.left().node());
+ if (m.right().IsInRange(kImmMin, kImmMax)) {
+ *opcode_return |= AddressingModeField::encode(kImmMode);
+ *shift_return = g.UseImmediate(m.right().node());
+ } else {
+ *opcode_return |= AddressingModeField::encode(kRegMode);
+ *shift_return = g.UseRegister(m.right().node());
+ }
+ return true;
}
- return true;
+ return false;
}
-static inline bool TryMatchASR(InstructionSelector* selector,
- InstructionCode* opcode_return, Node* node,
- InstructionOperand** value_return,
- InstructionOperand** shift_return) {
- ArmOperandGenerator g(selector);
- if (node->opcode() != IrOpcode::kWord32Sar) return false;
- Int32BinopMatcher m(node);
- *value_return = g.UseRegister(m.left().node());
- if (m.right().IsInRange(1, 32)) {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_I);
- *shift_return = g.UseImmediate(m.right().node());
- } else {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_ASR_R);
- *shift_return = g.UseRegister(m.right().node());
- }
- return true;
+bool TryMatchROR(InstructionSelector* selector, InstructionCode* opcode_return,
+ Node* node, InstructionOperand** value_return,
+ InstructionOperand** shift_return) {
+ return TryMatchShift<IrOpcode::kWord32Ror, 1, 31, kMode_Operand2_R_ROR_I,
+ kMode_Operand2_R_ROR_R>(selector, opcode_return, node,
+ value_return, shift_return);
}
-static inline bool TryMatchLSL(InstructionSelector* selector,
- InstructionCode* opcode_return, Node* node,
- InstructionOperand** value_return,
- InstructionOperand** shift_return) {
- ArmOperandGenerator g(selector);
- if (node->opcode() != IrOpcode::kWord32Shl) return false;
- Int32BinopMatcher m(node);
- *value_return = g.UseRegister(m.left().node());
- if (m.right().IsInRange(0, 31)) {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_I);
- *shift_return = g.UseImmediate(m.right().node());
- } else {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSL_R);
- *shift_return = g.UseRegister(m.right().node());
- }
- return true;
+bool TryMatchASR(InstructionSelector* selector, InstructionCode* opcode_return,
+ Node* node, InstructionOperand** value_return,
+ InstructionOperand** shift_return) {
+ return TryMatchShift<IrOpcode::kWord32Sar, 1, 32, kMode_Operand2_R_ASR_I,
+ kMode_Operand2_R_ASR_R>(selector, opcode_return, node,
+ value_return, shift_return);
}
-static inline bool TryMatchLSR(InstructionSelector* selector,
- InstructionCode* opcode_return, Node* node,
- InstructionOperand** value_return,
- InstructionOperand** shift_return) {
- ArmOperandGenerator g(selector);
- if (node->opcode() != IrOpcode::kWord32Shr) return false;
- Int32BinopMatcher m(node);
- *value_return = g.UseRegister(m.left().node());
- if (m.right().IsInRange(1, 32)) {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_I);
- *shift_return = g.UseImmediate(m.right().node());
- } else {
- *opcode_return |= AddressingModeField::encode(kMode_Operand2_R_LSR_R);
- *shift_return = g.UseRegister(m.right().node());
- }
- return true;
+bool TryMatchLSL(InstructionSelector* selector, InstructionCode* opcode_return,
+ Node* node, InstructionOperand** value_return,
+ InstructionOperand** shift_return) {
+ return TryMatchShift<IrOpcode::kWord32Shl, 0, 31, kMode_Operand2_R_LSL_I,
+ kMode_Operand2_R_LSL_R>(selector, opcode_return, node,
+ value_return, shift_return);
}
-static inline bool TryMatchShift(InstructionSelector* selector,
- InstructionCode* opcode_return, Node* node,
- InstructionOperand** value_return,
- InstructionOperand** shift_return) {
+bool TryMatchLSR(InstructionSelector* selector, InstructionCode* opcode_return,
+ Node* node, InstructionOperand** value_return,
+ InstructionOperand** shift_return) {
+ return TryMatchShift<IrOpcode::kWord32Shr, 1, 32, kMode_Operand2_R_LSR_I,
+ kMode_Operand2_R_LSR_R>(selector, opcode_return, node,
+ value_return, shift_return);
+}
+
+
+bool TryMatchShift(InstructionSelector* selector,
+ InstructionCode* opcode_return, Node* node,
+ InstructionOperand** value_return,
+ InstructionOperand** shift_return) {
return (
TryMatchASR(selector, opcode_return, node, value_return, shift_return) ||
TryMatchLSL(selector, opcode_return, node, value_return, shift_return) ||
@@ -206,11 +165,10 @@
}
-static inline bool TryMatchImmediateOrShift(InstructionSelector* selector,
- InstructionCode* opcode_return,
- Node* node,
- size_t* input_count_return,
- InstructionOperand** inputs) {
+bool TryMatchImmediateOrShift(InstructionSelector* selector,
+ InstructionCode* opcode_return, Node* node,
+ size_t* input_count_return,
+ InstructionOperand** inputs) {
ArmOperandGenerator g(selector);
if (g.CanBeImmediate(node, *opcode_return)) {
*opcode_return |= AddressingModeField::encode(kMode_Operand2_I);
@@ -226,9 +184,9 @@
}
-static void VisitBinop(InstructionSelector* selector, Node* node,
- InstructionCode opcode, InstructionCode reverse_opcode,
- FlagsContinuation* cont) {
+void VisitBinop(InstructionSelector* selector, Node* node,
+ InstructionCode opcode, InstructionCode reverse_opcode,
+ FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand* inputs[5];
@@ -236,8 +194,20 @@
InstructionOperand* outputs[2];
size_t output_count = 0;
- if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
- &input_count, &inputs[1])) {
+ if (m.left().node() == m.right().node()) {
+ // If both inputs refer to the same operand, enforce allocating a register
+ // for both of them to ensure that we don't end up generating code like
+ // this:
+ //
+ // mov r0, r1, asr #16
+ // adds r0, r0, r1, asr #16
+ // bvs label
+ InstructionOperand* const input = g.UseRegister(m.left().node());
+ opcode |= AddressingModeField::encode(kMode_Operand2_R);
+ inputs[input_count++] = input;
+ inputs[input_count++] = input;
+ } else if (TryMatchImmediateOrShift(selector, &opcode, m.right().node(),
+ &input_count, &inputs[1])) {
inputs[0] = g.UseRegister(m.left().node());
input_count++;
} else if (TryMatchImmediateOrShift(selector, &reverse_opcode,
@@ -274,13 +244,16 @@
}
-static void VisitBinop(InstructionSelector* selector, Node* node,
- InstructionCode opcode, InstructionCode reverse_opcode) {
+void VisitBinop(InstructionSelector* selector, Node* node,
+ InstructionCode opcode, InstructionCode reverse_opcode) {
FlagsContinuation cont;
VisitBinop(selector, node, opcode, reverse_opcode, &cont);
}
+} // namespace
+
+
void InstructionSelector::VisitLoad(Node* node) {
MachineType rep = RepresentationOf(OpParameter<LoadRepresentation>(node));
MachineType typ = TypeOf(OpParameter<LoadRepresentation>(node));
@@ -291,10 +264,10 @@
ArchOpcode opcode;
switch (rep) {
case kRepFloat32:
- opcode = kArmVldr32;
+ opcode = kArmVldrF32;
break;
case kRepFloat64:
- opcode = kArmVldr64;
+ opcode = kArmVldrF64;
break;
case kRepBit: // Fall through.
case kRepWord8:
@@ -346,10 +319,10 @@
ArchOpcode opcode;
switch (rep) {
case kRepFloat32:
- opcode = kArmVstr32;
+ opcode = kArmVstrF32;
break;
case kRepFloat64:
- opcode = kArmVstr64;
+ opcode = kArmVstrF64;
break;
case kRepBit: // Fall through.
case kRepWord8:
@@ -377,8 +350,86 @@
}
-static inline void EmitBic(InstructionSelector* selector, Node* node,
- Node* left, Node* right) {
+void InstructionSelector::VisitCheckedLoad(Node* node) {
+ MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+ MachineType typ = TypeOf(OpParameter<MachineType>(node));
+ ArmOperandGenerator g(this);
+ Node* const buffer = node->InputAt(0);
+ Node* const offset = node->InputAt(1);
+ Node* const length = node->InputAt(2);
+ ArchOpcode opcode;
+ switch (rep) {
+ case kRepWord8:
+ opcode = typ == kTypeInt32 ? kCheckedLoadInt8 : kCheckedLoadUint8;
+ break;
+ case kRepWord16:
+ opcode = typ == kTypeInt32 ? kCheckedLoadInt16 : kCheckedLoadUint16;
+ break;
+ case kRepWord32:
+ opcode = kCheckedLoadWord32;
+ break;
+ case kRepFloat32:
+ opcode = kCheckedLoadFloat32;
+ break;
+ case kRepFloat64:
+ opcode = kCheckedLoadFloat64;
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+ InstructionOperand* offset_operand = g.UseRegister(offset);
+ InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp)
+ ? g.UseImmediate(length)
+ : g.UseRegister(length);
+ Emit(opcode | AddressingModeField::encode(kMode_Offset_RR),
+ g.DefineAsRegister(node), offset_operand, length_operand,
+ g.UseRegister(buffer), offset_operand);
+}
+
+
+void InstructionSelector::VisitCheckedStore(Node* node) {
+ MachineType rep = RepresentationOf(OpParameter<MachineType>(node));
+ ArmOperandGenerator g(this);
+ Node* const buffer = node->InputAt(0);
+ Node* const offset = node->InputAt(1);
+ Node* const length = node->InputAt(2);
+ Node* const value = node->InputAt(3);
+ ArchOpcode opcode;
+ switch (rep) {
+ case kRepWord8:
+ opcode = kCheckedStoreWord8;
+ break;
+ case kRepWord16:
+ opcode = kCheckedStoreWord16;
+ break;
+ case kRepWord32:
+ opcode = kCheckedStoreWord32;
+ break;
+ case kRepFloat32:
+ opcode = kCheckedStoreFloat32;
+ break;
+ case kRepFloat64:
+ opcode = kCheckedStoreFloat64;
+ break;
+ default:
+ UNREACHABLE();
+ return;
+ }
+ InstructionOperand* offset_operand = g.UseRegister(offset);
+ InstructionOperand* length_operand = g.CanBeImmediate(length, kArmCmp)
+ ? g.UseImmediate(length)
+ : g.UseRegister(length);
+ Emit(opcode | AddressingModeField::encode(kMode_Offset_RR), nullptr,
+ offset_operand, length_operand, g.UseRegister(value),
+ g.UseRegister(buffer), offset_operand);
+}
+
+
+namespace {
+
+void EmitBic(InstructionSelector* selector, Node* node, Node* left,
+ Node* right) {
ArmOperandGenerator g(selector);
InstructionCode opcode = kArmBic;
InstructionOperand* value_operand;
@@ -394,6 +445,18 @@
}
+void EmitUbfx(InstructionSelector* selector, Node* node, Node* left,
+ uint32_t lsb, uint32_t width) {
+ DCHECK_LE(1, width);
+ DCHECK_LE(width, 32 - lsb);
+ ArmOperandGenerator g(selector);
+ selector->Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(left),
+ g.TempImmediate(lsb), g.TempImmediate(width));
+}
+
+} // namespace
+
+
void InstructionSelector::VisitWord32And(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
@@ -411,33 +474,50 @@
return;
}
}
- if (IsSupported(ARMv7) && m.right().HasValue()) {
- uint32_t value = m.right().Value();
+ if (m.right().HasValue()) {
+ uint32_t const value = m.right().Value();
uint32_t width = base::bits::CountPopulation32(value);
uint32_t msb = base::bits::CountLeadingZeros32(value);
- if (width != 0 && msb + width == 32) {
+ // Try to interpret this AND as UBFX.
+ if (IsSupported(ARMv7) && width != 0 && msb + width == 32) {
DCHECK_EQ(0, base::bits::CountTrailingZeros32(value));
if (m.left().IsWord32Shr()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().IsInRange(0, 31)) {
- Emit(kArmUbfx, g.DefineAsRegister(node),
- g.UseRegister(mleft.left().node()),
- g.UseImmediate(mleft.right().node()), g.TempImmediate(width));
- return;
+ // UBFX cannot extract bits past the register size, however since
+ // shifting the original value would have introduced some zeros we can
+ // still use UBFX with a smaller mask and the remaining bits will be
+ // zeros.
+ uint32_t const lsb = mleft.right().Value();
+ return EmitUbfx(this, node, mleft.left().node(), lsb,
+ std::min(width, 32 - lsb));
}
}
- Emit(kArmUbfx, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
- g.TempImmediate(0), g.TempImmediate(width));
+ return EmitUbfx(this, node, m.left().node(), 0, width);
+ }
+ // Try to interpret this AND as BIC.
+ if (g.CanBeImmediate(~value)) {
+ Emit(kArmBic | AddressingModeField::encode(kMode_Operand2_I),
+ g.DefineAsRegister(node), g.UseRegister(m.left().node()),
+ g.TempImmediate(~value));
+ return;
+ }
+ // Try to interpret this AND as UXTH.
+ if (value == 0xffff) {
+ Emit(kArmUxth, g.DefineAsRegister(m.node()),
+ g.UseRegister(m.left().node()), g.TempImmediate(0));
return;
}
// Try to interpret this AND as BFC.
- width = 32 - width;
- msb = base::bits::CountLeadingZeros32(~value);
- uint32_t lsb = base::bits::CountTrailingZeros32(~value);
- if (msb + width + lsb == 32) {
- Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
- g.TempImmediate(lsb), g.TempImmediate(width));
- return;
+ if (IsSupported(ARMv7)) {
+ width = 32 - width;
+ msb = base::bits::CountLeadingZeros32(~value);
+ uint32_t lsb = base::bits::CountTrailingZeros32(~value);
+ if (msb + width + lsb == 32) {
+ Emit(kArmBfc, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
+ g.TempImmediate(lsb), g.TempImmediate(width));
+ return;
+ }
}
}
VisitBinop(this, node, kArmAnd, kArmAnd);
@@ -530,10 +610,7 @@
uint32_t msb = base::bits::CountLeadingZeros32(value);
if (msb + width + lsb == 32) {
DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
- Emit(kArmUbfx, g.DefineAsRegister(node),
- g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
- g.TempImmediate(width));
- return;
+ return EmitUbfx(this, node, mleft.left().node(), lsb, width);
}
}
}
@@ -542,6 +619,20 @@
void InstructionSelector::VisitWord32Sar(Node* node) {
+ ArmOperandGenerator g(this);
+ Int32BinopMatcher m(node);
+ if (CanCover(m.node(), m.left().node()) && m.left().IsWord32Shl()) {
+ Int32BinopMatcher mleft(m.left().node());
+ if (mleft.right().Is(16) && m.right().Is(16)) {
+ Emit(kArmSxth, g.DefineAsRegister(node),
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+ return;
+ } else if (mleft.right().Is(24) && m.right().Is(24)) {
+ Emit(kArmSxtb, g.DefineAsRegister(node),
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+ return;
+ }
+ }
VisitShift(this, node, TryMatchASR);
}
@@ -554,17 +645,113 @@
void InstructionSelector::VisitInt32Add(Node* node) {
ArmOperandGenerator g(this);
Int32BinopMatcher m(node);
- if (m.left().IsInt32Mul() && CanCover(node, m.left().node())) {
- Int32BinopMatcher mleft(m.left().node());
- Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mleft.left().node()),
- g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
- return;
+ if (CanCover(node, m.left().node())) {
+ switch (m.left().opcode()) {
+ case IrOpcode::kInt32Mul: {
+ Int32BinopMatcher mleft(m.left().node());
+ Emit(kArmMla, g.DefineAsRegister(node),
+ g.UseRegister(mleft.left().node()),
+ g.UseRegister(mleft.right().node()),
+ g.UseRegister(m.right().node()));
+ return;
+ }
+ case IrOpcode::kInt32MulHigh: {
+ Int32BinopMatcher mleft(m.left().node());
+ Emit(kArmSmmla, g.DefineAsRegister(node),
+ g.UseRegister(mleft.left().node()),
+ g.UseRegister(mleft.right().node()),
+ g.UseRegister(m.right().node()));
+ return;
+ }
+ case IrOpcode::kWord32And: {
+ Int32BinopMatcher mleft(m.left().node());
+ if (mleft.right().Is(0xff)) {
+ Emit(kArmUxtab, g.DefineAsRegister(node),
+ g.UseRegister(m.right().node()),
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+ return;
+ } else if (mleft.right().Is(0xffff)) {
+ Emit(kArmUxtah, g.DefineAsRegister(node),
+ g.UseRegister(m.right().node()),
+ g.UseRegister(mleft.left().node()), g.TempImmediate(0));
+ return;
+ }
+ }
+ case IrOpcode::kWord32Sar: {
+ Int32BinopMatcher mleft(m.left().node());
+ if (CanCover(mleft.node(), mleft.left().node()) &&
+ mleft.left().IsWord32Shl()) {
+ Int32BinopMatcher mleftleft(mleft.left().node());
+ if (mleft.right().Is(24) && mleftleft.right().Is(24)) {
+ Emit(kArmSxtab, g.DefineAsRegister(node),
+ g.UseRegister(m.right().node()),
+ g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
+ return;
+ } else if (mleft.right().Is(16) && mleftleft.right().Is(16)) {
+ Emit(kArmSxtah, g.DefineAsRegister(node),
+ g.UseRegister(m.right().node()),
+ g.UseRegister(mleftleft.left().node()), g.TempImmediate(0));
+ return;
+ }
+ }
+ }
+ default:
+ break;
+ }
}
- if (m.right().IsInt32Mul() && CanCover(node, m.right().node())) {
- Int32BinopMatcher mright(m.right().node());
- Emit(kArmMla, g.DefineAsRegister(node), g.UseRegister(mright.left().node()),
- g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
- return;
+ if (CanCover(node, m.right().node())) {
+ switch (m.right().opcode()) {
+ case IrOpcode::kInt32Mul: {
+ Int32BinopMatcher mright(m.right().node());
+ Emit(kArmMla, g.DefineAsRegister(node),
+ g.UseRegister(mright.left().node()),
+ g.UseRegister(mright.right().node()),
+ g.UseRegister(m.left().node()));
+ return;
+ }
+ case IrOpcode::kInt32MulHigh: {
+ Int32BinopMatcher mright(m.right().node());
+ Emit(kArmSmmla, g.DefineAsRegister(node),
+ g.UseRegister(mright.left().node()),
+ g.UseRegister(mright.right().node()),
+ g.UseRegister(m.left().node()));
+ return;
+ }
+ case IrOpcode::kWord32And: {
+ Int32BinopMatcher mright(m.right().node());
+ if (mright.right().Is(0xff)) {
+ Emit(kArmUxtab, g.DefineAsRegister(node),
+ g.UseRegister(m.left().node()),
+ g.UseRegister(mright.left().node()), g.TempImmediate(0));
+ return;
+ } else if (mright.right().Is(0xffff)) {
+ Emit(kArmUxtah, g.DefineAsRegister(node),
+ g.UseRegister(m.left().node()),
+ g.UseRegister(mright.left().node()), g.TempImmediate(0));
+ return;
+ }
+ }
+ case IrOpcode::kWord32Sar: {
+ Int32BinopMatcher mright(m.right().node());
+ if (CanCover(mright.node(), mright.left().node()) &&
+ mright.left().IsWord32Shl()) {
+ Int32BinopMatcher mrightleft(mright.left().node());
+ if (mright.right().Is(24) && mrightleft.right().Is(24)) {
+ Emit(kArmSxtab, g.DefineAsRegister(node),
+ g.UseRegister(m.left().node()),
+ g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
+ return;
+ } else if (mright.right().Is(16) && mrightleft.right().Is(16)) {
+ Emit(kArmSxtah, g.DefineAsRegister(node),
+ g.UseRegister(m.left().node()),
+ g.UseRegister(mrightleft.left().node()), g.TempImmediate(0));
+ return;
+ }
+ }
+ }
+ default:
+ break;
+ }
}
VisitBinop(this, node, kArmAdd, kArmAdd);
}
@@ -609,6 +796,22 @@
}
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+ ArmOperandGenerator g(this);
+ Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+ g.UseRegister(node->InputAt(1)));
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+ ArmOperandGenerator g(this);
+ InstructionOperand* outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
+ InstructionOperand* inputs[] = {g.UseRegister(node->InputAt(0)),
+ g.UseRegister(node->InputAt(1))};
+ Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
+}
+
+
static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
InstructionOperand* result_operand,
@@ -646,7 +849,7 @@
}
-void InstructionSelector::VisitInt32UDiv(Node* node) {
+void InstructionSelector::VisitUint32Div(Node* node) {
VisitDiv(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
}
@@ -678,11 +881,18 @@
}
-void InstructionSelector::VisitInt32UMod(Node* node) {
+void InstructionSelector::VisitUint32Mod(Node* node) {
VisitMod(this, node, kArmUdiv, kArmVcvtF64U32, kArmVcvtU32F64);
}
+void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
+ ArmOperandGenerator g(this);
+ Emit(kArmVcvtF64F32, g.DefineAsRegister(node),
+ g.UseRegister(node->InputAt(0)));
+}
+
+
void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
ArmOperandGenerator g(this);
Emit(kArmVcvtF64S32, g.DefineAsRegister(node),
@@ -711,18 +921,25 @@
}
+void InstructionSelector::VisitTruncateFloat64ToFloat32(Node* node) {
+ ArmOperandGenerator g(this);
+ Emit(kArmVcvtF32F64, g.DefineAsRegister(node),
+ g.UseRegister(node->InputAt(0)));
+}
+
+
void InstructionSelector::VisitFloat64Add(Node* node) {
ArmOperandGenerator g(this);
- Int32BinopMatcher m(node);
+ Float64BinopMatcher m(node);
if (m.left().IsFloat64Mul() && CanCover(node, m.left().node())) {
- Int32BinopMatcher mleft(m.left().node());
+ Float64BinopMatcher mleft(m.left().node());
Emit(kArmVmlaF64, g.DefineSameAsFirst(node),
g.UseRegister(m.right().node()), g.UseRegister(mleft.left().node()),
g.UseRegister(mleft.right().node()));
return;
}
if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
- Int32BinopMatcher mright(m.right().node());
+ Float64BinopMatcher mright(m.right().node());
Emit(kArmVmlaF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
g.UseRegister(mright.left().node()),
g.UseRegister(mright.right().node()));
@@ -734,9 +951,14 @@
void InstructionSelector::VisitFloat64Sub(Node* node) {
ArmOperandGenerator g(this);
- Int32BinopMatcher m(node);
+ Float64BinopMatcher m(node);
+ if (m.left().IsMinusZero()) {
+ Emit(kArmVnegF64, g.DefineAsRegister(node),
+ g.UseRegister(m.right().node()));
+ return;
+ }
if (m.right().IsFloat64Mul() && CanCover(node, m.right().node())) {
- Int32BinopMatcher mright(m.right().node());
+ Float64BinopMatcher mright(m.right().node());
Emit(kArmVmlsF64, g.DefineSameAsFirst(node), g.UseRegister(m.left().node()),
g.UseRegister(mright.left().node()),
g.UseRegister(mright.right().node()));
@@ -747,13 +969,7 @@
void InstructionSelector::VisitFloat64Mul(Node* node) {
- ArmOperandGenerator g(this);
- Float64BinopMatcher m(node);
- if (m.right().Is(-1.0)) {
- Emit(kArmVnegF64, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
- } else {
- VisitRRRFloat64(this, kArmVmulF64, node);
- }
+ VisitRRRFloat64(this, kArmVmulF64, node);
}
@@ -775,15 +991,38 @@
}
-void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation,
- BasicBlock* deoptimization) {
+void InstructionSelector::VisitFloat64Floor(Node* node) {
+ DCHECK(CpuFeatures::IsSupported(ARMv8));
+ VisitRRFloat64(this, kArmVfloorF64, node);
+}
+
+
+void InstructionSelector::VisitFloat64Ceil(Node* node) {
+ DCHECK(CpuFeatures::IsSupported(ARMv8));
+ VisitRRFloat64(this, kArmVceilF64, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTruncate(Node* node) {
+ DCHECK(CpuFeatures::IsSupported(ARMv8));
+ VisitRRFloat64(this, kArmVroundTruncateF64, node);
+}
+
+
+void InstructionSelector::VisitFloat64RoundTiesAway(Node* node) {
+ DCHECK(CpuFeatures::IsSupported(ARMv8));
+ VisitRRFloat64(this, kArmVroundTiesAwayF64, node);
+}
+
+
+void InstructionSelector::VisitCall(Node* node) {
ArmOperandGenerator g(this);
- CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call);
+ const CallDescriptor* descriptor = OpParameter<const CallDescriptor*>(node);
FrameStateDescriptor* frame_state_descriptor = NULL;
if (descriptor->NeedsFrameState()) {
frame_state_descriptor =
- GetFrameStateDescriptor(call->InputAt(descriptor->InputCount()));
+ GetFrameStateDescriptor(node->InputAt(descriptor->InputCount()));
}
CallBuffer buffer(zone(), descriptor, frame_state_descriptor);
@@ -792,7 +1031,7 @@
// TODO(turbofan): on ARM64 it's probably better to use the code object in a
// register if there are multiple uses of it. Improve constant pool and the
// heuristics in the register allocator for where to emit constants.
- InitializeCallBuffer(call, &buffer, true, false);
+ InitializeCallBuffer(node, &buffer, true, false);
// TODO(dcarney): might be possible to use claim/poke instead
// Push any stack arguments.
@@ -818,34 +1057,39 @@
opcode |= MiscField::encode(descriptor->flags());
// Emit the call instruction.
+ InstructionOperand** first_output =
+ buffer.outputs.size() > 0 ? &buffer.outputs.front() : NULL;
Instruction* call_instr =
- Emit(opcode, buffer.outputs.size(), &buffer.outputs.front(),
+ Emit(opcode, buffer.outputs.size(), first_output,
buffer.instruction_args.size(), &buffer.instruction_args.front());
-
call_instr->MarkAsCall();
- if (deoptimization != NULL) {
- DCHECK(continuation != NULL);
- call_instr->MarkAsControl();
+}
+
+
+namespace {
+
+// Shared routine for multiple float compare operations.
+void VisitFloat64Compare(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ ArmOperandGenerator g(selector);
+ Float64BinopMatcher m(node);
+ if (cont->IsBranch()) {
+ selector->Emit(cont->Encode(kArmVcmpF64), nullptr,
+ g.UseRegister(m.left().node()),
+ g.UseRegister(m.right().node()), g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
+ } else {
+ DCHECK(cont->IsSet());
+ selector->Emit(
+ cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()),
+ g.UseRegister(m.left().node()), g.UseRegister(m.right().node()));
}
}
-void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
- FlagsContinuation* cont) {
- VisitBinop(this, node, kArmAdd, kArmAdd, cont);
-}
-
-
-void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
- FlagsContinuation* cont) {
- VisitBinop(this, node, kArmSub, kArmRsb, cont);
-}
-
-
-// Shared routine for multiple compare operations.
-static void VisitWordCompare(InstructionSelector* selector, Node* node,
- InstructionCode opcode, FlagsContinuation* cont,
- bool commutative) {
+// Shared routine for multiple word compare operations.
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+ InstructionCode opcode, FlagsContinuation* cont) {
ArmOperandGenerator g(selector);
Int32BinopMatcher m(node);
InstructionOperand* inputs[5];
@@ -859,7 +1103,7 @@
input_count++;
} else if (TryMatchImmediateOrShift(selector, &opcode, m.left().node(),
&input_count, &inputs[1])) {
- if (!commutative) cont->Commute();
+ if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
inputs[0] = g.UseRegister(m.right().node());
input_count++;
} else {
@@ -886,63 +1130,211 @@
}
-void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
- switch (node->opcode()) {
- case IrOpcode::kInt32Add:
- return VisitWordCompare(this, node, kArmCmn, cont, true);
- case IrOpcode::kInt32Sub:
- return VisitWordCompare(this, node, kArmCmp, cont, false);
- case IrOpcode::kWord32And:
- return VisitWordCompare(this, node, kArmTst, cont, true);
- case IrOpcode::kWord32Or:
- return VisitBinop(this, node, kArmOrr, kArmOrr, cont);
- case IrOpcode::kWord32Xor:
- return VisitWordCompare(this, node, kArmTeq, cont, true);
- case IrOpcode::kWord32Sar:
- return VisitShift(this, node, TryMatchASR, cont);
- case IrOpcode::kWord32Shl:
- return VisitShift(this, node, TryMatchLSL, cont);
- case IrOpcode::kWord32Shr:
- return VisitShift(this, node, TryMatchLSR, cont);
- case IrOpcode::kWord32Ror:
- return VisitShift(this, node, TryMatchROR, cont);
- default:
- break;
+void VisitWordCompare(InstructionSelector* selector, Node* node,
+ FlagsContinuation* cont) {
+ VisitWordCompare(selector, node, kArmCmp, cont);
+}
+
+
+// Shared routine for word comparisons against zero.
+void VisitWordCompareZero(InstructionSelector* selector, Node* user,
+ Node* value, FlagsContinuation* cont) {
+ while (selector->CanCover(user, value)) {
+ switch (value->opcode()) {
+ case IrOpcode::kWord32Equal: {
+ // Combine with comparisons against 0 by simply inverting the
+ // continuation.
+ Int32BinopMatcher m(value);
+ if (m.right().Is(0)) {
+ user = value;
+ value = m.left().node();
+ cont->Negate();
+ continue;
+ }
+ cont->OverwriteAndNegateIfEqual(kEqual);
+ return VisitWordCompare(selector, value, cont);
+ }
+ case IrOpcode::kInt32LessThan:
+ cont->OverwriteAndNegateIfEqual(kSignedLessThan);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kInt32LessThanOrEqual:
+ cont->OverwriteAndNegateIfEqual(kSignedLessThanOrEqual);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kUint32LessThan:
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThan);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kUint32LessThanOrEqual:
+ cont->OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual);
+ return VisitWordCompare(selector, value, cont);
+ case IrOpcode::kFloat64Equal:
+ cont->OverwriteAndNegateIfEqual(kUnorderedEqual);
+ return VisitFloat64Compare(selector, value, cont);
+ case IrOpcode::kFloat64LessThan:
+ cont->OverwriteAndNegateIfEqual(kUnorderedLessThan);
+ return VisitFloat64Compare(selector, value, cont);
+ case IrOpcode::kFloat64LessThanOrEqual:
+ cont->OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual);
+ return VisitFloat64Compare(selector, value, cont);
+ case IrOpcode::kProjection:
+ // Check if this is the overflow output projection of an
+ // <Operation>WithOverflow node.
+ if (OpParameter<size_t>(value) == 1u) {
+ // We cannot combine the <Operation>WithOverflow with this branch
+ // unless the 0th projection (the use of the actual value of the
+ // <Operation> is either NULL, which means there's no use of the
+ // actual value, or was already defined, which means it is scheduled
+ // *AFTER* this branch).
+ Node* const node = value->InputAt(0);
+ Node* const result = node->FindProjection(0);
+ if (!result || selector->IsDefined(result)) {
+ switch (node->opcode()) {
+ case IrOpcode::kInt32AddWithOverflow:
+ cont->OverwriteAndNegateIfEqual(kOverflow);
+ return VisitBinop(selector, node, kArmAdd, kArmAdd, cont);
+ case IrOpcode::kInt32SubWithOverflow:
+ cont->OverwriteAndNegateIfEqual(kOverflow);
+ return VisitBinop(selector, node, kArmSub, kArmRsb, cont);
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case IrOpcode::kInt32Add:
+ return VisitWordCompare(selector, value, kArmCmn, cont);
+ case IrOpcode::kInt32Sub:
+ return VisitWordCompare(selector, value, kArmCmp, cont);
+ case IrOpcode::kWord32And:
+ return VisitWordCompare(selector, value, kArmTst, cont);
+ case IrOpcode::kWord32Or:
+ return VisitBinop(selector, value, kArmOrr, kArmOrr, cont);
+ case IrOpcode::kWord32Xor:
+ return VisitWordCompare(selector, value, kArmTeq, cont);
+ case IrOpcode::kWord32Sar:
+ return VisitShift(selector, value, TryMatchASR, cont);
+ case IrOpcode::kWord32Shl:
+ return VisitShift(selector, value, TryMatchLSL, cont);
+ case IrOpcode::kWord32Shr:
+ return VisitShift(selector, value, TryMatchLSR, cont);
+ case IrOpcode::kWord32Ror:
+ return VisitShift(selector, value, TryMatchROR, cont);
+ default:
+ break;
+ }
+ break;
}
- ArmOperandGenerator g(this);
- InstructionCode opcode =
+ // Continuation could not be combined with a compare, emit compare against 0.
+ ArmOperandGenerator g(selector);
+ InstructionCode const opcode =
cont->Encode(kArmTst) | AddressingModeField::encode(kMode_Operand2_R);
+ InstructionOperand* const value_operand = g.UseRegister(value);
if (cont->IsBranch()) {
- Emit(opcode, NULL, g.UseRegister(node), g.UseRegister(node),
- g.Label(cont->true_block()),
- g.Label(cont->false_block()))->MarkAsControl();
+ selector->Emit(opcode, nullptr, value_operand, value_operand,
+ g.Label(cont->true_block()),
+ g.Label(cont->false_block()))->MarkAsControl();
} else {
- Emit(opcode, g.DefineAsRegister(cont->result()), g.UseRegister(node),
- g.UseRegister(node));
+ selector->Emit(opcode, g.DefineAsRegister(cont->result()), value_operand,
+ value_operand);
}
}
+} // namespace
-void InstructionSelector::VisitWord32Compare(Node* node,
- FlagsContinuation* cont) {
- VisitWordCompare(this, node, kArmCmp, cont, false);
+
+void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
+ BasicBlock* fbranch) {
+ FlagsContinuation cont(kNotEqual, tbranch, fbranch);
+ VisitWordCompareZero(this, branch, branch->InputAt(0), &cont);
}
-void InstructionSelector::VisitFloat64Compare(Node* node,
- FlagsContinuation* cont) {
- ArmOperandGenerator g(this);
- Float64BinopMatcher m(node);
- if (cont->IsBranch()) {
- Emit(cont->Encode(kArmVcmpF64), NULL, g.UseRegister(m.left().node()),
- g.UseRegister(m.right().node()), g.Label(cont->true_block()),
- g.Label(cont->false_block()))->MarkAsControl();
- } else {
- DCHECK(cont->IsSet());
- Emit(cont->Encode(kArmVcmpF64), g.DefineAsRegister(cont->result()),
- g.UseRegister(m.left().node()), g.UseRegister(m.right().node()));
+void InstructionSelector::VisitWord32Equal(Node* const node) {
+ FlagsContinuation cont(kEqual, node);
+ Int32BinopMatcher m(node);
+ if (m.right().Is(0)) {
+ return VisitWordCompareZero(this, m.node(), m.left().node(), &cont);
}
+ VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThan(Node* node) {
+ FlagsContinuation cont(kSignedLessThan, node);
+ VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32LessThanOrEqual(Node* node) {
+ FlagsContinuation cont(kSignedLessThanOrEqual, node);
+ VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThan(Node* node) {
+ FlagsContinuation cont(kUnsignedLessThan, node);
+ VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
+ FlagsContinuation cont(kUnsignedLessThanOrEqual, node);
+ VisitWordCompare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
+ if (Node* ovf = node->FindProjection(1)) {
+ FlagsContinuation cont(kOverflow, ovf);
+ return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
+ }
+ FlagsContinuation cont;
+ VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
+}
+
+
+void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
+ if (Node* ovf = node->FindProjection(1)) {
+ FlagsContinuation cont(kOverflow, ovf);
+ return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
+ }
+ FlagsContinuation cont;
+ VisitBinop(this, node, kArmSub, kArmRsb, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64Equal(Node* node) {
+ FlagsContinuation cont(kUnorderedEqual, node);
+ VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThan(Node* node) {
+ FlagsContinuation cont(kUnorderedLessThan, node);
+ VisitFloat64Compare(this, node, &cont);
+}
+
+
+void InstructionSelector::VisitFloat64LessThanOrEqual(Node* node) {
+ FlagsContinuation cont(kUnorderedLessThanOrEqual, node);
+ VisitFloat64Compare(this, node, &cont);
+}
+
+
+// static
+MachineOperatorBuilder::Flags
+InstructionSelector::SupportedMachineOperatorFlags() {
+ MachineOperatorBuilder::Flags flags =
+ MachineOperatorBuilder::kInt32DivIsSafe |
+ MachineOperatorBuilder::kUint32DivIsSafe;
+
+ if (CpuFeatures::IsSupported(ARMv8)) {
+ flags |= MachineOperatorBuilder::kFloat64Floor |
+ MachineOperatorBuilder::kFloat64Ceil |
+ MachineOperatorBuilder::kFloat64RoundTruncate |
+ MachineOperatorBuilder::kFloat64RoundTiesAway;
+ }
+ return flags;
}
} // namespace compiler
diff --git a/src/compiler/arm/linkage-arm.cc b/src/compiler/arm/linkage-arm.cc
index 6673a47..3fca76f 100644
--- a/src/compiler/arm/linkage-arm.cc
+++ b/src/compiler/arm/linkage-arm.cc
@@ -35,8 +35,9 @@
typedef LinkageHelper<ArmLinkageHelperTraits> LH;
-CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone) {
- return LH::GetJSCallDescriptor(zone, parameter_count);
+CallDescriptor* Linkage::GetJSCallDescriptor(int parameter_count, Zone* zone,
+ CallDescriptor::Flags flags) {
+ return LH::GetJSCallDescriptor(zone, parameter_count, flags);
}
@@ -49,10 +50,10 @@
CallDescriptor* Linkage::GetStubCallDescriptor(
- CallInterfaceDescriptor descriptor, int stack_parameter_count,
- CallDescriptor::Flags flags, Zone* zone) {
+ const CallInterfaceDescriptor& descriptor, int stack_parameter_count,
+ CallDescriptor::Flags flags, Operator::Properties properties, Zone* zone) {
return LH::GetStubCallDescriptor(zone, descriptor, stack_parameter_count,
- flags);
+ flags, properties);
}