s390: use new mul instruction
R=joransiu@ca.ibm.com, bjaideep@ca.ibm.com, danno@chromium.org, bmeurer@chromium.org BUG= Review-Url: https://codereview.chromium.org/2691893002 Cr-Commit-Position: refs/heads/master@{#43166}
This commit is contained in:
parent
d891b50053
commit
2dab40ccda
@ -1287,8 +1287,12 @@ void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
|
||||
__ bge(&done, Label::kNear);
|
||||
|
||||
// If there is no remainder then we are done.
|
||||
__ lr(scratch, result);
|
||||
__ msr(scratch, divisor);
|
||||
if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
|
||||
__ msrkc(scratch, result, divisor);
|
||||
} else {
|
||||
__ lr(scratch, result);
|
||||
__ msr(scratch, divisor);
|
||||
}
|
||||
__ Cmp32(dividend, scratch);
|
||||
__ beq(&done, Label::kNear);
|
||||
|
||||
@ -1419,36 +1423,48 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
||||
Register right = ToRegister(right_op);
|
||||
|
||||
if (can_overflow) {
|
||||
if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
|
||||
// result = left * right.
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiUntag(scratch, right);
|
||||
__ MulPWithCondition(result, left, scratch);
|
||||
} else {
|
||||
__ msrkc(result, left, right);
|
||||
__ LoadW(result, result);
|
||||
}
|
||||
DeoptimizeIf(overflow, instr, DeoptimizeReason::kOverflow);
|
||||
} else {
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
// result = left * right.
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiUntag(result, left);
|
||||
__ SmiUntag(scratch, right);
|
||||
__ msgr(result, scratch);
|
||||
} else {
|
||||
__ LoadRR(result, left);
|
||||
__ msgr(result, right);
|
||||
}
|
||||
__ TestIfInt32(result, r0);
|
||||
DeoptimizeIf(ne, instr, DeoptimizeReason::kOverflow);
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiTag(result);
|
||||
}
|
||||
// result = left * right.
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiUntag(result, left);
|
||||
__ SmiUntag(scratch, right);
|
||||
__ msgr(result, scratch);
|
||||
} else {
|
||||
__ LoadRR(result, left);
|
||||
__ msgr(result, right);
|
||||
}
|
||||
__ TestIfInt32(result, r0);
|
||||
DeoptimizeIf(ne, instr, DeoptimizeReason::kOverflow);
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiTag(result);
|
||||
}
|
||||
#else
|
||||
// r0:scratch = scratch * right
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiUntag(scratch, left);
|
||||
__ mr_z(r0, right);
|
||||
__ LoadRR(result, scratch);
|
||||
} else {
|
||||
// r0:scratch = scratch * right
|
||||
__ LoadRR(scratch, left);
|
||||
__ mr_z(r0, right);
|
||||
__ LoadRR(result, scratch);
|
||||
}
|
||||
__ TestIfInt32(r0, result, scratch);
|
||||
DeoptimizeIf(ne, instr, DeoptimizeReason::kOverflow);
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiUntag(scratch, left);
|
||||
__ mr_z(r0, right);
|
||||
__ LoadRR(result, scratch);
|
||||
} else {
|
||||
// r0:scratch = scratch * right
|
||||
__ LoadRR(scratch, left);
|
||||
__ mr_z(r0, right);
|
||||
__ LoadRR(result, scratch);
|
||||
}
|
||||
__ TestIfInt32(r0, result, scratch);
|
||||
DeoptimizeIf(ne, instr, DeoptimizeReason::kOverflow);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (instr->hydrogen()->representation().IsSmi()) {
|
||||
__ SmiUntag(result, left);
|
||||
|
@ -1582,34 +1582,42 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
||||
}
|
||||
case Token::MUL: {
|
||||
Label mul_zero;
|
||||
if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
|
||||
__ SmiUntag(ip, right);
|
||||
__ MulPWithCondition(scratch2, ip, left);
|
||||
__ b(overflow, &stub_call);
|
||||
__ beq(&mul_zero, Label::kNear);
|
||||
__ LoadRR(right, scratch2);
|
||||
} else {
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
// Remove tag from both operands.
|
||||
__ SmiUntag(ip, right);
|
||||
__ SmiUntag(scratch2, left);
|
||||
__ mr_z(scratch1, ip);
|
||||
// Check for overflowing the smi range - no overflow if higher 33 bits of
|
||||
// the result are identical.
|
||||
__ lr(ip, scratch2); // 32 bit load
|
||||
__ sra(ip, Operand(31));
|
||||
__ cr_z(ip, scratch1); // 32 bit compare
|
||||
__ bne(&stub_call);
|
||||
// Remove tag from both operands.
|
||||
__ SmiUntag(ip, right);
|
||||
__ SmiUntag(scratch2, left);
|
||||
__ mr_z(scratch1, ip);
|
||||
// Check for overflowing the smi range - no overflow if higher 33 bits
|
||||
// of the result are identical.
|
||||
__ lr(ip, scratch2); // 32 bit load
|
||||
__ sra(ip, Operand(31));
|
||||
__ cr_z(ip, scratch1); // 32 bit compare
|
||||
__ bne(&stub_call);
|
||||
#else
|
||||
__ SmiUntag(ip, right);
|
||||
__ LoadRR(scratch2, left); // load into low order of reg pair
|
||||
__ mr_z(scratch1, ip); // R4:R5 = R5 * ip
|
||||
// Check for overflowing the smi range - no overflow if higher 33 bits of
|
||||
// the result are identical.
|
||||
__ TestIfInt32(scratch1, scratch2, ip);
|
||||
__ bne(&stub_call);
|
||||
__ SmiUntag(ip, right);
|
||||
__ LoadRR(scratch2, left); // load into low order of reg pair
|
||||
__ mr_z(scratch1, ip); // R4:R5 = R5 * ip
|
||||
// Check for overflowing the smi range - no overflow if higher 33 bits
|
||||
// of the result are identical.
|
||||
__ TestIfInt32(scratch1, scratch2, ip);
|
||||
__ bne(&stub_call);
|
||||
#endif
|
||||
// Go slow on zero result to handle -0.
|
||||
__ chi(scratch2, Operand::Zero());
|
||||
__ beq(&mul_zero, Label::kNear);
|
||||
// Go slow on zero result to handle -0.
|
||||
__ chi(scratch2, Operand::Zero());
|
||||
__ beq(&mul_zero, Label::kNear);
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
__ SmiTag(right, scratch2);
|
||||
__ SmiTag(right, scratch2);
|
||||
#else
|
||||
__ LoadRR(right, scratch2);
|
||||
__ LoadRR(right, scratch2);
|
||||
#endif
|
||||
}
|
||||
__ b(&done);
|
||||
// We need -0 if we were multiplying a negative number with 0 to get 0.
|
||||
// We know one of them was zero.
|
||||
|
@ -807,6 +807,7 @@ enum CpuFeature {
|
||||
GENERAL_INSTR_EXT,
|
||||
FLOATING_POINT_EXT,
|
||||
VECTOR_FACILITY,
|
||||
MISC_INSTR_EXT2,
|
||||
|
||||
NUMBER_OF_CPU_FEATURES,
|
||||
|
||||
|
@ -166,14 +166,18 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
|
||||
if (facilities[2] & (one << (63 - (129 - 128)))) {
|
||||
supported_ |= (1u << VECTOR_FACILITY);
|
||||
}
|
||||
// Test for Miscellaneous Instruction Extension Facility - Bit 58
|
||||
if (facilities[0] & (1lu << (63 - 58))) {
|
||||
supported_ |= (1u << MISC_INSTR_EXT2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// All distinct ops instructions can be simulated
|
||||
supported_ |= (1u << DISTINCT_OPS);
|
||||
// RISBG can be simulated
|
||||
supported_ |= (1u << GENERAL_INSTR_EXT);
|
||||
|
||||
supported_ |= (1u << FLOATING_POINT_EXT);
|
||||
supported_ |= (1u << MISC_INSTR_EXT2);
|
||||
USE(performSTFLE); // To avoid assert
|
||||
supported_ |= (1u << VECTOR_FACILITY);
|
||||
#endif
|
||||
@ -198,6 +202,7 @@ void CpuFeatures::PrintFeatures() {
|
||||
printf("GENERAL_INSTR=%d\n", CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
|
||||
printf("DISTINCT_OPS=%d\n", CpuFeatures::IsSupported(DISTINCT_OPS));
|
||||
printf("VECTOR_FACILITY=%d\n", CpuFeatures::IsSupported(VECTOR_FACILITY));
|
||||
printf("MISC_INSTR_EXT2=%d\n", CpuFeatures::IsSupported(MISC_INSTR_EXT2));
|
||||
}
|
||||
|
||||
Register ToRegister(int num) {
|
||||
@ -1510,6 +1515,16 @@ void Assembler::mhi(Register r1, const Operand& opnd) {
|
||||
ri_form(MHI, r1, opnd);
|
||||
}
|
||||
|
||||
// Multiply Single Register (32)
|
||||
void Assembler::msrkc(Register r1, Register r2, Register r3) {
|
||||
rrf1_form(MSRKC, r1, r2, r3);
|
||||
}
|
||||
|
||||
// Multiply Single Register (64)
|
||||
void Assembler::msgrkc(Register r1, Register r2, Register r3) {
|
||||
rrf1_form(MSGRKC, r1, r2, r3);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// 64-bit Multiply Instructions
|
||||
// ----------------------------
|
||||
|
@ -1160,6 +1160,8 @@ class Assembler : public AssemblerBase {
|
||||
|
||||
// 32-bit Multiply Instructions
|
||||
void mhi(Register r1, const Operand& opnd);
|
||||
void msrkc(Register r1, Register r2, Register r3);
|
||||
void msgrkc(Register r1, Register r2, Register r3);
|
||||
|
||||
// 64-bit Multiply Instructions
|
||||
void mghi(Register r1, const Operand& opnd);
|
||||
|
@ -271,6 +271,8 @@ typedef uint64_t SixByteInstr;
|
||||
V(sdtra, SDTRA, 0xB3D3) /* type = RRF_A SUBTRACT (long DFP) */ \
|
||||
V(mxtr, MXTR, 0xB3D8) /* type = RRF_A MULTIPLY (extended DFP) */ \
|
||||
V(mxtra, MXTRA, 0xB3D8) /* type = RRF_A MULTIPLY (extended DFP) */ \
|
||||
V(msrkc, MSRKC, 0xB9FD) /* type = RRF_A MULTIPLY (32)*/ \
|
||||
V(msgrkc, MSGRKC, 0xB9ED) /* type = RRF_A MULTIPLY (64)*/ \
|
||||
V(dxtr, DXTR, 0xB3D9) /* type = RRF_A DIVIDE (extended DFP) */ \
|
||||
V(dxtra, DXTRA, 0xB3D9) /* type = RRF_A DIVIDE (extended DFP) */ \
|
||||
V(axtr, AXTR, 0xB3DA) /* type = RRF_A ADD (extended DFP) */ \
|
||||
|
@ -775,6 +775,9 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
|
||||
case MSR:
|
||||
Format(instr, "msr\t'r5,'r6");
|
||||
break;
|
||||
case MSRKC:
|
||||
Format(instr, "msrkc\t'r5,'r6,'r3");
|
||||
break;
|
||||
case LGBR:
|
||||
Format(instr, "lgbr\t'r5,'r6");
|
||||
break;
|
||||
@ -784,6 +787,9 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
|
||||
case MSGR:
|
||||
Format(instr, "msgr\t'r5,'r6");
|
||||
break;
|
||||
case MSGRKC:
|
||||
Format(instr, "msgrkc\t'r5,'r6,'r3");
|
||||
break;
|
||||
case DSGR:
|
||||
Format(instr, "dsgr\t'r5,'r6");
|
||||
break;
|
||||
|
@ -3340,13 +3340,17 @@ void MacroAssembler::Mul64(Register dst, const Operand& src1) {
|
||||
}
|
||||
|
||||
void MacroAssembler::Mul(Register dst, Register src1, Register src2) {
|
||||
if (dst.is(src2)) {
|
||||
MulP(dst, src1);
|
||||
} else if (dst.is(src1)) {
|
||||
MulP(dst, src2);
|
||||
if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
|
||||
MulPWithCondition(dst, src1, src2);
|
||||
} else {
|
||||
Move(dst, src1);
|
||||
MulP(dst, src2);
|
||||
if (dst.is(src2)) {
|
||||
MulP(dst, src1);
|
||||
} else if (dst.is(src1)) {
|
||||
MulP(dst, src2);
|
||||
} else {
|
||||
Move(dst, src1);
|
||||
MulP(dst, src2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3478,6 +3482,16 @@ void MacroAssembler::MulP(Register dst, Register src) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void MacroAssembler::MulPWithCondition(Register dst, Register src1,
|
||||
Register src2) {
|
||||
CHECK(CpuFeatures::IsSupported(MISC_INSTR_EXT2));
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
msgrkc(dst, src1, src2);
|
||||
#else
|
||||
msrkc(dst, src1, src2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MacroAssembler::MulP(Register dst, const MemOperand& opnd) {
|
||||
#if V8_TARGET_ARCH_S390X
|
||||
if (is_uint16(opnd.offset())) {
|
||||
|
@ -336,6 +336,7 @@ class MacroAssembler : public Assembler {
|
||||
void Mul64(Register dst, const MemOperand& src1);
|
||||
void Mul64(Register dst, Register src1);
|
||||
void Mul64(Register dst, const Operand& src1);
|
||||
void MulPWithCondition(Register dst, Register src1, Register src2);
|
||||
|
||||
// Divide
|
||||
void DivP(Register dividend, Register divider);
|
||||
|
@ -985,6 +985,7 @@ void Simulator::EvalTableInit() {
|
||||
EvalTable[SAR] = &Simulator::Evaluate_SAR;
|
||||
EvalTable[EAR] = &Simulator::Evaluate_EAR;
|
||||
EvalTable[MSR] = &Simulator::Evaluate_MSR;
|
||||
EvalTable[MSRKC] = &Simulator::Evaluate_MSRKC;
|
||||
EvalTable[MVST] = &Simulator::Evaluate_MVST;
|
||||
EvalTable[CUSE] = &Simulator::Evaluate_CUSE;
|
||||
EvalTable[SRST] = &Simulator::Evaluate_SRST;
|
||||
@ -1158,6 +1159,7 @@ void Simulator::EvalTableInit() {
|
||||
EvalTable[ALGR] = &Simulator::Evaluate_ALGR;
|
||||
EvalTable[SLGR] = &Simulator::Evaluate_SLGR;
|
||||
EvalTable[MSGR] = &Simulator::Evaluate_MSGR;
|
||||
EvalTable[MSGRKC] = &Simulator::Evaluate_MSGRKC;
|
||||
EvalTable[DSGR] = &Simulator::Evaluate_DSGR;
|
||||
EvalTable[LRVGR] = &Simulator::Evaluate_LRVGR;
|
||||
EvalTable[LPGFR] = &Simulator::Evaluate_LPGFR;
|
||||
@ -8471,6 +8473,21 @@ EVALUATE(MSR) {
|
||||
return length;
|
||||
}
|
||||
|
||||
EVALUATE(MSRKC) {
|
||||
DCHECK_OPCODE(MSRKC);
|
||||
DECODE_RRF_A_INSTRUCTION(r1, r2, r3);
|
||||
int32_t r2_val = get_low_register<int32_t>(r2);
|
||||
int32_t r3_val = get_low_register<int32_t>(r3);
|
||||
int64_t result64 =
|
||||
static_cast<int64_t>(r2_val) * static_cast<int64_t>(r3_val);
|
||||
int32_t result32 = static_cast<int32_t>(result64);
|
||||
bool isOF = (static_cast<int64_t>(result32) != result64);
|
||||
SetS390ConditionCode<int32_t>(result32, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
set_low_register(r1, result32);
|
||||
return length;
|
||||
}
|
||||
|
||||
EVALUATE(MVST) {
|
||||
UNIMPLEMENTED();
|
||||
USE(instr);
|
||||
@ -9996,6 +10013,20 @@ EVALUATE(MSGR) {
|
||||
return length;
|
||||
}
|
||||
|
||||
EVALUATE(MSGRKC) {
|
||||
DCHECK_OPCODE(MSGRKC);
|
||||
DECODE_RRF_A_INSTRUCTION(r1, r2, r3);
|
||||
int64_t r2_val = get_register(r2);
|
||||
int64_t r3_val = get_register(r3);
|
||||
volatile int64_t result64 = r2_val * r3_val;
|
||||
bool isOF = ((r2_val == -1 && result64 == (static_cast<int64_t>(1L) << 63)) ||
|
||||
(r2_val != 0 && result64 / r2_val != r3_val));
|
||||
SetS390ConditionCode<int64_t>(result64, 0);
|
||||
SetS390OverflowCode(isOF);
|
||||
set_register(r1, result64);
|
||||
return length;
|
||||
}
|
||||
|
||||
EVALUATE(DSGR) {
|
||||
DCHECK_OPCODE(DSGR);
|
||||
DECODE_RRE_INSTRUCTION(r1, r2);
|
||||
|
@ -758,6 +758,7 @@ class Simulator {
|
||||
EVALUATE(SAR);
|
||||
EVALUATE(EAR);
|
||||
EVALUATE(MSR);
|
||||
EVALUATE(MSRKC);
|
||||
EVALUATE(MVST);
|
||||
EVALUATE(CUSE);
|
||||
EVALUATE(SRST);
|
||||
@ -931,6 +932,7 @@ class Simulator {
|
||||
EVALUATE(ALGR);
|
||||
EVALUATE(SLGR);
|
||||
EVALUATE(MSGR);
|
||||
EVALUATE(MSGRKC);
|
||||
EVALUATE(DSGR);
|
||||
EVALUATE(LRVGR);
|
||||
EVALUATE(LPGFR);
|
||||
|
@ -413,4 +413,89 @@ TEST(9) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test msrkc and msgrkc
|
||||
TEST(10) {
|
||||
if (!CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
::printf("MISC_INSTR_EXT2 is enabled.\n");
|
||||
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Assembler assm(isolate, NULL, 0);
|
||||
|
||||
Label ok, failed;
|
||||
|
||||
{ // test 1: msrkc
|
||||
__ lgfi(r2, Operand(3));
|
||||
__ lgfi(r3, Operand(4));
|
||||
__ msrkc(r1, r2, r3); // 3 * 4
|
||||
__ b(static_cast<Condition>(le | overflow), &failed); // test failed.
|
||||
__ chi(r1, Operand(12));
|
||||
__ bne(&failed); // test failed.
|
||||
|
||||
__ lgfi(r2, Operand(-3));
|
||||
__ lgfi(r3, Operand(4));
|
||||
__ msrkc(r1, r2, r3); // -3 * 4
|
||||
__ b(static_cast<Condition>(ge | overflow), &failed); // test failed.
|
||||
__ chi(r1, Operand(-12));
|
||||
__ bne(&failed); // test failed.
|
||||
|
||||
__ iilf(r2, Operand(0x80000000));
|
||||
__ lgfi(r3, Operand(-1));
|
||||
__ msrkc(r1, r2, r3); // INT_MIN * -1
|
||||
__ b(nooverflow, &failed); // test failed.
|
||||
__ cfi(r1, Operand(0x80000000));
|
||||
__ bne(&failed); // test failed.
|
||||
}
|
||||
|
||||
{ // test 1: msgrkc
|
||||
__ lgfi(r2, Operand(3));
|
||||
__ lgfi(r3, Operand(4));
|
||||
__ msgrkc(r1, r2, r3); // 3 * 4
|
||||
__ b(static_cast<Condition>(le | overflow), &failed); // test failed.
|
||||
__ chi(r1, Operand(12));
|
||||
__ bne(&failed); // test failed.
|
||||
|
||||
__ lgfi(r2, Operand(-3));
|
||||
__ lgfi(r3, Operand(4));
|
||||
__ msgrkc(r1, r2, r3); // -3 * 4
|
||||
__ b(static_cast<Condition>(ge | overflow), &failed); // test failed.
|
||||
__ chi(r1, Operand(-12));
|
||||
__ bne(&failed); // test failed.
|
||||
|
||||
__ lgfi(r2, Operand::Zero());
|
||||
__ iihf(r2, Operand(0x80000000));
|
||||
__ lgfi(r3, Operand(-1));
|
||||
__ msgrkc(r1, r2, r3); // INT_MIN * -1
|
||||
__ b(nooverflow, &failed); // test failed.
|
||||
__ cgr(r1, r2);
|
||||
__ bne(&failed); // test failed.
|
||||
}
|
||||
|
||||
__ bind(&ok);
|
||||
__ lgfi(r2, Operand::Zero());
|
||||
__ b(r14); // test done.
|
||||
|
||||
__ bind(&failed);
|
||||
__ lgfi(r2, Operand(1));
|
||||
__ b(r14);
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
#ifdef DEBUG
|
||||
code->Print();
|
||||
#endif
|
||||
F2 f = FUNCTION_CAST<F2>(code->entry());
|
||||
intptr_t res = reinterpret_cast<intptr_t>(
|
||||
CALL_GENERATED_CODE(isolate, f, 3, 4, 0, 0, 0));
|
||||
::printf("f() = %" V8PRIxPTR "\n", res);
|
||||
CHECK_EQ(0, static_cast<int>(res));
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
Loading…
Reference in New Issue
Block a user