Commit 2dab40cc authored by jyan's avatar jyan Committed by Commit bot

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}
parent d891b500
......@@ -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 V8_TARGET_ARCH_S390X
// result = left * right.
if (instr->hydrogen()->representation().IsSmi()) {
__ SmiUntag(result, left);
__ SmiUntag(scratch, right);
__ msgr(result, scratch);
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 {
__ LoadRR(result, left);
__ msgr(result, right);
}
__ TestIfInt32(result, r0);
DeoptimizeIf(ne, instr, DeoptimizeReason::kOverflow);
if (instr->hydrogen()->representation().IsSmi()) {
__ SmiTag(result);
}
#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);
}
#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 __
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment