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}
This commit is contained in:
jyan 2016-08-08 07:02:52 -07:00 committed by Commit bot
parent 0d9ce3acff
commit dc88458120
11 changed files with 180 additions and 312 deletions

View File

@ -235,26 +235,22 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
case kOverflow: case kOverflow:
// Overflow checked for AddP/SubP only. // Overflow checked for AddP/SubP only.
switch (op) { switch (op) {
#if V8_TARGET_ARCH_S390X case kS390_Add32:
case kS390_Add: case kS390_Add64:
case kS390_Sub: case kS390_Sub32:
#endif case kS390_Sub64:
case kS390_AddWithOverflow32: return overflow;
case kS390_SubWithOverflow32:
return lt;
default: default:
break; break;
} }
break; break;
case kNotOverflow: case kNotOverflow:
switch (op) { switch (op) {
#if V8_TARGET_ARCH_S390X case kS390_Add32:
case kS390_Add: case kS390_Add64:
case kS390_Sub: case kS390_Sub32:
#endif case kS390_Sub64:
case kS390_AddWithOverflow32: return nooverflow;
case kS390_SubWithOverflow32:
return ge;
default: default:
break; break;
} }
@ -290,56 +286,6 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
} \ } \
} while (0) } 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) \ #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \
do { \ do { \
if (HasRegisterInput(instr, 1)) { \ if (HasRegisterInput(instr, 1)) { \
@ -1209,19 +1155,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
} }
break; break;
#endif #endif
case kS390_Add: case kS390_Add32:
#if V8_TARGET_ARCH_S390X ASSEMBLE_BINOP(Add32);
if (FlagsModeField::decode(instr->opcode()) != kFlags_none) { __ LoadW(i.OutputRegister(), i.OutputRegister());
ASSEMBLE_ADD_WITH_OVERFLOW();
} else {
#endif
ASSEMBLE_BINOP(AddP);
#if V8_TARGET_ARCH_S390X
}
#endif
break; break;
case kS390_AddWithOverflow32: case kS390_Add64:
ASSEMBLE_ADD_WITH_OVERFLOW32(); ASSEMBLE_BINOP(AddP);
break; break;
case kS390_AddFloat: case kS390_AddFloat:
// Ensure we don't clobber right/InputReg(1) // Ensure we don't clobber right/InputReg(1)
@ -1243,19 +1182,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ adbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1)); __ adbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
} }
break; break;
case kS390_Sub: case kS390_Sub32:
#if V8_TARGET_ARCH_S390X ASSEMBLE_BINOP(Sub32);
if (FlagsModeField::decode(instr->opcode()) != kFlags_none) { __ LoadW(i.OutputRegister(), i.OutputRegister());
ASSEMBLE_SUB_WITH_OVERFLOW();
} else {
#endif
ASSEMBLE_BINOP(SubP);
#if V8_TARGET_ARCH_S390X
}
#endif
break; break;
case kS390_SubWithOverflow32: case kS390_Sub64:
ASSEMBLE_SUB_WITH_OVERFLOW32(); ASSEMBLE_BINOP(SubP);
break; break;
case kS390_SubFloat: case kS390_SubFloat:
// OutputDoubleReg() = i.InputDoubleRegister(0) - i.InputDoubleRegister(1) // OutputDoubleReg() = i.InputDoubleRegister(0) - i.InputDoubleRegister(1)
@ -1486,8 +1418,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Move(d1, d3); __ Move(d1, d3);
break; break;
} }
case kS390_Neg: case kS390_Neg32:
__ LoadComplementRR(i.OutputRegister(), i.InputRegister(0)); __ lcr(i.OutputRegister(), i.InputRegister(0));
__ LoadW(i.OutputRegister(), i.OutputRegister());
break;
case kS390_Neg64:
__ lcgr(i.OutputRegister(), i.InputRegister(0));
break; break;
case kS390_MaxDouble: case kS390_MaxDouble:
ASSEMBLE_FLOAT_MAX(); ASSEMBLE_FLOAT_MAX();
@ -2020,63 +1956,29 @@ void CodeGenerator::AssembleArchJump(RpoNumber target) {
void CodeGenerator::AssembleArchBoolean(Instruction* instr, void CodeGenerator::AssembleArchBoolean(Instruction* instr,
FlagsCondition condition) { FlagsCondition condition) {
S390OperandConverter i(this, instr); S390OperandConverter i(this, instr);
Label done;
ArchOpcode op = instr->arch_opcode(); 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. // Overflow checked for add/sub only.
DCHECK((condition != kOverflow && condition != kNotOverflow) || DCHECK((condition != kOverflow && condition != kNotOverflow) ||
(op == kS390_AddWithOverflow32 || op == kS390_SubWithOverflow32) || (op == kS390_Add32 || kS390_Add64 || op == kS390_Sub32 ||
(op == kS390_Add || op == kS390_Sub)); op == kS390_Sub64));
// Materialize a full 32-bit 1 or 0 value. The result register is always the // Materialize a full 32-bit 1 or 0 value. The result register is always the
// last output of the instruction. // last output of the instruction.
DCHECK_NE(0u, instr->OutputCount()); DCHECK_NE(0u, instr->OutputCount());
Register reg = i.OutputRegister(instr->OutputCount() - 1); Register reg = i.OutputRegister(instr->OutputCount() - 1);
Condition cond = FlagsConditionToCondition(condition, op); Condition cond = FlagsConditionToCondition(condition, op);
switch (cond) { Label done;
case ne:
case ge:
case gt:
if (check_unordered) { if (check_unordered) {
__ LoadImmP(reg, Operand(1)); __ LoadImmP(reg, (cond == eq || cond == le || cond == lt) ? Operand::Zero()
__ LoadImmP(kScratchReg, Operand::Zero()); : Operand(1));
__ bunordered(&done); __ 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(reg, Operand::Zero());
__ LoadImmP(kScratchReg, Operand(1)); __ LoadImmP(kScratchReg, Operand(1));
__ bunordered(&done); // locr is sufficient since reg's upper 32 is guarrantee to be 0
Label cond_false; __ locr(cond, reg, kScratchReg);
__ 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;
}
__ bind(&done); __ bind(&done);
} }

View File

@ -35,13 +35,13 @@ namespace compiler {
V(S390_RotLeftAndClear64) \ V(S390_RotLeftAndClear64) \
V(S390_RotLeftAndClearLeft64) \ V(S390_RotLeftAndClearLeft64) \
V(S390_RotLeftAndClearRight64) \ V(S390_RotLeftAndClearRight64) \
V(S390_Add) \ V(S390_Add32) \
V(S390_AddWithOverflow32) \ V(S390_Add64) \
V(S390_AddPair) \ V(S390_AddPair) \
V(S390_AddFloat) \ V(S390_AddFloat) \
V(S390_AddDouble) \ V(S390_AddDouble) \
V(S390_Sub) \ V(S390_Sub32) \
V(S390_SubWithOverflow32) \ V(S390_Sub64) \
V(S390_SubFloat) \ V(S390_SubFloat) \
V(S390_SubDouble) \ V(S390_SubDouble) \
V(S390_SubPair) \ V(S390_SubPair) \
@ -64,7 +64,8 @@ namespace compiler {
V(S390_ModU32) \ V(S390_ModU32) \
V(S390_ModU64) \ V(S390_ModU64) \
V(S390_ModDouble) \ V(S390_ModDouble) \
V(S390_Neg) \ V(S390_Neg32) \
V(S390_Neg64) \
V(S390_NegDouble) \ V(S390_NegDouble) \
V(S390_SqrtFloat) \ V(S390_SqrtFloat) \
V(S390_FloorFloat) \ V(S390_FloorFloat) \

View File

@ -36,13 +36,13 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kS390_RotLeftAndClear64: case kS390_RotLeftAndClear64:
case kS390_RotLeftAndClearLeft64: case kS390_RotLeftAndClearLeft64:
case kS390_RotLeftAndClearRight64: case kS390_RotLeftAndClearRight64:
case kS390_Add: case kS390_Add32:
case kS390_AddWithOverflow32: case kS390_Add64:
case kS390_AddPair: case kS390_AddPair:
case kS390_AddFloat: case kS390_AddFloat:
case kS390_AddDouble: case kS390_AddDouble:
case kS390_Sub: case kS390_Sub32:
case kS390_SubWithOverflow32: case kS390_Sub64:
case kS390_SubPair: case kS390_SubPair:
case kS390_MulPair: case kS390_MulPair:
case kS390_SubFloat: case kS390_SubFloat:
@ -65,7 +65,8 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kS390_ModU32: case kS390_ModU32:
case kS390_ModU64: case kS390_ModU64:
case kS390_ModDouble: case kS390_ModDouble:
case kS390_Neg: case kS390_Neg32:
case kS390_Neg64:
case kS390_NegDouble: case kS390_NegDouble:
case kS390_SqrtFloat: case kS390_SqrtFloat:
case kS390_FloorFloat: case kS390_FloorFloat:

View File

@ -874,12 +874,12 @@ void InstructionSelector::VisitWord32ReverseBytes(Node* node) {
} }
void InstructionSelector::VisitInt32Add(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 #if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitInt64Add(Node* node) { void InstructionSelector::VisitInt64Add(Node* node) {
VisitBinop<Int64BinopMatcher>(this, node, kS390_Add, kInt16Imm); VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt16Imm);
} }
#endif #endif
@ -887,9 +887,10 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
S390OperandGenerator g(this); S390OperandGenerator g(this);
Int32BinopMatcher m(node); Int32BinopMatcher m(node);
if (m.left().Is(0)) { 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 { } 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); S390OperandGenerator g(this);
Int64BinopMatcher m(node); Int64BinopMatcher m(node);
if (m.left().Is(0)) { 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 { } else {
VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub, kInt16Imm_Negate); VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64, kInt16Imm_Negate);
} }
} }
#endif #endif
@ -1284,44 +1286,44 @@ void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int32BinopMatcher>(this, node, kS390_AddWithOverflow32, return VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt16Imm,
kInt16Imm, &cont); &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
VisitBinop<Int32BinopMatcher>(this, node, kS390_AddWithOverflow32, kInt16Imm, VisitBinop<Int32BinopMatcher>(this, node, kS390_Add32, kInt16Imm, &cont);
&cont);
} }
void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int32BinopMatcher>(this, node, kS390_SubWithOverflow32, return VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32,
kInt16Imm_Negate, &cont); kInt16Imm_Negate, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
VisitBinop<Int32BinopMatcher>(this, node, kS390_SubWithOverflow32, VisitBinop<Int32BinopMatcher>(this, node, kS390_Sub32, kInt16Imm_Negate,
kInt16Imm_Negate, &cont); &cont);
} }
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { void InstructionSelector::VisitInt64AddWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Add, kInt16Imm, return VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt16Imm,
&cont); &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
VisitBinop<Int64BinopMatcher>(this, node, kS390_Add, kInt16Imm, &cont); VisitBinop<Int64BinopMatcher>(this, node, kS390_Add64, kInt16Imm, &cont);
} }
void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
if (Node* ovf = NodeProperties::FindProjection(node, 1)) { if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf);
return VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub, return VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64,
kInt16Imm_Negate, &cont); kInt16Imm_Negate, &cont);
} }
FlagsContinuation cont; FlagsContinuation cont;
VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub, kInt16Imm_Negate, &cont); VisitBinop<Int64BinopMatcher>(this, node, kS390_Sub64, kInt16Imm_Negate,
&cont);
} }
#endif #endif
@ -1497,24 +1499,23 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kInt32AddWithOverflow: case IrOpcode::kInt32AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow); cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int32BinopMatcher>( return VisitBinop<Int32BinopMatcher>(
selector, node, kS390_AddWithOverflow32, kInt16Imm, cont); selector, node, kS390_Add32, kInt16Imm, cont);
case IrOpcode::kInt32SubWithOverflow: case IrOpcode::kInt32SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow); cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int32BinopMatcher>(selector, node, return VisitBinop<Int32BinopMatcher>(
kS390_SubWithOverflow32, selector, node, kS390_Sub32, kInt16Imm_Negate, cont);
kInt16Imm_Negate, cont);
case IrOpcode::kInt32MulWithOverflow: case IrOpcode::kInt32MulWithOverflow:
cont->OverwriteAndNegateIfEqual(kNotEqual); cont->OverwriteAndNegateIfEqual(kNotEqual);
return EmitInt32MulWithOverflow(selector, node, cont); return EmitInt32MulWithOverflow(selector, node, cont);
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
case IrOpcode::kInt64AddWithOverflow: case IrOpcode::kInt64AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow); cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int64BinopMatcher>(selector, node, kS390_Add, return VisitBinop<Int64BinopMatcher>(
kInt16Imm, cont); selector, node, kS390_Add64, kInt16Imm, cont);
case IrOpcode::kInt64SubWithOverflow: case IrOpcode::kInt64SubWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow); cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitBinop<Int64BinopMatcher>(selector, node, kS390_Sub, return VisitBinop<Int64BinopMatcher>(
kInt16Imm_Negate, cont); selector, node, kS390_Sub64, kInt16Imm_Negate, cont);
#endif #endif
default: default:
break; break;
@ -1610,7 +1611,7 @@ void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) {
InstructionOperand index_operand = value_operand; InstructionOperand index_operand = value_operand;
if (sw.min_value) { if (sw.min_value) {
index_operand = g.TempRegister(); index_operand = g.TempRegister();
Emit(kS390_Sub, index_operand, value_operand, Emit(kS390_Sub32, index_operand, value_operand,
g.TempImmediate(sw.min_value)); g.TempImmediate(sw.min_value));
} }
// Generate a table lookup. // Generate a table lookup.

View File

@ -1908,14 +1908,14 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
break; break;
} }
case Token::ADD: { case Token::ADD: {
__ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0); __ AddP(scratch1, left, right);
__ BranchOnOverflow(&stub_call); __ b(overflow, &stub_call);
__ LoadRR(right, scratch1); __ LoadRR(right, scratch1);
break; break;
} }
case Token::SUB: { case Token::SUB: {
__ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0); __ SubP(scratch1, left, right);
__ BranchOnOverflow(&stub_call); __ b(overflow, &stub_call);
__ LoadRR(right, scratch1); __ LoadRR(right, scratch1);
break; break;
} }
@ -3204,10 +3204,10 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Register scratch1 = r3; Register scratch1 = r3;
Register scratch2 = r4; Register scratch2 = r4;
__ LoadSmiLiteral(scratch1, Smi::FromInt(count_value)); __ LoadSmiLiteral(scratch1, Smi::FromInt(count_value));
__ AddAndCheckForOverflow(r2, r2, scratch1, scratch2, r0); __ AddP(scratch2, r2, scratch1);
__ BranchOnNoOverflow(&done); __ LoadOnConditionP(nooverflow, r2, scratch2);
__ b(nooverflow, &done);
// Call stub. Undo operation first. // Call stub. Undo operation first.
__ SubP(r2, r2, scratch1);
__ b(&stub_call); __ b(&stub_call);
__ bind(&slow); __ bind(&slow);
} }

View File

@ -971,6 +971,20 @@ void Assembler::rxy_form(Opcode op, Register r1, Register x2, Register b2,
emit6bytes(code); 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, void Assembler::rxy_form(Opcode op, DoubleRegister r1, Register x2, Register b2,
Disp d2) { Disp d2) {
DCHECK(is_int20(d2)); DCHECK(is_int20(d2));
@ -1418,7 +1432,6 @@ RIL1_FORM_EMIT(llihf, LLIHF)
RIL1_FORM_EMIT(llilf, LLILF) RIL1_FORM_EMIT(llilf, LLILF)
RRE_FORM_EMIT(lngr, LNGR) RRE_FORM_EMIT(lngr, LNGR)
RR_FORM_EMIT(lnr, LNR) RR_FORM_EMIT(lnr, LNR)
RSY1_FORM_EMIT(loc, LOC)
RRE_FORM_EMIT(lrvr, LRVR) RRE_FORM_EMIT(lrvr, LRVR)
RRE_FORM_EMIT(lrvgr, LRVGR) RRE_FORM_EMIT(lrvgr, LRVGR)
RXY_FORM_EMIT(lrv, LRV) 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) // Load Logical halfword Register-Register (64)
void Assembler::llghr(Register r1, Register r2) { rre_form(LLGHR, r1, r2); } 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 // Branch Instructions
// ------------------- // -------------------

View File

@ -875,6 +875,12 @@ class Assembler : public AssemblerBase {
void lmy(Register r1, Register r2, const MemOperand& src); void lmy(Register r1, Register r2, const MemOperand& src);
void lmg(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 // Store Instructions
void st(Register r, const MemOperand& src); void st(Register r, const MemOperand& src);
void stc(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, inline void rxy_form(Opcode op, Register r1, Register x2, Register b2,
Disp d2); 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, inline void rxy_form(Opcode op, DoubleRegister r1, Register x2, Register b2,
Disp d2); Disp d2);

View File

@ -820,6 +820,12 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
case LLGHR: case LLGHR:
Format(instr, "llghr\t'r5,'r6"); Format(instr, "llghr\t'r5,'r6");
break; break;
case LOCR:
Format(instr, "locr\t'm1,'r5,'r6");
break;
case LOCGR:
Format(instr, "locgr\t'm1,'r5,'r6");
break;
case LNGR: case LNGR:
Format(instr, "lngr\t'r5,'r6"); Format(instr, "lngr\t'r5,'r6");
break; break;
@ -1130,6 +1136,12 @@ bool Decoder::DecodeSixByte(Instruction* instr) {
case RISBGN: case RISBGN:
Format(instr, "risbgn\t'r1,'r2,'i9,'ia,'ib"); Format(instr, "risbgn\t'r1,'r2,'i9,'ia,'ib");
break; 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: case LMY:
Format(instr, "lmy\t'r1,'r2,'d2('r3)"); Format(instr, "lmy\t'r1,'r2,'d2('r3)");
break; break;

View File

@ -2188,89 +2188,6 @@ void MacroAssembler::StoreNumberToDoubleElements(
FixedDoubleArray::kHeaderSize - elements_offset)); 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, void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
Label* early_success) { Label* early_success) {
LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
@ -4159,15 +4076,18 @@ void MacroAssembler::SubP_ExtendSrc(Register dst, Register src) {
// Subtract 32-bit (Register = Register - Register) // Subtract 32-bit (Register = Register - Register)
void MacroAssembler::Sub32(Register dst, Register src1, Register src2) { void MacroAssembler::Sub32(Register dst, Register src1, Register src2) {
// Use non-clobbering version if possible // Use non-clobbering version if possible
if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) { if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
srk(dst, src1, src2); srk(dst, src1, src2);
return; return;
} }
if (!dst.is(src1) && !dst.is(src2)) lr(dst, src1); if (!dst.is(src1) && !dst.is(src2)) lr(dst, src1);
// In scenario where we have dst = src - dst, we need to swap and negate // In scenario where we have dst = src - dst, we need to swap and negate
if (!dst.is(src1) && dst.is(src2)) { if (!dst.is(src1) && dst.is(src2)) {
sr(dst, src1); // dst = (dst - src) Label done;
lcr(dst, dst); // dst = -dst lcr(dst, dst); // dst = -dst
b(overflow, &done);
ar(dst, src1); // dst = dst + src
bind(&done);
} else { } else {
sr(dst, src2); sr(dst, src2);
} }
@ -4176,15 +4096,18 @@ void MacroAssembler::Sub32(Register dst, Register src1, Register src2) {
// Subtract Pointer Sized (Register = Register - Register) // Subtract Pointer Sized (Register = Register - Register)
void MacroAssembler::SubP(Register dst, Register src1, Register src2) { void MacroAssembler::SubP(Register dst, Register src1, Register src2) {
// Use non-clobbering version if possible // Use non-clobbering version if possible
if (CpuFeatures::IsSupported(DISTINCT_OPS) && !dst.is(src1)) { if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
SubP_RRR(dst, src1, src2); SubP_RRR(dst, src1, src2);
return; return;
} }
if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1); if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1);
// In scenario where we have dst = src - dst, we need to swap and negate // In scenario where we have dst = src - dst, we need to swap and negate
if (!dst.is(src1) && dst.is(src2)) { if (!dst.is(src1) && dst.is(src2)) {
SubP(dst, src1); // dst = (dst - src) Label done;
LoadComplementRR(dst, dst); // dst = -dst LoadComplementRR(dst, dst); // dst = -dst
b(overflow, &done);
AddP(dst, src1); // dst = dst + src
bind(&done);
} else { } else {
SubP(dst, src2); 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 // In scenario where we have dst = src - dst, we need to swap and negate
if (!dst.is(src1) && dst.is(src2)) { if (!dst.is(src1) && dst.is(src2)) {
lgfr(dst, dst); // Sign extend this operand first. lgfr(dst, dst); // Sign extend this operand first.
SubP(dst, src1); // dst = (dst - src)
LoadComplementRR(dst, dst); // dst = -dst LoadComplementRR(dst, dst); // dst = -dst
AddP(dst, src1); // dst = -dst + src
} else { } else {
sgfr(dst, src2); sgfr(dst, src2);
} }
@ -5182,6 +5105,16 @@ void MacroAssembler::LoadAndTestP(Register dst, const MemOperand& mem) {
#endif #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 // Load Double Precision (64-bit) Floating Point number from memory
void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) { void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) {
// for 32bit and 64bit we all use 64bit floating point regs // for 32bit and 64bit we all use 64bit floating point regs

View File

@ -353,6 +353,9 @@ class MacroAssembler : public Assembler {
void LoadFloat32(DoubleRegister dst, const MemOperand& opnd); void LoadFloat32(DoubleRegister dst, const MemOperand& opnd);
void LoadFloat32ConvertToDouble(DoubleRegister dst, const MemOperand& mem); void LoadFloat32ConvertToDouble(DoubleRegister dst, const MemOperand& mem);
// Load On Condition
void LoadOnConditionP(Condition cond, Register dst, Register src);
// Store Floating Point // Store Floating Point
void StoreDouble(DoubleRegister dst, const MemOperand& opnd); void StoreDouble(DoubleRegister dst, const MemOperand& opnd);
void StoreFloat32(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, Register heap_number_map, Register scratch1,
Label* not_int32); 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 // Runtime calls

View File

@ -5978,6 +5978,12 @@ uintptr_t Simulator::PopAddress() {
int r3 = AS(RRFInstruction)->R3Value(); \ int r3 = AS(RRFInstruction)->R3Value(); \
int length = 4; 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) \ #define DECODE_RR_INSTRUCTION(r1, r2) \
int r1 = AS(RRInstruction)->R1Value(); \ int r1 = AS(RRInstruction)->R1Value(); \
int r2 = AS(RRInstruction)->R2Value(); \ int r2 = AS(RRInstruction)->R2Value(); \
@ -10467,9 +10473,12 @@ EVALUATE(POPCNT_Z) {
} }
EVALUATE(LOCGR) { EVALUATE(LOCGR) {
UNIMPLEMENTED(); DCHECK_OPCODE(LOCR);
USE(instr); DECODE_RRF_C_INSTRUCTION(r1, r2, m3);
return 0; if (TestConditionCode(m3)) {
set_register(r1, get_register(r2));
}
return length;
} }
EVALUATE(NGRK) { EVALUATE(NGRK) {
@ -10564,9 +10573,12 @@ EVALUATE(SLGRK) {
} }
EVALUATE(LOCR) { EVALUATE(LOCR) {
UNIMPLEMENTED(); DCHECK_OPCODE(LOCR);
USE(instr); DECODE_RRF_C_INSTRUCTION(r1, r2, m3);
return 0; if (TestConditionCode(m3)) {
set_low_register(r1, get_low_register<int32_t>(r2));
}
return length;
} }
EVALUATE(NRK) { EVALUATE(NRK) {