Commit 37e9437e authored by jyan's avatar jyan Committed by Commit bot

s390: optimize for compares

1. use ltr/ltgr when possible
2. combine compares with possible load

R=joransiu@ca.ibm.com, bjaideep@ca.ibm.com

Review-Url: https://codereview.chromium.org/2696343002
Cr-Commit-Position: refs/heads/master@{#43265}
parent 50e26939
...@@ -131,10 +131,18 @@ class S390OperandConverter final : public InstructionOperandConverter { ...@@ -131,10 +131,18 @@ class S390OperandConverter final : public InstructionOperandConverter {
} }
}; };
static inline bool HasRegisterOutput(Instruction* instr, int index = 0) {
return instr->OutputCount() > 0 && instr->OutputAt(index)->IsRegister();
}
static inline bool HasRegisterInput(Instruction* instr, int index) { static inline bool HasRegisterInput(Instruction* instr, int index) {
return instr->InputAt(index)->IsRegister(); return instr->InputAt(index)->IsRegister();
} }
static inline bool HasFPRegisterInput(Instruction* instr, int index) {
return instr->InputAt(index)->IsFPRegister();
}
static inline bool HasImmediateInput(Instruction* instr, size_t index) { static inline bool HasImmediateInput(Instruction* instr, size_t index) {
return instr->InputAt(index)->IsImmediate(); return instr->InputAt(index)->IsImmediate();
} }
...@@ -143,6 +151,10 @@ static inline bool HasStackSlotInput(Instruction* instr, size_t index) { ...@@ -143,6 +151,10 @@ static inline bool HasStackSlotInput(Instruction* instr, size_t index) {
return instr->InputAt(index)->IsStackSlot(); return instr->InputAt(index)->IsStackSlot();
} }
static inline bool HasFPStackSlotInput(Instruction* instr, size_t index) {
return instr->InputAt(index)->IsFPStackSlot();
}
namespace { namespace {
class OutOfLineLoadNAN32 final : public OutOfLineCode { class OutOfLineLoadNAN32 final : public OutOfLineCode {
...@@ -260,17 +272,33 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) { ...@@ -260,17 +272,33 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
return eq; return eq;
case kNotEqual: case kNotEqual:
return ne; return ne;
case kSignedLessThan:
case kUnsignedLessThan: case kUnsignedLessThan:
// unsigned number never less than 0
if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
return CC_NOP;
// fall through
case kSignedLessThan:
return lt; return lt;
case kSignedGreaterThanOrEqual:
case kUnsignedGreaterThanOrEqual: case kUnsignedGreaterThanOrEqual:
// unsigned number always greater than or equal 0
if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
return CC_ALWAYS;
// fall through
case kSignedGreaterThanOrEqual:
return ge; return ge;
case kSignedLessThanOrEqual:
case kUnsignedLessThanOrEqual: case kUnsignedLessThanOrEqual:
// unsigned number never less than 0
if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
return CC_EQ;
// fall through
case kSignedLessThanOrEqual:
return le; return le;
case kSignedGreaterThan:
case kUnsignedGreaterThan: case kUnsignedGreaterThan:
// unsigned number always greater than or equal 0
if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
return ne;
// fall through
case kSignedGreaterThan:
return gt; return gt;
case kOverflow: case kOverflow:
// Overflow checked for AddP/SubP only. // Overflow checked for AddP/SubP only.
...@@ -498,24 +526,89 @@ void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm, ...@@ -498,24 +526,89 @@ void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
#define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \ #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \
do { \ do { \
if (HasRegisterInput(instr, 1)) { \ AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
if (mode != kMode_None) { \
size_t first_index = 1; \
MemOperand operand = i.MemoryOperand(&mode, &first_index); \
if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), operand); \
} else { \
__ cmp_instr(i.InputRegister(0), operand); \
} \
} else if (HasRegisterInput(instr, 1)) { \
if (i.CompareLogical()) { \ if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), i.InputRegister(1)); \ __ cmpl_instr(i.InputRegister(0), i.InputRegister(1)); \
} else { \ } else { \
__ cmp_instr(i.InputRegister(0), i.InputRegister(1)); \ __ cmp_instr(i.InputRegister(0), i.InputRegister(1)); \
} \ } \
} else if (HasImmediateInput(instr, 1)) { \
if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), i.InputImmediate(1)); \
} else { \
__ cmp_instr(i.InputRegister(0), i.InputImmediate(1)); \
} \
} else { \
DCHECK(HasStackSlotInput(instr, 1)); \
if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), i.InputStackSlot(1)); \
} else { \
__ cmp_instr(i.InputRegister(0), i.InputStackSlot(1)); \
} \
} \
} while (0)
#define ASSEMBLE_COMPARE32(cmp_instr, cmpl_instr) \
do { \
AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
if (mode != kMode_None) { \
size_t first_index = 1; \
MemOperand operand = i.MemoryOperand(&mode, &first_index); \
if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), operand); \
} else { \
__ cmp_instr(i.InputRegister(0), operand); \
} \
} else if (HasRegisterInput(instr, 1)) { \
if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), i.InputRegister(1)); \
} else { \ } else { \
__ cmp_instr(i.InputRegister(0), i.InputRegister(1)); \
} \
} else if (HasImmediateInput(instr, 1)) { \
if (i.CompareLogical()) { \ if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), i.InputImmediate(1)); \ __ cmpl_instr(i.InputRegister(0), i.InputImmediate(1)); \
} else { \ } else { \
__ cmp_instr(i.InputRegister(0), i.InputImmediate(1)); \ __ cmp_instr(i.InputRegister(0), i.InputImmediate(1)); \
} \ } \
} else { \
DCHECK(HasStackSlotInput(instr, 1)); \
if (i.CompareLogical()) { \
__ cmpl_instr(i.InputRegister(0), i.InputStackSlot32(1)); \
} else { \
__ cmp_instr(i.InputRegister(0), i.InputStackSlot32(1)); \
} \
} \ } \
} while (0) } while (0)
#define ASSEMBLE_FLOAT_COMPARE(cmp_instr) \ #define ASSEMBLE_FLOAT_COMPARE(cmp_rr_instr, cmp_rm_instr, load_instr) \
do { \ do { \
__ cmp_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \ AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
if (mode != kMode_None) { \
size_t first_index = 1; \
MemOperand operand = i.MemoryOperand(&mode, &first_index); \
__ cmp_rm_instr(i.InputDoubleRegister(0), operand); \
} else if (HasFPRegisterInput(instr, 1)) { \
__ cmp_rr_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
} else { \
DCHECK(HasFPStackSlotInput(instr, 1)); \
MemOperand operand = i.InputStackSlot(1); \
if (operand.offset() >= 0) { \
__ cmp_rm_instr(i.InputDoubleRegister(0), operand); \
} else { \
__ load_instr(kScratchDoubleReg, operand); \
__ cmp_rr_instr(i.InputDoubleRegister(0), kScratchDoubleReg); \
} \
} \
} while (0) } while (0)
// Divide instruction dr will implicity use register pair // Divide instruction dr will implicity use register pair
...@@ -747,6 +840,7 @@ void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm, ...@@ -747,6 +840,7 @@ void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
} \ } \
__ bind(&done); \ __ bind(&done); \
} while (0) } while (0)
//
// Only MRI mode for these instructions available // Only MRI mode for these instructions available
#define ASSEMBLE_LOAD_FLOAT(asm_instr) \ #define ASSEMBLE_LOAD_FLOAT(asm_instr) \
do { \ do { \
...@@ -764,6 +858,38 @@ void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm, ...@@ -764,6 +858,38 @@ void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
__ asm_instr(result, operand); \ __ asm_instr(result, operand); \
} while (0) } while (0)
#define ASSEMBLE_LOADANDTEST64(asm_instr_rr, asm_instr_rm) \
{ \
AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
Register dst = HasRegisterOutput(instr) ? i.OutputRegister() : r0; \
if (mode != kMode_None) { \
size_t first_index = 0; \
MemOperand operand = i.MemoryOperand(&mode, &first_index); \
__ asm_instr_rm(dst, operand); \
} else if (HasRegisterInput(instr, 0)) { \
__ asm_instr_rr(dst, i.InputRegister(0)); \
} else { \
DCHECK(HasStackSlotInput(instr, 0)); \
__ asm_instr_rm(dst, i.InputStackSlot(0)); \
} \
}
#define ASSEMBLE_LOADANDTEST32(asm_instr_rr, asm_instr_rm) \
{ \
AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
Register dst = HasRegisterOutput(instr) ? i.OutputRegister() : r0; \
if (mode != kMode_None) { \
size_t first_index = 0; \
MemOperand operand = i.MemoryOperand(&mode, &first_index); \
__ asm_instr_rm(dst, operand); \
} else if (HasRegisterInput(instr, 0)) { \
__ asm_instr_rr(dst, i.InputRegister(0)); \
} else { \
DCHECK(HasStackSlotInput(instr, 0)); \
__ asm_instr_rm(dst, i.InputStackSlot32(0)); \
} \
}
#define ASSEMBLE_STORE_FLOAT32() \ #define ASSEMBLE_STORE_FLOAT32() \
do { \ do { \
size_t index = 0; \ size_t index = 0; \
...@@ -1776,7 +1902,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -1776,7 +1902,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break; break;
#endif #endif
case kS390_Cmp32: case kS390_Cmp32:
ASSEMBLE_COMPARE(Cmp32, CmpLogical32); ASSEMBLE_COMPARE32(Cmp32, CmpLogical32);
break; break;
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
case kS390_Cmp64: case kS390_Cmp64:
...@@ -1784,15 +1910,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -1784,15 +1910,16 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break; break;
#endif #endif
case kS390_CmpFloat: case kS390_CmpFloat:
__ cebr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); ASSEMBLE_FLOAT_COMPARE(cebr, ceb, ley);
// __ cebr(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
break; break;
case kS390_CmpDouble: case kS390_CmpDouble:
__ cdbr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); ASSEMBLE_FLOAT_COMPARE(cdbr, cdb, ldy);
// __ cdbr(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
break; break;
case kS390_Tst32: case kS390_Tst32:
if (HasRegisterInput(instr, 1)) { if (HasRegisterInput(instr, 1)) {
__ lr(r0, i.InputRegister(0)); __ And(r0, i.InputRegister(0), i.InputRegister(1));
__ nr(r0, i.InputRegister(1));
} else { } else {
Operand opnd = i.InputImmediate(1); Operand opnd = i.InputImmediate(1);
if (is_uint16(opnd.immediate())) { if (is_uint16(opnd.immediate())) {
...@@ -2107,6 +2234,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -2107,6 +2234,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
ASSEMBLE_LOAD_INTEGER(lg); ASSEMBLE_LOAD_INTEGER(lg);
break; break;
#endif #endif
case kS390_LoadAndTestWord32: {
ASSEMBLE_LOADANDTEST32(ltr, lt_z);
break;
}
case kS390_LoadAndTestWord64: {
ASSEMBLE_LOADANDTEST64(ltgr, ltg);
break;
}
case kS390_LoadFloat32: case kS390_LoadFloat32:
ASSEMBLE_LOAD_FLOAT(LoadFloat32); ASSEMBLE_LOAD_FLOAT(LoadFloat32);
break; break;
......
...@@ -135,6 +135,10 @@ namespace compiler { ...@@ -135,6 +135,10 @@ namespace compiler {
V(S390_LoadWordU16) \ V(S390_LoadWordU16) \
V(S390_LoadWordS32) \ V(S390_LoadWordS32) \
V(S390_LoadWordU32) \ V(S390_LoadWordU32) \
V(S390_LoadAndTestWord32) \
V(S390_LoadAndTestWord64) \
V(S390_LoadAndTestFloat32) \
V(S390_LoadAndTestFloat64) \
V(S390_LoadReverse16RR) \ V(S390_LoadReverse16RR) \
V(S390_LoadReverse32RR) \ V(S390_LoadReverse32RR) \
V(S390_LoadReverse64RR) \ V(S390_LoadReverse64RR) \
......
...@@ -130,6 +130,10 @@ int InstructionScheduler::GetTargetInstructionFlags( ...@@ -130,6 +130,10 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kS390_LoadReverse16RR: case kS390_LoadReverse16RR:
case kS390_LoadReverse32RR: case kS390_LoadReverse32RR:
case kS390_LoadReverse64RR: case kS390_LoadReverse64RR:
case kS390_LoadAndTestWord32:
case kS390_LoadAndTestWord64:
case kS390_LoadAndTestFloat32:
case kS390_LoadAndTestFloat64:
return kNoOpcodeFlags; return kNoOpcodeFlags;
case kS390_LoadWordS8: case kS390_LoadWordS8:
......
...@@ -21,6 +21,7 @@ enum class OperandMode : uint32_t { ...@@ -21,6 +21,7 @@ enum class OperandMode : uint32_t {
kInt32Imm_Negate = 1u << 3, kInt32Imm_Negate = 1u << 3,
kUint32Imm = 1u << 4, kUint32Imm = 1u << 4,
kInt20Imm = 1u << 5, kInt20Imm = 1u << 5,
kUint12Imm = 1u << 6,
// Instr format // Instr format
kAllowRRR = 1u << 7, kAllowRRR = 1u << 7,
kAllowRM = 1u << 8, kAllowRM = 1u << 8,
...@@ -83,6 +84,13 @@ class S390OperandGenerator final : public OperandGenerator { ...@@ -83,6 +84,13 @@ class S390OperandGenerator final : public OperandGenerator {
return UseRegister(node); return UseRegister(node);
} }
InstructionOperand UseAnyExceptImmediate(Node* node) {
if (NodeProperties::IsConstant(node))
return UseRegister(node);
else
return Use(node);
}
int64_t GetImmediate(Node* node) { int64_t GetImmediate(Node* node) {
if (node->opcode() == IrOpcode::kInt32Constant) if (node->opcode() == IrOpcode::kInt32Constant)
return OpParameter<int32_t>(node); return OpParameter<int32_t>(node);
...@@ -117,10 +125,38 @@ class S390OperandGenerator final : public OperandGenerator { ...@@ -117,10 +125,38 @@ class S390OperandGenerator final : public OperandGenerator {
return is_uint32(value); return is_uint32(value);
else if (mode & OperandMode::kInt20Imm) else if (mode & OperandMode::kInt20Imm)
return is_int20(value); return is_int20(value);
else if (mode & OperandMode::kUint12Imm)
return is_uint12(value);
else else
return false; return false;
} }
bool CanBeMemoryOperand(InstructionCode opcode, Node* user, Node* input,
int effect_level) {
if (input->opcode() != IrOpcode::kLoad ||
!selector()->CanCover(user, input)) {
return false;
}
if (effect_level != selector()->GetEffectLevel(input)) {
return false;
}
MachineRepresentation rep =
LoadRepresentationOf(input->op()).representation();
switch (opcode) {
case kS390_Cmp64:
case kS390_LoadAndTestWord64:
return rep == MachineRepresentation::kWord64 || IsAnyTagged(rep);
case kS390_LoadAndTestWord32:
case kS390_Cmp32:
return rep == MachineRepresentation::kWord32;
default:
break;
}
return false;
}
AddressingMode GenerateMemoryOperandInputs(Node* index, Node* base, AddressingMode GenerateMemoryOperandInputs(Node* index, Node* base,
Node* displacement, Node* displacement,
DisplacementMode displacement_mode, DisplacementMode displacement_mode,
...@@ -164,9 +200,9 @@ class S390OperandGenerator final : public OperandGenerator { ...@@ -164,9 +200,9 @@ class S390OperandGenerator final : public OperandGenerator {
return mode; return mode;
} }
AddressingMode GetEffectiveAddressMemoryOperand(Node* operand, AddressingMode GetEffectiveAddressMemoryOperand(
InstructionOperand inputs[], Node* operand, InstructionOperand inputs[], size_t* input_count,
size_t* input_count) { OperandModes immediate_mode = OperandMode::kInt20Imm) {
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
BaseWithIndexAndDisplacement64Matcher m(operand, BaseWithIndexAndDisplacement64Matcher m(operand,
AddressOption::kAllowInputSwap); AddressOption::kAllowInputSwap);
...@@ -176,7 +212,7 @@ class S390OperandGenerator final : public OperandGenerator { ...@@ -176,7 +212,7 @@ class S390OperandGenerator final : public OperandGenerator {
#endif #endif
DCHECK(m.matches()); DCHECK(m.matches());
if ((m.displacement() == nullptr || if ((m.displacement() == nullptr ||
CanBeImmediate(m.displacement(), OperandMode::kInt20Imm))) { CanBeImmediate(m.displacement(), immediate_mode))) {
DCHECK(m.scale() == 0); DCHECK(m.scale() == 0);
return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(), return GenerateMemoryOperandInputs(m.index(), m.base(), m.displacement(),
m.displacement_mode(), inputs, m.displacement_mode(), inputs,
...@@ -203,6 +239,25 @@ class S390OperandGenerator final : public OperandGenerator { ...@@ -203,6 +239,25 @@ class S390OperandGenerator final : public OperandGenerator {
namespace { namespace {
bool S390OpcodeOnlySupport12BitDisp(ArchOpcode opcode) {
switch (opcode) {
case kS390_CmpFloat:
case kS390_CmpDouble:
return true;
default:
return false;
}
}
bool S390OpcodeOnlySupport12BitDisp(InstructionCode op) {
ArchOpcode opcode = ArchOpcodeField::decode(op);
return S390OpcodeOnlySupport12BitDisp(opcode);
}
#define OpcodeImmMode(op) \
(S390OpcodeOnlySupport12BitDisp(op) ? OperandMode::kUint12Imm \
: OperandMode::kInt20Imm)
ArchOpcode SelectLoadOpcode(Node* node) { ArchOpcode SelectLoadOpcode(Node* node) {
NodeMatcher m(node); NodeMatcher m(node);
DCHECK(m.IsLoad()); DCHECK(m.IsLoad());
...@@ -1741,25 +1796,87 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode, ...@@ -1741,25 +1796,87 @@ void VisitCompare(InstructionSelector* selector, InstructionCode opcode,
} }
} }
void VisitWordCompareZero(InstructionSelector* selector, Node* user,
Node* value, InstructionCode opcode,
FlagsContinuation* cont);
void VisitLoadAndTest(InstructionSelector* selector, InstructionCode opcode,
Node* node, Node* value, FlagsContinuation* cont,
bool discard_output = false);
// Shared routine for multiple word compare operations. // Shared routine for multiple word compare operations.
void VisitWordCompare(InstructionSelector* selector, Node* node, void VisitWordCompare(InstructionSelector* selector, Node* node,
InstructionCode opcode, FlagsContinuation* cont, InstructionCode opcode, FlagsContinuation* cont,
bool commutative, OperandModes immediate_mode) { OperandModes immediate_mode) {
S390OperandGenerator g(selector); S390OperandGenerator g(selector);
Node* left = node->InputAt(0); Node* left = node->InputAt(0);
Node* right = node->InputAt(1); Node* right = node->InputAt(1);
// Match immediates on left or right side of comparison. DCHECK(IrOpcode::IsComparisonOpcode(node->opcode()) ||
if (g.CanBeImmediate(right, immediate_mode)) { node->opcode() == IrOpcode::kInt32Sub ||
VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), node->opcode() == IrOpcode::kInt64Sub);
cont);
} else if (g.CanBeImmediate(left, immediate_mode)) { InstructionOperand inputs[8];
if (!commutative) cont->Commute(); InstructionOperand outputs[1];
VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), size_t input_count = 0;
cont); size_t output_count = 0;
// If one of the two inputs is an immediate, make sure it's on the right, or
// if one of the two inputs is a memory operand, make sure it's on the left.
int effect_level = selector->GetEffectLevel(node);
if (cont->IsBranch()) {
effect_level = selector->GetEffectLevel(
cont->true_block()->PredecessorAt(0)->control_input());
}
if ((!g.CanBeImmediate(right, immediate_mode) &&
g.CanBeImmediate(left, immediate_mode)) ||
(!g.CanBeMemoryOperand(opcode, node, right, effect_level) &&
g.CanBeMemoryOperand(opcode, node, left, effect_level))) {
if (!node->op()->HasProperty(Operator::kCommutative)) cont->Commute();
std::swap(left, right);
}
// check if compare with 0
if (g.CanBeImmediate(right, immediate_mode) && g.GetImmediate(right) == 0) {
DCHECK(opcode == kS390_Cmp32 || opcode == kS390_Cmp64);
ArchOpcode load_and_test = (opcode == kS390_Cmp32)
? kS390_LoadAndTestWord32
: kS390_LoadAndTestWord64;
return VisitLoadAndTest(selector, load_and_test, node, left, cont, true);
}
inputs[input_count++] = g.UseRegister(left);
if (g.CanBeMemoryOperand(opcode, node, right, effect_level)) {
// generate memory operand
AddressingMode addressing_mode = g.GetEffectiveAddressMemoryOperand(
right, inputs, &input_count, OpcodeImmMode(opcode));
opcode |= AddressingModeField::encode(addressing_mode);
} else if (g.CanBeImmediate(right, immediate_mode)) {
inputs[input_count++] = g.UseImmediate(right);
} else { } else {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseRegister(right), inputs[input_count++] = g.UseAnyExceptImmediate(right);
cont); }
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
} else if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.UseImmediate(cont->trap_id());
} else {
DCHECK(cont->IsDeoptimize());
// nothing to do
}
DCHECK(input_count <= 8 && output_count <= 1);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, 0, nullptr, input_count, inputs,
cont->reason(), cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
} }
} }
...@@ -1767,7 +1884,7 @@ void VisitWord32Compare(InstructionSelector* selector, Node* node, ...@@ -1767,7 +1884,7 @@ void VisitWord32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
OperandModes mode = OperandModes mode =
(CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm); (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm);
VisitWordCompare(selector, node, kS390_Cmp32, cont, false, mode); VisitWordCompare(selector, node, kS390_Cmp32, cont, mode);
} }
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
...@@ -1775,28 +1892,97 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node, ...@@ -1775,28 +1892,97 @@ void VisitWord64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
OperandModes mode = OperandModes mode =
(CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm); (CompareLogical(cont) ? OperandMode::kUint32Imm : OperandMode::kInt32Imm);
VisitWordCompare(selector, node, kS390_Cmp64, cont, false, mode); VisitWordCompare(selector, node, kS390_Cmp64, cont, mode);
} }
#endif #endif
// Shared routine for multiple float32 compare operations. // Shared routine for multiple float32 compare operations.
void VisitFloat32Compare(InstructionSelector* selector, Node* node, void VisitFloat32Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
S390OperandGenerator g(selector); VisitWordCompare(selector, node, kS390_CmpFloat, cont, OperandMode::kNone);
Node* left = node->InputAt(0);
Node* right = node->InputAt(1);
VisitCompare(selector, kS390_CmpFloat, g.UseRegister(left),
g.UseRegister(right), cont);
} }
// Shared routine for multiple float64 compare operations. // Shared routine for multiple float64 compare operations.
void VisitFloat64Compare(InstructionSelector* selector, Node* node, void VisitFloat64Compare(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
VisitWordCompare(selector, node, kS390_CmpDouble, cont, OperandMode::kNone);
}
void VisitTestUnderMask(InstructionSelector* selector, Node* node,
FlagsContinuation* cont) {
DCHECK(node->opcode() == IrOpcode::kWord32And ||
node->opcode() == IrOpcode::kWord64And);
ArchOpcode opcode =
(node->opcode() == IrOpcode::kWord32And) ? kS390_Tst32 : kS390_Tst64;
S390OperandGenerator g(selector); S390OperandGenerator g(selector);
Node* left = node->InputAt(0); Node* left = node->InputAt(0);
Node* right = node->InputAt(1); Node* right = node->InputAt(1);
VisitCompare(selector, kS390_CmpDouble, g.UseRegister(left), if (!g.CanBeImmediate(right, OperandMode::kUint32Imm) &&
g.UseRegister(right), cont); g.CanBeImmediate(left, OperandMode::kUint32Imm)) {
std::swap(left, right);
}
VisitCompare(selector, opcode, g.UseRegister(left),
g.UseOperand(right, OperandMode::kUint32Imm), cont);
}
void VisitLoadAndTest(InstructionSelector* selector, InstructionCode opcode,
Node* node, Node* value, FlagsContinuation* cont,
bool discard_output) {
static_assert(kS390_LoadAndTestFloat64 - kS390_LoadAndTestWord32 == 3,
"LoadAndTest Opcode shouldn't contain other opcodes.");
// TODO(john.yan): Add support for Float32/Float64.
DCHECK(opcode >= kS390_LoadAndTestWord32 ||
opcode <= kS390_LoadAndTestWord64);
S390OperandGenerator g(selector);
InstructionOperand inputs[8];
InstructionOperand outputs[2];
size_t input_count = 0;
size_t output_count = 0;
bool use_value = false;
int effect_level = selector->GetEffectLevel(node);
if (cont->IsBranch()) {
effect_level = selector->GetEffectLevel(
cont->true_block()->PredecessorAt(0)->control_input());
}
if (g.CanBeMemoryOperand(opcode, node, value, effect_level)) {
// generate memory operand
AddressingMode addressing_mode =
g.GetEffectiveAddressMemoryOperand(value, inputs, &input_count);
opcode |= AddressingModeField::encode(addressing_mode);
} else {
inputs[input_count++] = g.UseAnyExceptImmediate(value);
use_value = true;
}
if (!discard_output && !use_value) {
outputs[output_count++] = g.DefineAsRegister(value);
}
opcode = cont->Encode(opcode);
if (cont->IsBranch()) {
inputs[input_count++] = g.Label(cont->true_block());
inputs[input_count++] = g.Label(cont->false_block());
} else if (cont->IsSet()) {
outputs[output_count++] = g.DefineAsRegister(cont->result());
} else if (cont->IsTrap()) {
inputs[input_count++] = g.UseImmediate(cont->trap_id());
} else {
DCHECK(cont->IsDeoptimize());
// nothing to do
}
DCHECK(input_count <= 8 && output_count <= 2);
opcode = cont->Encode(opcode);
if (cont->IsDeoptimize()) {
selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs,
cont->reason(), cont->frame_state());
} else {
selector->Emit(opcode, output_count, outputs, input_count, inputs);
}
} }
// Shared routine for word comparisons against zero. // Shared routine for word comparisons against zero.
...@@ -1814,6 +2000,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1814,6 +2000,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
cont->Negate(); cont->Negate();
} }
FlagsCondition fc = cont->condition();
if (selector->CanCover(user, value)) { if (selector->CanCover(user, value)) {
switch (value->opcode()) { switch (value->opcode()) {
case IrOpcode::kWord32Equal: { case IrOpcode::kWord32Equal: {
...@@ -1828,8 +2015,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1828,8 +2015,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kInt32Sub: case IrOpcode::kInt32Sub:
return VisitWord32Compare(selector, value, cont); return VisitWord32Compare(selector, value, cont);
case IrOpcode::kWord32And: case IrOpcode::kWord32And:
return VisitWordCompare(selector, value, kS390_Tst64, cont, return VisitTestUnderMask(selector, value, cont);
true, OperandMode::kUint32Imm);
default: default:
break; break;
} }
...@@ -1862,8 +2048,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1862,8 +2048,7 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
case IrOpcode::kInt64Sub: case IrOpcode::kInt64Sub:
return VisitWord64Compare(selector, value, cont); return VisitWord64Compare(selector, value, cont);
case IrOpcode::kWord64And: case IrOpcode::kWord64And:
return VisitWordCompare(selector, value, kS390_Tst64, cont, return VisitTestUnderMask(selector, value, cont);
true, OperandMode::kUint32Imm);
default: default:
break; break;
} }
...@@ -1947,53 +2132,77 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user, ...@@ -1947,53 +2132,77 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
} }
break; break;
case IrOpcode::kInt32Sub: case IrOpcode::kInt32Sub:
if (fc == kNotEqual || fc == kEqual)
return VisitWord32Compare(selector, value, cont); return VisitWord32Compare(selector, value, cont);
break;
case IrOpcode::kWord32And: case IrOpcode::kWord32And:
return VisitWordCompare(selector, value, kS390_Tst32, cont, true, return VisitTestUnderMask(selector, value, cont);
OperandMode::kUint32Imm); case IrOpcode::kLoad: {
// TODO(mbrandy): Handle? LoadRepresentation load_rep = LoadRepresentationOf(value->op());
// case IrOpcode::kInt32Add: switch (load_rep.representation()) {
// case IrOpcode::kWord32Or: case MachineRepresentation::kWord32:
// case IrOpcode::kWord32Xor: if (opcode == kS390_LoadAndTestWord32) {
// case IrOpcode::kWord32Sar: return VisitLoadAndTest(selector, opcode, user, value, cont);
// case IrOpcode::kWord32Shl: }
// case IrOpcode::kWord32Shr: default:
// case IrOpcode::kWord32Ror: break;
}
break;
}
case IrOpcode::kInt32Add:
// can't handle overflow case.
break;
case IrOpcode::kWord32Or:
return VisitBin32op(selector, value, kS390_Or32, OrOperandMode, cont);
case IrOpcode::kWord32Xor:
return VisitBin32op(selector, value, kS390_Xor32, XorOperandMode, cont);
case IrOpcode::kWord32Sar:
case IrOpcode::kWord32Shl:
case IrOpcode::kWord32Shr:
case IrOpcode::kWord32Ror:
// doesn't generate cc, so ignore.
break;
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
case IrOpcode::kInt64Sub: case IrOpcode::kInt64Sub:
if (fc == kNotEqual || fc == kEqual)
return VisitWord64Compare(selector, value, cont); return VisitWord64Compare(selector, value, cont);
break;
case IrOpcode::kWord64And: case IrOpcode::kWord64And:
return VisitWordCompare(selector, value, kS390_Tst64, cont, true, return VisitTestUnderMask(selector, value, cont);
OperandMode::kUint32Imm); case IrOpcode::kInt64Add:
// TODO(mbrandy): Handle? // can't handle overflow case.
// case IrOpcode::kInt64Add: break;
// case IrOpcode::kWord64Or: case IrOpcode::kWord64Or:
// case IrOpcode::kWord64Xor: // TODO(john.yan): need to handle
// case IrOpcode::kWord64Sar: break;
// case IrOpcode::kWord64Shl: case IrOpcode::kWord64Xor:
// case IrOpcode::kWord64Shr: // TODO(john.yan): need to handle
// case IrOpcode::kWord64Ror: break;
case IrOpcode::kWord64Sar:
case IrOpcode::kWord64Shl:
case IrOpcode::kWord64Shr:
case IrOpcode::kWord64Ror:
// doesn't generate cc, so ignore
break;
#endif #endif
default: default:
break; break;
} }
} }
// Branch could not be combined with a compare, emit compare against 0. // Branch could not be combined with a compare, emit LoadAndTest
S390OperandGenerator g(selector); VisitLoadAndTest(selector, opcode, user, value, cont, true);
VisitCompare(selector, opcode, g.UseRegister(value), g.TempImmediate(0),
cont);
} }
void VisitWord32CompareZero(InstructionSelector* selector, Node* user, void VisitWord32CompareZero(InstructionSelector* selector, Node* user,
Node* value, FlagsContinuation* cont) { Node* value, FlagsContinuation* cont) {
VisitWordCompareZero(selector, user, value, kS390_Cmp32, cont); VisitWordCompareZero(selector, user, value, kS390_LoadAndTestWord32, cont);
} }
#if V8_TARGET_ARCH_S390X #if V8_TARGET_ARCH_S390X
void VisitWord64CompareZero(InstructionSelector* selector, Node* user, void VisitWord64CompareZero(InstructionSelector* selector, Node* user,
Node* value, FlagsContinuation* cont) { Node* value, FlagsContinuation* cont) {
VisitWordCompareZero(selector, user, value, kS390_Cmp64, cont); VisitWordCompareZero(selector, user, value, kS390_LoadAndTestWord64, cont);
} }
#endif #endif
......
...@@ -1250,7 +1250,6 @@ void Assembler::rrfe_form(Opcode op, Condition m3, Condition m4, Register r1, ...@@ -1250,7 +1250,6 @@ void Assembler::rrfe_form(Opcode op, Condition m3, Condition m4, Register r1,
// end of S390 Instruction generation // end of S390 Instruction generation
// start of S390 instruction // start of S390 instruction
RXE_FORM_EMIT(ceb, CEB)
SS1_FORM_EMIT(ed, ED) SS1_FORM_EMIT(ed, ED)
SS1_FORM_EMIT(mvn, MVN) SS1_FORM_EMIT(mvn, MVN)
SS1_FORM_EMIT(nc, NC) SS1_FORM_EMIT(nc, NC)
...@@ -1863,6 +1862,16 @@ void Assembler::sdb(DoubleRegister r1, const MemOperand& opnd) { ...@@ -1863,6 +1862,16 @@ void Assembler::sdb(DoubleRegister r1, const MemOperand& opnd) {
opnd.offset()); opnd.offset());
} }
void Assembler::ceb(DoubleRegister r1, const MemOperand& opnd) {
rxe_form(CEB, Register::from_code(r1.code()), opnd.rx(), opnd.rb(),
opnd.offset());
}
void Assembler::cdb(DoubleRegister r1, const MemOperand& opnd) {
rxe_form(CDB, Register::from_code(r1.code()), opnd.rx(), opnd.rb(),
opnd.offset());
}
// Square Root (LB) // Square Root (LB)
void Assembler::sqdb(DoubleRegister r1, const MemOperand& opnd) { void Assembler::sqdb(DoubleRegister r1, const MemOperand& opnd) {
rxe_form(SQDB, Register::from_code(r1.code()), opnd.rx(), opnd.rb(), rxe_form(SQDB, Register::from_code(r1.code()), opnd.rx(), opnd.rb(),
......
...@@ -1006,8 +1006,6 @@ class Assembler : public AssemblerBase { ...@@ -1006,8 +1006,6 @@ class Assembler : public AssemblerBase {
} }
// S390 instruction sets // S390 instruction sets
RXE_FORM(cdb);
RXE_FORM(ceb);
RXE_FORM(ddb); RXE_FORM(ddb);
SS1_FORM(ed); SS1_FORM(ed);
RRF2_FORM(fidbr); RRF2_FORM(fidbr);
...@@ -1200,6 +1198,7 @@ class Assembler : public AssemblerBase { ...@@ -1200,6 +1198,7 @@ class Assembler : public AssemblerBase {
// Floating Point Compare Instructions // Floating Point Compare Instructions
void cdb(DoubleRegister r1, const MemOperand& opnd); void cdb(DoubleRegister r1, const MemOperand& opnd);
void ceb(DoubleRegister r1, const MemOperand& opnd);
// Floating Point Arithmetic Instructions // Floating Point Arithmetic Instructions
void adb(DoubleRegister r1, const MemOperand& opnd); void adb(DoubleRegister r1, const MemOperand& opnd);
......
...@@ -1434,7 +1434,13 @@ bool Decoder::DecodeSixByte(Instruction* instr) { ...@@ -1434,7 +1434,13 @@ bool Decoder::DecodeSixByte(Instruction* instr) {
Format(instr, "stdy\t'f1,'d2('r2d,'r3)"); Format(instr, "stdy\t'f1,'d2('r2d,'r3)");
break; break;
case ADB: case ADB:
Format(instr, "adb\t'r1,'d1('r2d, 'r3)"); Format(instr, "adb\t'f1,'d1('r2d, 'r3)");
break;
case CDB:
Format(instr, "cdb\t'f1,'d1('r2d, 'r3)");
break;
case CEB:
Format(instr, "ceb\t'f1,'d1('r2d, 'r3)");
break; break;
case SDB: case SDB:
Format(instr, "sdb\t'r1,'d1('r2d, 'r3)"); Format(instr, "sdb\t'r1,'d1('r2d, 'r3)");
......
...@@ -3307,7 +3307,10 @@ void MacroAssembler::MulHighU32(Register dst, Register src1, ...@@ -3307,7 +3307,10 @@ void MacroAssembler::MulHighU32(Register dst, Register src1,
void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1, void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
const MemOperand& src2) { const MemOperand& src2) {
Register result = dst;
if (src2.rx().is(dst) || src2.rb().is(dst)) dst = r0;
Generate_Mul32WithOverflowIfCCUnequal(msgf); Generate_Mul32WithOverflowIfCCUnequal(msgf);
if (!result.is(dst)) llgfr(result, dst);
} }
void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1, void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
......
...@@ -1850,6 +1850,11 @@ double Simulator::ReadDouble(intptr_t addr) { ...@@ -1850,6 +1850,11 @@ double Simulator::ReadDouble(intptr_t addr) {
return *ptr; return *ptr;
} }
float Simulator::ReadFloat(intptr_t addr) {
float* ptr = reinterpret_cast<float*>(addr);
return *ptr;
}
// Returns the limit of the stack area to enable checking for stack overflows. // Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
// The simulator uses a separate JS stack. If we have exhausted the C stack, // The simulator uses a separate JS stack. If we have exhausted the C stack,
...@@ -12542,9 +12547,16 @@ EVALUATE(KEB) { ...@@ -12542,9 +12547,16 @@ EVALUATE(KEB) {
} }
EVALUATE(CEB) { EVALUATE(CEB) {
UNIMPLEMENTED(); DCHECK_OPCODE(CEB);
USE(instr);
return 0; DECODE_RXE_INSTRUCTION(r1, b2, x2, d2);
int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
intptr_t d2_val = d2;
float r1_val = get_float32_from_d_register(r1);
float fval = ReadFloat(b2_val + x2_val + d2_val);
SetS390ConditionCode<float>(r1_val, fval);
return length;
} }
EVALUATE(AEB) { EVALUATE(AEB) {
......
...@@ -304,6 +304,7 @@ class Simulator { ...@@ -304,6 +304,7 @@ class Simulator {
inline int64_t ReadDW(intptr_t addr); inline int64_t ReadDW(intptr_t addr);
inline double ReadDouble(intptr_t addr); inline double ReadDouble(intptr_t addr);
inline float ReadFloat(intptr_t addr);
inline void WriteDW(intptr_t addr, int64_t value); inline void WriteDW(intptr_t addr, int64_t value);
// S390 // S390
......
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