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:
parent
0d9ce3acff
commit
dc88458120
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user