Commit dc884581 authored by jyan's avatar jyan Committed by Commit bot

S390: Decouple Add/Sub/Neg to 32/64 Bit Op

1. Decouple kS390_Add/Sub/Neg to
     kS390_Add32/Sub32/Neg32/Add64/Sub64/Neg64
2. Nuke kS390_Add/SubWithOverflow32
3. Add Support for Load-On-Condition to optimize AssembleArchBoolean

R=joransiu@ca.ibm.com, michael_dawson@ca.ibm.com, mbrandy@us.ibm.com, bjaideep@ca.ibm.com
BUG=

Review-Url: https://codereview.chromium.org/2220313002
Cr-Commit-Position: refs/heads/master@{#38443}
parent 0d9ce3ac
......@@ -235,26 +235,22 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
case kOverflow:
// Overflow checked for AddP/SubP only.
switch (op) {
#if V8_TARGET_ARCH_S390X
case kS390_Add:
case kS390_Sub:
#endif
case kS390_AddWithOverflow32:
case kS390_SubWithOverflow32:
return lt;
case kS390_Add32:
case kS390_Add64:
case kS390_Sub32:
case kS390_Sub64:
return overflow;
default:
break;
}
break;
case kNotOverflow:
switch (op) {
#if V8_TARGET_ARCH_S390X
case kS390_Add:
case kS390_Sub:
#endif
case kS390_AddWithOverflow32:
case kS390_SubWithOverflow32:
return ge;
case kS390_Add32:
case kS390_Add64:
case kS390_Sub32:
case kS390_Sub64:
return nooverflow;
default:
break;
}
......@@ -290,56 +286,6 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
} \
} while (0)
#define ASSEMBLE_BINOP_INT(asm_instr_reg, asm_instr_imm) \
do { \
if (HasRegisterInput(instr, 1)) { \
__ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
i.InputRegister(1)); \
} else { \
__ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
i.InputInt32(1)); \
} \
} while (0)
#define ASSEMBLE_ADD_WITH_OVERFLOW() \
do { \
if (HasRegisterInput(instr, 1)) { \
__ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
i.InputRegister(1), kScratchReg, r0); \
} else { \
__ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
i.InputInt32(1), kScratchReg, r0); \
} \
} while (0)
#define ASSEMBLE_SUB_WITH_OVERFLOW() \
do { \
if (HasRegisterInput(instr, 1)) { \
__ SubAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
i.InputRegister(1), kScratchReg, r0); \
} else { \
__ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
-i.InputInt32(1), kScratchReg, r0); \
} \
} while (0)
#if V8_TARGET_ARCH_S390X
#define ASSEMBLE_ADD_WITH_OVERFLOW32() \
do { \
ASSEMBLE_ADD_WITH_OVERFLOW(); \
__ LoadAndTestP_ExtendSrc(kScratchReg, kScratchReg); \
} while (0)
#define ASSEMBLE_SUB_WITH_OVERFLOW32() \
do { \
ASSEMBLE_SUB_WITH_OVERFLOW(); \
__ LoadAndTestP_ExtendSrc(kScratchReg, kScratchReg); \
} while (0)
#else
#define ASSEMBLE_ADD_WITH_OVERFLOW32 ASSEMBLE_ADD_WITH_OVERFLOW
#define ASSEMBLE_SUB_WITH_OVERFLOW32 ASSEMBLE_SUB_WITH_OVERFLOW
#endif
#define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \
do { \
if (HasRegisterInput(instr, 1)) { \
......@@ -1209,19 +1155,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
}
break;
#endif
case kS390_Add:
#if V8_TARGET_ARCH_S390X
if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
ASSEMBLE_ADD_WITH_OVERFLOW();
} else {
#endif
ASSEMBLE_BINOP(AddP);
#if V8_TARGET_ARCH_S390X
}
#endif
case kS390_Add32:
ASSEMBLE_BINOP(Add32);
__ LoadW(i.OutputRegister(), i.OutputRegister());
break;
case kS390_AddWithOverflow32:
ASSEMBLE_ADD_WITH_OVERFLOW32();
case kS390_Add64:
ASSEMBLE_BINOP(AddP);
break;
case kS390_AddFloat:
// Ensure we don't clobber right/InputReg(1)
......@@ -1243,19 +1182,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ adbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
}
break;
case kS390_Sub:
#if V8_TARGET_ARCH_S390X
if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
ASSEMBLE_SUB_WITH_OVERFLOW();
} else {
#endif
ASSEMBLE_BINOP(SubP);
#if V8_TARGET_ARCH_S390X
}
#endif
case kS390_Sub32:
ASSEMBLE_BINOP(Sub32);
__ LoadW(i.OutputRegister(), i.OutputRegister());
break;
case kS390_SubWithOverflow32:
ASSEMBLE_SUB_WITH_OVERFLOW32();
case kS390_Sub64:
ASSEMBLE_BINOP(SubP);
break;
case kS390_SubFloat:
// OutputDoubleReg() = i.InputDoubleRegister(0) - i.InputDoubleRegister(1)
......@@ -1486,8 +1418,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Move(d1, d3);
break;
}
case kS390_Neg:
__ LoadComplementRR(i.OutputRegister(), i.InputRegister(0));
case kS390_Neg32:
__ lcr(i.OutputRegister(), i.InputRegister(0));
__ LoadW(i.OutputRegister(), i.OutputRegister());
break;
case kS390_Neg64:
__ lcgr(i.OutputRegister(), i.InputRegister(0));
break;
case kS390_MaxDouble:
ASSEMBLE_FLOAT_MAX();
......@@ -2020,63 +1956,29 @@ void CodeGenerator::AssembleArchJump(RpoNumber target) {
void CodeGenerator::AssembleArchBoolean(Instruction* instr,
FlagsCondition condition) {
S390OperandConverter i(this, instr);
Label done;
ArchOpcode op = instr->arch_opcode();
bool check_unordered = (op == kS390_CmpDouble || kS390_CmpFloat);
bool check_unordered = (op == kS390_CmpDouble || op == kS390_CmpFloat);
// Overflow checked for add/sub only.
DCHECK((condition != kOverflow && condition != kNotOverflow) ||
(op == kS390_AddWithOverflow32 || op == kS390_SubWithOverflow32) ||
(op == kS390_Add || op == kS390_Sub));
(op == kS390_Add32 || kS390_Add64 || op == kS390_Sub32 ||
op == kS390_Sub64));
// Materialize a full 32-bit 1 or 0 value. The result register is always the
// last output of the instruction.
DCHECK_NE(0u, instr->OutputCount());
Register reg = i.OutputRegister(instr->OutputCount() - 1);
Condition cond = FlagsConditionToCondition(condition, op);
switch (cond) {
case ne:
case ge:
case gt:
if (check_unordered) {
__ LoadImmP(reg, Operand(1));
__ LoadImmP(kScratchReg, Operand::Zero());
__ bunordered(&done);
Label cond_true;
__ b(cond, &cond_true, Label::kNear);
__ LoadRR(reg, kScratchReg);
__ bind(&cond_true);
} else {
Label cond_true, done_here;
__ LoadImmP(reg, Operand(1));
__ b(cond, &cond_true, Label::kNear);
__ LoadImmP(reg, Operand::Zero());
__ bind(&cond_true);
}
break;
case eq:
case lt:
case le:
if (check_unordered) {
__ LoadImmP(reg, Operand::Zero());
__ LoadImmP(kScratchReg, Operand(1));
__ bunordered(&done);
Label cond_false;
__ b(NegateCondition(cond), &cond_false, Label::kNear);
__ LoadRR(reg, kScratchReg);
__ bind(&cond_false);
} else {
__ LoadImmP(reg, Operand::Zero());
Label cond_false;
__ b(NegateCondition(cond), &cond_false, Label::kNear);
__ LoadImmP(reg, Operand(1));
__ bind(&cond_false);
}
break;
default:
UNREACHABLE();
break;
Label done;
if (check_unordered) {
__ LoadImmP(reg, (cond == eq || cond == le || cond == lt) ? Operand::Zero()
: Operand(1));
__ bunordered(&done);
}
__ LoadImmP(reg, Operand::Zero());
__ LoadImmP(kScratchReg, Operand(1));
// locr is sufficient since reg's upper 32 is guarrantee to be 0
__ locr(cond, reg, kScratchReg);
__ bind(&done);
}
......
......@@ -35,13 +35,13 @@ namespace compiler {
V(S390_RotLeftAndClear64) \
V(S390_RotLeftAndClearLeft64) \
V(S390_RotLeftAndClearRight64) \
V(S390_Add) \
V(S390_AddWithOverflow32) \
V(S390_Add32) \
V(S390_Add64) \
V(S390_AddPair) \
V(S390_AddFloat) \
V(S390_AddDouble) \
V(S390_Sub) \
V(S390_SubWithOverflow32) \
V(S390_Sub32) \
V(S390_Sub64) \
V(S390_SubFloat) \
V(S390_SubDouble) \
V(S390_SubPair) \
......@@ -64,7 +64,8 @@ namespace compiler {
V(S390_ModU32) \
V(S390_ModU64) \
V(S390_ModDouble) \
V(S390_Neg) \
V(S390_Neg32) \
V(S390_Neg64) \
V(S390_NegDouble) \
V(S390_SqrtFloat) \
V(S390_FloorFloat) \
......
......@@ -36,13 +36,13 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kS390_RotLeftAndClear64:
case kS390_RotLeftAndClearLeft64:
case kS390_RotLeftAndClearRight64:
case kS390_Add:
case kS390_AddWithOverflow32:
case kS390_Add32:
case kS390_Add64:
case kS390_AddPair:
case kS390_AddFloat:
case kS390_AddDouble:
case kS390_Sub:
case kS390_SubWithOverflow32:
case kS390_Sub32:
case kS390_Sub64:
case kS390_SubPair:
case kS390_MulPair:
case kS390_SubFloat:
......@@ -65,7 +65,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kS390_ModU32:
case kS390_ModU64:
case kS390_ModDouble:
case kS390_Neg:
case kS390_Neg32:
case kS390_Neg64:
case kS390_NegDouble:
case kS390_SqrtFloat:
case kS390_FloorFloat:
......
......@@ -874,12 +874,12 @@ void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
}
void InstructionSelector::VisitInt32Add(Node* node) {
VisitBinop<Int32BinopMatcher>(this, node, kS390_Add, kInt16Imm);
VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt16Imm);
}
#if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitInt64Add(Node* node) {
VisitBinop<Int64BinopMatcher>(this, node, kS390_Add, kInt16Imm);
VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt16Imm);
}
#endif
......@@ -887,9 +887,10 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
S390OperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.left().Is(0)) {
Emit(kS390_Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
Emit(kS390_Neg32, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub, kInt16Imm_Negate);
VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32, kInt16Imm_Negate);
}
}
......@@ -898,9 +899,10 @@ void InstructionSelector::VisitInt64Sub(Node* node) {
S390OperandGenerator g(this);
Int64BinopMatcher m(node);
if (m.left().Is(0)) {
Emit(kS390_Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
Emit(kS390_Neg64, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub, kInt16Imm_Negate);
VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64, kInt16Imm_Negate);
}
}
#endif
......@@ -1284,44 +1286,44 @@ void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int32BinopMatcher>(this, node, kS390_AddWithOverflow32,
kInt16Imm, &cont);
return VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt16Imm,
&cont);
}
FlagsContinuation cont;
VisitBinop<Int32BinopMatcher>(this, node, kS390_AddWithOverflow32, kInt16Imm,
&cont);
VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt16Imm, &cont);
}
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int32BinopMatcher>(this, node, kS390_SubWithOverflow32,
return VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32,
kInt16Imm_Negate, &cont);
}
FlagsContinuation cont;
VisitBinop<Int32BinopMatcher>(this, node, kS390_SubWithOverflow32,
kInt16Imm_Negate, &cont);
VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32, kInt16Imm_Negate,
&cont);
}
#if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Add, kInt16Imm,
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt16Imm,
&cont);
}
FlagsContinuation cont;
VisitBinop<Int64BinopMatcher>(this, node, kS390_Add, kInt16Imm, &cont);
VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt16Imm, &cont);
}
void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub,
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64,
kInt16Imm_Negate, &cont);
}
FlagsContinuation cont;
VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub, kInt16Imm_Negate, &cont);
VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64, kInt16Imm_Negate,
&cont);
}
#endif
......@@ -1497,24 +1499,23 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kInt32AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int32BinopMatcher>(
selector, node, kS390_AddWithOverflow32, kInt16Imm, cont);
selector, node, kS390_Add32, kInt16Imm, cont);
case IrOpcode::kInt32SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int32BinopMatcher>(selector, node,
kS390_SubWithOverflow32,
kInt16Imm_Negate, cont);
return VisitBinop<Int32BinopMatcher>(
selector, node, kS390_Sub32, kInt16Imm_Negate, cont);
case IrOpcode::kInt32MulWithOverflow:
cont->OverwriteAndNegateIfEqual(kNotEqual);
return EmitInt32MulWithOverflow(selector, node, cont);
#if V8_TARGET_ARCH_S390X
case IrOpcode::kInt64AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int64BinopMatcher>(selector, node, kS390_Add,
kInt16Imm, cont);
return VisitBinop<Int64BinopMatcher>(
selector, node, kS390_Add64, kInt16Imm, cont);
case IrOpcode::kInt64SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int64BinopMatcher>(selector, node, kS390_Sub,
kInt16Imm_Negate, cont);
return VisitBinop<Int64BinopMatcher>(
selector, node, kS390_Sub64, kInt16Imm_Negate, cont);
#endif
default:
break;
......@@ -1610,7 +1611,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand index_operand = value_operand;
if (sw.min_value) {
index_operand = g.TempRegister();
Emit(kS390_Sub, index_operand, value_operand,
Emit(kS390_Sub32, index_operand, value_operand,
g.TempImmediate(sw.min_value));
}
// Generate a table lookup.
......
......@@ -1908,14 +1908,14 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
break;
}
case Token::ADD: {
__ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0);
__ BranchOnOverflow(&stub_call);
__ AddP(scratch1, left, right);
__ b(overflow, &stub_call);
__ LoadRR(right, scratch1);
break;
}
case Token::SUB: {
__ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0);
__ BranchOnOverflow(&stub_call);
__ SubP(scratch1, left, right);
__ b(overflow, &stub_call);
__ LoadRR(right, scratch1);
break;
}
......@@ -3204,10 +3204,10 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Register scratch1 = r3;
Register scratch2 = r4;
__ LoadSmiLiteral(scratch1, Smi::FromInt(count_value));
__ AddAndCheckForOverflow(r2, r2, scratch1, scratch2, r0);
__ BranchOnNoOverflow(&done);
__ AddP(scratch2, r2, scratch1);
__ LoadOnConditionP(nooverflow, r2, scratch2);
__ b(nooverflow, &done);
// Call stub. Undo operation first.
__ SubP(r2, r2, scratch1);
__ b(&stub_call);
__ bind(&slow);
}
......
......@@ -971,6 +971,20 @@ void Assembler::rxy_form(Opcode op, Register r1, Register x2, Register b2,
emit6bytes(code);
}
void Assembler::rxy_form(Opcode op, Register r1, Condition m3, Register b2,
Disp d2) {
DCHECK(is_int20(d2));
DCHECK(is_uint16(op));
uint64_t code = (static_cast<uint64_t>(op & 0xFF00)) * B32 |
(static_cast<uint64_t>(r1.code())) * B36 |
(static_cast<uint64_t>(m3 & 0xF)) * B32 |
(static_cast<uint64_t>(b2.code())) * B28 |
(static_cast<uint64_t>(d2 & 0x0FFF)) * B16 |
(static_cast<uint64_t>(d2 & 0x0FF000)) >> 4 |
(static_cast<uint64_t>(op & 0x00FF));
emit6bytes(code);
}
void Assembler::rxy_form(Opcode op, DoubleRegister r1, Register x2, Register b2,
Disp d2) {
DCHECK(is_int20(d2));
......@@ -1418,7 +1432,6 @@ RIL1_FORM_EMIT(llihf, LLIHF)
RIL1_FORM_EMIT(llilf, LLILF)
RRE_FORM_EMIT(lngr, LNGR)
RR_FORM_EMIT(lnr, LNR)
RSY1_FORM_EMIT(loc, LOC)
RRE_FORM_EMIT(lrvr, LRVR)
RRE_FORM_EMIT(lrvgr, LRVGR)
RXY_FORM_EMIT(lrv, LRV)
......@@ -1604,6 +1617,26 @@ void Assembler::llhr(Register r1, Register r2) { rre_form(LLHR, r1, r2); }
// Load Logical halfword Register-Register (64)
void Assembler::llghr(Register r1, Register r2) { rre_form(LLGHR, r1, r2); }
// Load On Condition R-R (32)
void Assembler::locr(Condition m3, Register r1, Register r2) {
rrf2_form(LOCR << 16 | m3 * B12 | r1.code() * B4 | r2.code());
}
// Load On Condition R-R (64)
void Assembler::locgr(Condition m3, Register r1, Register r2) {
rrf2_form(LOCGR << 16 | m3 * B12 | r1.code() * B4 | r2.code());
}
// Load On Condition R-M (32)
void Assembler::loc(Condition m3, Register r1, const MemOperand& src) {
rxy_form(LOC, r1, m3, src.rb(), src.offset());
}
// Load On Condition R-M (64)
void Assembler::locg(Condition m3, Register r1, const MemOperand& src) {
rxy_form(LOCG, r1, m3, src.rb(), src.offset());
}
// -------------------
// Branch Instructions
// -------------------
......
......@@ -875,6 +875,12 @@ class Assembler : public AssemblerBase {
void lmy(Register r1, Register r2, const MemOperand& src);
void lmg(Register r1, Register r2, const MemOperand& src);
// Load On Condition Instructions
void locr(Condition m3, Register r1, Register r2);
void locgr(Condition m3, Register r1, Register r2);
void loc(Condition m3, Register r1, const MemOperand& src);
void locg(Condition m3, Register r1, const MemOperand& src);
// Store Instructions
void st(Register r, const MemOperand& src);
void stc(Register r, const MemOperand& src);
......@@ -1416,6 +1422,8 @@ class Assembler : public AssemblerBase {
inline void rxy_form(Opcode op, Register r1, Register x2, Register b2,
Disp d2);
inline void rxy_form(Opcode op, Register r1, Condition m3, Register b2,
Disp d2);
inline void rxy_form(Opcode op, DoubleRegister r1, Register x2, Register b2,
Disp d2);
......
......@@ -820,6 +820,12 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
case LLGHR:
Format(instr, "llghr\t'r5,'r6");
break;
case LOCR:
Format(instr, "locr\t'm1,'r5,'r6");
break;
case LOCGR:
Format(instr, "locgr\t'm1,'r5,'r6");
break;
case LNGR:
Format(instr, "lngr\t'r5,'r6");
break;
......@@ -1130,6 +1136,12 @@ bool Decoder::DecodeSixByte(Instruction* instr) {
case RISBGN:
Format(instr, "risbgn\t'r1,'r2,'i9,'ia,'ib");
break;
case LOCG:
Format(instr, "locg\t'm2,'r1,'d2('r3)");
break;
case LOC:
Format(instr, "loc\t'm2,'r1,'d2('r3)");
break;
case LMY:
Format(instr, "lmy\t'r1,'r2,'d2('r3)");
break;
......
......@@ -2188,89 +2188,6 @@ void MacroAssembler::StoreNumberToDoubleElements(
FixedDoubleArray::kHeaderSize - elements_offset));
}
void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
Register right,
Register overflow_dst,
Register scratch) {
DCHECK(!dst.is(overflow_dst));
DCHECK(!dst.is(scratch));
DCHECK(!overflow_dst.is(scratch));
DCHECK(!overflow_dst.is(left));
DCHECK(!overflow_dst.is(right));
// TODO(joransiu): Optimize paths for left == right.
bool left_is_right = left.is(right);
// C = A+B; C overflows if A/B have same sign and C has diff sign than A
if (dst.is(left)) {
LoadRR(scratch, left); // Preserve left.
AddP(dst, left, right); // Left is overwritten.
XorP(overflow_dst, scratch, dst); // Original left.
if (!left_is_right) XorP(scratch, dst, right);
} else if (dst.is(right)) {
LoadRR(scratch, right); // Preserve right.
AddP(dst, left, right); // Right is overwritten.
XorP(overflow_dst, dst, left);
if (!left_is_right) XorP(scratch, dst, scratch);
} else {
AddP(dst, left, right);
XorP(overflow_dst, dst, left);
if (!left_is_right) XorP(scratch, dst, right);
}
if (!left_is_right) AndP(overflow_dst, scratch, overflow_dst);
LoadAndTestRR(overflow_dst, overflow_dst);
}
void MacroAssembler::AddAndCheckForOverflow(Register dst, Register left,
intptr_t right,
Register overflow_dst,
Register scratch) {
DCHECK(!dst.is(overflow_dst));
DCHECK(!dst.is(scratch));
DCHECK(!overflow_dst.is(scratch));
DCHECK(!overflow_dst.is(left));
mov(r1, Operand(right));
AddAndCheckForOverflow(dst, left, r1, overflow_dst, scratch);
}
void MacroAssembler::SubAndCheckForOverflow(Register dst, Register left,
Register right,
Register overflow_dst,
Register scratch) {
DCHECK(!dst.is(overflow_dst));
DCHECK(!dst.is(scratch));
DCHECK(!overflow_dst.is(scratch));
DCHECK(!overflow_dst.is(left));
DCHECK(!overflow_dst.is(right));
// C = A-B; C overflows if A/B have diff signs and C has diff sign than A
if (dst.is(left)) {
LoadRR(scratch, left); // Preserve left.
SubP(dst, left, right); // Left is overwritten.
XorP(overflow_dst, dst, scratch);
XorP(scratch, right);
AndP(overflow_dst, scratch /*, SetRC*/);
LoadAndTestRR(overflow_dst, overflow_dst);
// Should be okay to remove rc
} else if (dst.is(right)) {
LoadRR(scratch, right); // Preserve right.
SubP(dst, left, right); // Right is overwritten.
XorP(overflow_dst, dst, left);
XorP(scratch, left);
AndP(overflow_dst, scratch /*, SetRC*/);
LoadAndTestRR(overflow_dst, overflow_dst);
// Should be okay to remove rc
} else {
SubP(dst, left, right);
XorP(overflow_dst, dst, left);
XorP(scratch, left, right);
AndP(overflow_dst, scratch /*, SetRC*/);
LoadAndTestRR(overflow_dst, overflow_dst);
// Should be okay to remove rc
}
}
void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
Label* early_success) {
LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
......@@ -4159,15 +4076,18 @@ void MacroAssembler::SubP_ExtendSrc(Register dst, Register src) {
// Subtract 32-bit (Register = Register - Register)
void MacroAssembler::Sub32(Register dst, Register src1, Register src2) {
// Use non-clobbering version if possible
if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) {
if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
srk(dst, src1, src2);
return;
}
if (!dst.is(src1) && !dst.is(src2)) lr(dst, src1);
// In scenario where we have dst = src - dst, we need to swap and negate
if (!dst.is(src1) && dst.is(src2)) {
sr(dst, src1); // dst = (dst - src)
Label done;
lcr(dst, dst); // dst = -dst
b(overflow, &done);
ar(dst, src1); // dst = dst + src
bind(&done);
} else {
sr(dst, src2);
}
......@@ -4176,15 +4096,18 @@ void MacroAssembler::Sub32(Register dst, Register src1, Register src2) {
// Subtract Pointer Sized (Register = Register - Register)
void MacroAssembler::SubP(Register dst, Register src1, Register src2) {
// Use non-clobbering version if possible
if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) {
if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
SubP_RRR(dst, src1, src2);
return;
}
if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1);
// In scenario where we have dst = src - dst, we need to swap and negate
if (!dst.is(src1) && dst.is(src2)) {
SubP(dst, src1); // dst = (dst - src)
Label done;
LoadComplementRR(dst, dst); // dst = -dst
b(overflow, &done);
AddP(dst, src1); // dst = dst + src
bind(&done);
} else {
SubP(dst, src2);
}
......@@ -4202,8 +4125,8 @@ void MacroAssembler::SubP_ExtendSrc(Register dst, Register src1,
// In scenario where we have dst = src - dst, we need to swap and negate
if (!dst.is(src1) && dst.is(src2)) {
lgfr(dst, dst); // Sign extend this operand first.
SubP(dst, src1); // dst = (dst - src)
LoadComplementRR(dst, dst); // dst = -dst
AddP(dst, src1); // dst = -dst + src
} else {
sgfr(dst, src2);
}
......@@ -5182,6 +5105,16 @@ void MacroAssembler::LoadAndTestP(Register dst, const MemOperand& mem) {
#endif
}
// Load On Condition Pointer Sized (Reg <- Reg)
void MacroAssembler::LoadOnConditionP(Condition cond, Register dst,
Register src) {
#if V8_TARGET_ARCH_S390X
locgr(cond, dst, src);
#else
locr(cond, dst, src);
#endif
}
// Load Double Precision (64-bit) Floating Point number from memory
void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) {
// for 32bit and 64bit we all use 64bit floating point regs
......
......@@ -353,6 +353,9 @@ class MacroAssembler : public Assembler {
void LoadFloat32(DoubleRegister dst, const MemOperand& opnd);
void LoadFloat32ConvertToDouble(DoubleRegister dst, const MemOperand& mem);
// Load On Condition
void LoadOnConditionP(Condition cond, Register dst, Register src);
// Store Floating Point
void StoreDouble(DoubleRegister dst, const MemOperand& opnd);
void StoreFloat32(DoubleRegister dst, const MemOperand& opnd);
......@@ -1226,44 +1229,6 @@ class MacroAssembler : public Assembler {
Register heap_number_map, Register scratch1,
Label* not_int32);
// Overflow handling functions.
// Usage: call the appropriate arithmetic function and then call one of the
// flow control functions with the corresponding label.
// Compute dst = left + right, setting condition codes. dst may be same as
// either left or right (or a unique register). left and right must not be
// the same register.
void AddAndCheckForOverflow(Register dst, Register left, Register right,
Register overflow_dst, Register scratch = r0);
void AddAndCheckForOverflow(Register dst, Register left, intptr_t right,
Register overflow_dst, Register scratch = r0);
// Compute dst = left - right, setting condition codes. dst may be same as
// either left or right (or a unique register). left and right must not be
// the same register.
void SubAndCheckForOverflow(Register dst, Register left, Register right,
Register overflow_dst, Register scratch = r0);
void BranchOnOverflow(Label* label) { blt(label /*, cr0*/); }
void BranchOnNoOverflow(Label* label) { bge(label /*, cr0*/); }
void RetOnOverflow(void) {
Label label;
blt(&label /*, cr0*/);
Ret();
bind(&label);
}
void RetOnNoOverflow(void) {
Label label;
bge(&label /*, cr0*/);
Ret();
bind(&label);
}
// ---------------------------------------------------------------------------
// Runtime calls
......
......@@ -5978,6 +5978,12 @@ uintptr_t Simulator::PopAddress() {
int r3 = AS(RRFInstruction)->R3Value(); \
int length = 4;
#define DECODE_RRF_C_INSTRUCTION(r1, r2, m3) \
int r1 = AS(RRFInstruction)->R1Value(); \
int r2 = AS(RRFInstruction)->R2Value(); \
Condition m3 = static_cast<Condition>(AS(RRFInstruction)->M3Value()); \
int length = 4;
#define DECODE_RR_INSTRUCTION(r1, r2) \
int r1 = AS(RRInstruction)->R1Value(); \
int r2 = AS(RRInstruction)->R2Value(); \
......@@ -10467,9 +10473,12 @@ EVALUATE(POPCNT_Z) {
}
EVALUATE(LOCGR) {
UNIMPLEMENTED();
USE(instr);
return 0;
DCHECK_OPCODE(LOCR);
DECODE_RRF_C_INSTRUCTION(r1, r2, m3);
if (TestConditionCode(m3)) {
set_register(r1, get_register(r2));
}
return length;
}
EVALUATE(NGRK) {
......@@ -10564,9 +10573,12 @@ EVALUATE(SLGRK) {
}
EVALUATE(LOCR) {
UNIMPLEMENTED();
USE(instr);
return 0;
DCHECK_OPCODE(LOCR);
DECODE_RRF_C_INSTRUCTION(r1, r2, m3);
if (TestConditionCode(m3)) {
set_low_register(r1, get_low_register<int32_t>(r2));
}
return length;
}
EVALUATE(NRK) {
......
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