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

[turbofan] introduce Int32/64AbsWithOverflow optional operator

some arch like s390 has native instr can benefit from this.
see ~10% improvement on MathAbs on s390

Review-Url: https://codereview.chromium.org/2785773002
Cr-Commit-Position: refs/heads/master@{#44310}
parent 591562c1
......@@ -48,36 +48,45 @@ TF_BUILTIN(MathAbs, CodeStubAssembler) {
Bind(&if_xissmi);
{
// Check if {x} is already positive.
Label if_xispositive(this), if_xisnotpositive(this);
BranchIfSmiLessThanOrEqual(SmiConstant(Smi::FromInt(0)), x,
&if_xispositive, &if_xisnotpositive);
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
Node* pair = NULL;
Bind(&if_xispositive);
{
// Just return the input {x}.
Return(x);
}
Bind(&if_xisnotpositive);
{
// Try to negate the {x} value.
Node* pair =
IntPtrSubWithOverflow(IntPtrConstant(0), BitcastTaggedToWord(x));
// check if support abs function
if (IsIntPtrAbsWithOverflowSupported()) {
pair = IntPtrAbsWithOverflow(x);
Node* overflow = Projection(1, pair);
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
Branch(overflow, &if_overflow, &if_notoverflow);
} else {
// Check if {x} is already positive.
Label if_xispositive(this), if_xisnotpositive(this);
BranchIfSmiLessThanOrEqual(SmiConstant(Smi::FromInt(0)), x,
&if_xispositive, &if_xisnotpositive);
Bind(&if_xispositive);
{
// Just return the input {x}.
Return(x);
}
Bind(&if_notoverflow);
Bind(&if_xisnotpositive);
{
// There is a Smi representation for negated {x}.
Node* result = Projection(0, pair);
Return(BitcastWordToTagged(result));
// Try to negate the {x} value.
pair =
IntPtrSubWithOverflow(IntPtrConstant(0), BitcastTaggedToWord(x));
Node* overflow = Projection(1, pair);
Branch(overflow, &if_overflow, &if_notoverflow);
}
}
Bind(&if_overflow);
{ Return(NumberConstant(0.0 - Smi::kMinValue)); }
Bind(&if_notoverflow);
{
// There is a Smi representation for negated {x}.
Node* result = Projection(0, pair);
Return(BitcastWordToTagged(result));
}
Bind(&if_overflow);
{ Return(NumberConstant(0.0 - Smi::kMinValue)); }
}
Bind(&if_xisnotsmi);
......
......@@ -2483,6 +2483,14 @@ SIMD_BINOP_LIST(SIMD_VISIT_BINOP)
SIMD_FORMAT_LIST(SIMD_VISIT_SELECT_OP)
#undef SIMD_VISIT_SELECT_OP
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -2782,6 +2782,14 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
Emit(code, 1, outputs, input_count, inputs, 2, temp);
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -165,6 +165,19 @@ bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
}
bool CodeAssembler::IsInt32AbsWithOverflowSupported() const {
return raw_assembler()->machine()->Int32AbsWithOverflow().IsSupported();
}
bool CodeAssembler::IsInt64AbsWithOverflowSupported() const {
return raw_assembler()->machine()->Int64AbsWithOverflow().IsSupported();
}
bool CodeAssembler::IsIntPtrAbsWithOverflowSupported() const {
return Is64() ? IsInt64AbsWithOverflowSupported()
: IsInt32AbsWithOverflowSupported();
}
Node* CodeAssembler::Int32Constant(int32_t value) {
return raw_assembler()->Int32Constant(value);
}
......
......@@ -167,6 +167,9 @@ typedef std::function<void()> CodeAssemblerCallback;
V(Float64RoundTruncate) \
V(Word32Clz) \
V(Word32Not) \
V(Int32AbsWithOverflow) \
V(Int64AbsWithOverflow) \
V(IntPtrAbsWithOverflow) \
V(Word32BinaryNot)
// A "public" interface used by components outside of compiler directory to
......@@ -201,6 +204,9 @@ class V8_EXPORT_PRIVATE CodeAssembler {
bool IsFloat64RoundDownSupported() const;
bool IsFloat64RoundTiesEvenSupported() const;
bool IsFloat64RoundTruncateSupported() const;
bool IsInt32AbsWithOverflowSupported() const;
bool IsInt64AbsWithOverflowSupported() const;
bool IsIntPtrAbsWithOverflowSupported() const;
// Shortened aliases for use in CodeAssembler subclasses.
typedef CodeAssemblerLabel Label;
......
......@@ -1838,6 +1838,14 @@ void InstructionSelector::VisitI32x4ReplaceLane(Node* node) {
g.Use(node->InputAt(1)));
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -1126,6 +1126,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord32(node), VisitWord32ReverseBits(node);
case IrOpcode::kWord32ReverseBytes:
return MarkAsWord32(node), VisitWord32ReverseBytes(node);
case IrOpcode::kInt32AbsWithOverflow:
return MarkAsWord32(node), VisitInt32AbsWithOverflow(node);
case IrOpcode::kWord32Popcnt:
return MarkAsWord32(node), VisitWord32Popcnt(node);
case IrOpcode::kWord64Popcnt:
......@@ -1152,6 +1154,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsWord64(node), VisitWord64ReverseBits(node);
case IrOpcode::kWord64ReverseBytes:
return MarkAsWord64(node), VisitWord64ReverseBytes(node);
case IrOpcode::kInt64AbsWithOverflow:
return MarkAsWord64(node), VisitInt64AbsWithOverflow(node);
case IrOpcode::kWord64Equal:
return VisitWord64Equal(node);
case IrOpcode::kInt32Add:
......@@ -2392,6 +2396,8 @@ void InstructionSelector::VisitProjection(Node* node) {
case IrOpcode::kWord32PairShl:
case IrOpcode::kWord32PairShr:
case IrOpcode::kWord32PairSar:
case IrOpcode::kInt32AbsWithOverflow:
case IrOpcode::kInt64AbsWithOverflow:
if (ProjectionIndexOf(node->op()) == 0u) {
Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
} else {
......
......@@ -346,6 +346,8 @@ MachineType AtomicCompareExchangeRepresentationOf(Operator const* op) {
V(Word64ReverseBits, Operator::kNoProperties, 1, 0, 1) \
V(Word32ReverseBytes, Operator::kNoProperties, 1, 0, 1) \
V(Word64ReverseBytes, Operator::kNoProperties, 1, 0, 1) \
V(Int32AbsWithOverflow, Operator::kNoProperties, 1, 0, 1) \
V(Int64AbsWithOverflow, Operator::kNoProperties, 1, 0, 1) \
V(Word32Popcnt, Operator::kNoProperties, 1, 0, 1) \
V(Word64Popcnt, Operator::kNoProperties, 1, 0, 1) \
V(Float32RoundDown, Operator::kNoProperties, 1, 0, 1) \
......
......@@ -131,13 +131,15 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
kWord64ReverseBits = 1u << 17,
kWord32ReverseBytes = 1u << 18,
kWord64ReverseBytes = 1u << 19,
kAllOptionalOps = kFloat32RoundDown | kFloat64RoundDown | kFloat32RoundUp |
kFloat64RoundUp | kFloat32RoundTruncate |
kFloat64RoundTruncate | kFloat64RoundTiesAway |
kFloat32RoundTiesEven | kFloat64RoundTiesEven |
kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt |
kWord32ReverseBits | kWord64ReverseBits |
kWord32ReverseBytes | kWord64ReverseBytes
kInt32AbsWithOverflow = 1u << 20,
kInt64AbsWithOverflow = 1u << 21,
kAllOptionalOps =
kFloat32RoundDown | kFloat64RoundDown | kFloat32RoundUp |
kFloat64RoundUp | kFloat32RoundTruncate | kFloat64RoundTruncate |
kFloat64RoundTiesAway | kFloat32RoundTiesEven | kFloat64RoundTiesEven |
kWord32Ctz | kWord64Ctz | kWord32Popcnt | kWord64Popcnt |
kWord32ReverseBits | kWord64ReverseBits | kWord32ReverseBytes |
kWord64ReverseBytes | kInt32AbsWithOverflow | kInt64AbsWithOverflow
};
typedef base::Flags<Flag, unsigned> Flags;
......@@ -232,6 +234,8 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const OptionalOperator Word64ReverseBits();
const OptionalOperator Word32ReverseBytes();
const OptionalOperator Word64ReverseBytes();
const OptionalOperator Int32AbsWithOverflow();
const OptionalOperator Int64AbsWithOverflow();
bool Word32ShiftIsSafe() const { return flags_ & kWord32ShiftIsSafe; }
const Operator* Word64And();
......
......@@ -1891,6 +1891,14 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -2642,6 +2642,14 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -380,6 +380,7 @@
#define MACHINE_UNOP_32_LIST(V) \
V(Word32Clz) \
V(Word32Ctz) \
V(Int32AbsWithOverflow) \
V(Word32ReverseBits) \
V(Word32ReverseBytes)
......@@ -499,6 +500,7 @@
V(Word64Ctz) \
V(Word64ReverseBits) \
V(Word64ReverseBytes) \
V(Int64AbsWithOverflow) \
V(BitcastTaggedToWord) \
V(BitcastWordToTagged) \
V(BitcastWordToTaggedSigned) \
......
......@@ -2155,6 +2155,14 @@ void InstructionSelector::VisitAtomicCompareExchange(Node* node) {
UNIMPLEMENTED();
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -439,6 +439,19 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
#undef UINTPTR_BINOP
Node* Int32AbsWithOverflow(Node* a) {
return AddNode(machine()->Int32AbsWithOverflow().op(), a);
}
Node* Int64AbsWithOverflow(Node* a) {
return AddNode(machine()->Int64AbsWithOverflow().op(), a);
}
Node* IntPtrAbsWithOverflow(Node* a) {
return kPointerSize == 8 ? Int64AbsWithOverflow(a)
: Int32AbsWithOverflow(a);
}
Node* Float32Add(Node* a, Node* b) {
return AddNode(machine()->Float32Add(), a, b);
}
......
......@@ -309,6 +309,8 @@ Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
case kS390_Add64:
case kS390_Sub32:
case kS390_Sub64:
case kS390_Abs64:
case kS390_Abs32:
return overflow;
default:
break;
......@@ -1347,6 +1349,13 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
Operand(offset.offset()));
break;
}
case kS390_Abs32:
// TODO(john.yan): zero-ext
__ lpr(i.OutputRegister(0), i.InputRegister(0));
break;
case kS390_Abs64:
__ lpgr(i.OutputRegister(0), i.InputRegister(0));
break;
case kS390_And32:
// zero-ext
if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
......@@ -1855,6 +1864,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
if (HasRegisterInput(instr, 1)) {
__ And(r0, i.InputRegister(0), i.InputRegister(1));
} else {
// detect tmlh/tmhl/tmhh case
Operand opnd = i.InputImmediate(1);
if (is_uint16(opnd.immediate())) {
__ tmll(i.InputRegister(0), opnd);
......
......@@ -12,6 +12,8 @@ namespace compiler {
// S390-specific opcodes that specify which assembly sequence to emit.
// Most opcodes specify a single instruction.
#define TARGET_ARCH_OPCODE_LIST(V) \
V(S390_Abs32) \
V(S390_Abs64) \
V(S390_And32) \
V(S390_And64) \
V(S390_Or32) \
......
......@@ -13,6 +13,8 @@ bool InstructionScheduler::SchedulerSupported() { return true; }
int InstructionScheduler::GetTargetInstructionFlags(
const Instruction* instr) const {
switch (instr->arch_opcode()) {
case kS390_Abs32:
case kS390_Abs64:
case kS390_And32:
case kS390_And64:
case kS390_Or32:
......
......@@ -389,6 +389,11 @@ bool ProduceWord32Result(Node* node) {
switch (load_rep.representation()) {
case MachineRepresentation::kWord32:
return true;
case MachineRepresentation::kWord8:
if (load_rep.IsSigned())
return false;
else
return true;
default:
return false;
}
......@@ -515,6 +520,8 @@ void VisitBinOp(InstructionSelector* selector, Node* node,
V(Word32, Unary, [](ArchOpcode opcode) { \
return opcode == kS390_LoadWordS32 || opcode == kS390_LoadWordU32; \
}) \
V(Word64, Unary, \
[](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \
V(Float32, Unary, \
[](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \
V(Float64, Unary, \
......@@ -529,8 +536,6 @@ void VisitBinOp(InstructionSelector* selector, Node* node,
#if V8_TARGET_ARCH_S390X
#define VISIT_OP_LIST(V) \
VISIT_OP_LIST_32(V) \
V(Word64, Unary, \
[](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \
V(Word64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; })
#else
#define VISIT_OP_LIST VISIT_OP_LIST_32
......@@ -1242,6 +1247,14 @@ void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); }
void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); }
#endif
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
VisitWord32UnaryOp(this, node, kS390_Abs32, OperandMode::kNone);
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
VisitWord64UnaryOp(this, node, kS390_Abs64, OperandMode::kNone);
}
void InstructionSelector::VisitWord64ReverseBytes(Node* node) {
S390OperandGenerator g(this);
Emit(kS390_LoadReverse64RR, g.DefineAsRegister(node),
......@@ -2037,7 +2050,15 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
selector, node, kS390_Mul32WithOverflow,
OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps,
cont);
case IrOpcode::kInt32AbsWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitWord32UnaryOp(selector, node, kS390_Abs32,
OperandMode::kNone, cont);
#if V8_TARGET_ARCH_S390X
case IrOpcode::kInt64AbsWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitWord64UnaryOp(selector, node, kS390_Abs64,
OperandMode::kNone, cont);
case IrOpcode::kInt64AddWithOverflow:
cont->OverwriteAndNegateIfEqual(kOverflow);
return VisitWord64BinOp(selector, node, kS390_Add64,
......@@ -2450,6 +2471,8 @@ InstructionSelector::SupportedMachineOperatorFlags() {
MachineOperatorBuilder::kWord32Popcnt |
MachineOperatorBuilder::kWord32ReverseBytes |
MachineOperatorBuilder::kWord64ReverseBytes |
MachineOperatorBuilder::kInt32AbsWithOverflow |
MachineOperatorBuilder::kInt64AbsWithOverflow |
MachineOperatorBuilder::kWord64Popcnt;
}
......
......@@ -1270,6 +1270,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kWord32Ctz:
case IrOpcode::kWord32ReverseBits:
case IrOpcode::kWord32ReverseBytes:
case IrOpcode::kInt32AbsWithOverflow:
case IrOpcode::kWord32Popcnt:
case IrOpcode::kWord64And:
case IrOpcode::kWord64Or:
......@@ -1283,6 +1284,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kWord64Ctz:
case IrOpcode::kWord64ReverseBits:
case IrOpcode::kWord64ReverseBytes:
case IrOpcode::kInt64AbsWithOverflow:
case IrOpcode::kWord64Equal:
case IrOpcode::kInt32Add:
case IrOpcode::kInt32AddWithOverflow:
......
......@@ -2469,6 +2469,14 @@ void InstructionSelector::VisitS32x4Select(Node* node) {
g.UseRegister(node->InputAt(2)));
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -1833,6 +1833,14 @@ void InstructionSelector::VisitAtomicStore(Node* node) {
Emit(code, 0, nullptr, input_count, inputs);
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
void InstructionSelector::VisitInt64AbsWithOverflow(Node* node) {
UNREACHABLE();
}
// static
MachineOperatorBuilder::Flags
InstructionSelector::SupportedMachineOperatorFlags() {
......
......@@ -1067,10 +1067,10 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
break;
}
case LPGR:
Format(instr, "lpgr\t'r1, 'r2");
Format(instr, "lpgr\t'r5,'r6");
break;
case LPGFR:
Format(instr, "lpgfr\t'r1,'r2");
Format(instr, "lpgfr\t'r5,'r6");
break;
default:
return false;
......
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