[riscv64] support 64bit mul high and Int64MulWithOverflow
Port222007bc11
Port78570f7826
Bug: v8:9407 Change-Id: I5de127dad747bd94b7129476acd67cb2ce8af09d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3940601 Auto-Submit: ji qiu <qiuji@iscas.ac.cn> Reviewed-by: Yahan Lu <yahan@iscas.ac.cn> Commit-Queue: ji qiu <qiuji@iscas.ac.cn> Cr-Commit-Position: refs/heads/main@{#83582}
This commit is contained in:
parent
7f0c777d9e
commit
ed6ea9cecb
@ -699,6 +699,18 @@ void TurboAssembler::Mulh64(Register rd, Register rs, const Operand& rt) {
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Mulhu64(Register rd, Register rs, const Operand& rt) {
|
||||
if (rt.is_reg()) {
|
||||
mulhu(rd, rs, rt.rm());
|
||||
} else {
|
||||
// li handles the relocation.
|
||||
UseScratchRegisterScope temps(this);
|
||||
Register scratch = temps.Acquire();
|
||||
Li(scratch, rt.immediate());
|
||||
mulhu(rd, rs, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void TurboAssembler::Div32(Register res, Register rs, const Operand& rt) {
|
||||
if (rt.is_reg()) {
|
||||
divw(res, rs, rt.rm());
|
||||
@ -5200,6 +5212,37 @@ void TurboAssembler::MulOverflow32(Register dst, Register left,
|
||||
sext_w(dst, overflow);
|
||||
xor_(overflow, overflow, dst);
|
||||
}
|
||||
|
||||
void TurboAssembler::MulOverflow64(Register dst, Register left,
|
||||
const Operand& right, Register overflow) {
|
||||
ASM_CODE_COMMENT(this);
|
||||
UseScratchRegisterScope temps(this);
|
||||
BlockTrampolinePoolScope block_trampoline_pool(this);
|
||||
Register right_reg = no_reg;
|
||||
Register scratch = temps.Acquire();
|
||||
Register scratch2 = temps.Acquire();
|
||||
if (!right.is_reg()) {
|
||||
li(scratch, Operand(right));
|
||||
right_reg = scratch;
|
||||
} else {
|
||||
right_reg = right.rm();
|
||||
}
|
||||
|
||||
DCHECK(left != scratch2 && right_reg != scratch2 && dst != scratch2 &&
|
||||
overflow != scratch2);
|
||||
DCHECK(overflow != left && overflow != right_reg);
|
||||
// use this sequence of "mulh/mul" according to recommendation of ISA Spec 7.1
|
||||
// upper part
|
||||
mulh(scratch2, left, right_reg);
|
||||
// lower part
|
||||
mul(dst, left, right_reg);
|
||||
// expand the sign of the lower part to 64bit
|
||||
srai(overflow, dst, 63);
|
||||
// if the upper part is not eqaul to the expanded sign bit of the lower part,
|
||||
// overflow happens
|
||||
xor_(overflow, overflow, scratch2);
|
||||
}
|
||||
|
||||
#elif V8_TARGET_ARCH_RISCV32
|
||||
void TurboAssembler::AddOverflow(Register dst, Register left,
|
||||
const Operand& right, Register overflow) {
|
||||
|
@ -447,6 +447,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
DEFINE_INSTRUCTION(Mulh32)
|
||||
DEFINE_INSTRUCTION(Mul64)
|
||||
DEFINE_INSTRUCTION(Mulh64)
|
||||
DEFINE_INSTRUCTION(Mulhu64)
|
||||
DEFINE_INSTRUCTION2(Div32)
|
||||
DEFINE_INSTRUCTION2(Div64)
|
||||
DEFINE_INSTRUCTION2(Divu32)
|
||||
@ -871,7 +872,9 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
|
||||
// MulOverflow32 sets overflow register to zero if no overflow occured
|
||||
void MulOverflow32(Register dst, Register left, const Operand& right,
|
||||
Register overflow);
|
||||
|
||||
// MulOverflow64 sets overflow register to zero if no overflow occured
|
||||
void MulOverflow64(Register dst, Register left, const Operand& right,
|
||||
Register overflow);
|
||||
// Number of instructions needed for calculation of switch table entry address
|
||||
static const int kSwitchTablePrologueSize = 6;
|
||||
|
||||
|
@ -1036,6 +1036,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Mulh64(i.OutputRegister(), i.InputOrZeroRegister(0),
|
||||
i.InputOperand(1));
|
||||
break;
|
||||
case kRiscvMulHighU64:
|
||||
__ Mulhu64(i.OutputRegister(), i.InputOrZeroRegister(0),
|
||||
i.InputOperand(1));
|
||||
break;
|
||||
case kRiscvMulOvf64:
|
||||
__ MulOverflow64(i.OutputRegister(), i.InputOrZeroRegister(0),
|
||||
i.InputOperand(1), kScratchReg);
|
||||
break;
|
||||
case kRiscvDiv32: {
|
||||
__ Div32(i.OutputRegister(), i.InputOrZeroRegister(0), i.InputOperand(1));
|
||||
// Set ouput to zero if divisor == 0
|
||||
@ -3745,7 +3753,13 @@ void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
|
||||
default:
|
||||
UNSUPPORTED_COND(instr->arch_opcode(), condition);
|
||||
}
|
||||
#if V8_TARGET_ARCH_RISCV64
|
||||
// kRiscvMulOvf64 is only for RISCV64
|
||||
} else if (instr->arch_opcode() == kRiscvMulOvf32 ||
|
||||
instr->arch_opcode() == kRiscvMulOvf64) {
|
||||
#elif V8_TARGET_ARCH_RISCV32
|
||||
} else if (instr->arch_opcode() == kRiscvMulOvf32) {
|
||||
#endif
|
||||
// Overflow occurs if overflow register is not zero
|
||||
switch (condition) {
|
||||
case kOverflow:
|
||||
@ -3755,7 +3769,7 @@ void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
|
||||
__ Branch(tlabel, eq, kScratchReg, Operand(zero_reg));
|
||||
break;
|
||||
default:
|
||||
UNSUPPORTED_COND(kRiscvMulOvf32, condition);
|
||||
UNSUPPORTED_COND(instr->arch_opcode(), condition);
|
||||
}
|
||||
} else if (instr->arch_opcode() == kRiscvCmp) {
|
||||
Condition cc = FlagsConditionToConditionCmp(condition);
|
||||
@ -3908,7 +3922,13 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
|
||||
#endif
|
||||
// Overflow occurs if overflow register is negative
|
||||
__ Slt(result, kScratchReg, zero_reg);
|
||||
#if V8_TARGET_ARCH_RISCV64
|
||||
// kRiscvMulOvf64 is only for RISCV64
|
||||
} else if (instr->arch_opcode() == kRiscvMulOvf32 ||
|
||||
instr->arch_opcode() == kRiscvMulOvf64) {
|
||||
#elif V8_TARGET_ARCH_RISCV32
|
||||
} else if (instr->arch_opcode() == kRiscvMulOvf32) {
|
||||
#endif
|
||||
// Overflow occurs if overflow register is not zero
|
||||
__ Sgtu(result, kScratchReg, zero_reg);
|
||||
} else if (instr->arch_opcode() == kRiscvCmp) {
|
||||
|
@ -18,7 +18,9 @@ namespace compiler {
|
||||
V(RiscvSub64) \
|
||||
V(RiscvSubOvf64) \
|
||||
V(RiscvMulHigh64) \
|
||||
V(RiscvMulHighU64) \
|
||||
V(RiscvMul64) \
|
||||
V(RiscvMulOvf64) \
|
||||
V(RiscvDiv64) \
|
||||
V(RiscvDivU64) \
|
||||
V(RiscvMod64) \
|
||||
|
@ -24,6 +24,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kRiscvCvtSL:
|
||||
case kRiscvCvtSUl:
|
||||
case kRiscvMulHigh64:
|
||||
case kRiscvMulHighU64:
|
||||
case kRiscvAdd64:
|
||||
case kRiscvAddOvf64:
|
||||
case kRiscvClz64:
|
||||
@ -35,6 +36,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
|
||||
case kRiscvMod64:
|
||||
case kRiscvModU64:
|
||||
case kRiscvMul64:
|
||||
case kRiscvMulOvf64:
|
||||
case kRiscvPopcnt64:
|
||||
case kRiscvRor64:
|
||||
case kRiscvSar64:
|
||||
@ -946,6 +948,11 @@ int MulOverflow32Latency() {
|
||||
return Mul32Latency() + Mulh32Latency() + 2;
|
||||
}
|
||||
|
||||
int MulOverflow64Latency() {
|
||||
// Estimated max.
|
||||
return Mul64Latency() + Mulh64Latency() + 2;
|
||||
}
|
||||
|
||||
// TODO(RISCV): This is incorrect for RISC-V.
|
||||
int Clz64Latency() { return 1; }
|
||||
|
||||
@ -1216,6 +1223,8 @@ int InstructionScheduler::GetInstructionLatency(const Instruction* instr) {
|
||||
return Mulh64Latency();
|
||||
case kRiscvMul64:
|
||||
return Mul64Latency();
|
||||
case kRiscvMulOvf64:
|
||||
return MulOverflow64Latency();
|
||||
case kRiscvDiv64: {
|
||||
int latency = Div64Latency();
|
||||
return latency + MovzLatency();
|
||||
|
@ -667,10 +667,18 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) {
|
||||
VisitRRR(this, kRiscvMulHigh32, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitInt64MulHigh(Node* node) {
|
||||
VisitRRR(this, kRiscvMulHigh64, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitUint32MulHigh(Node* node) {
|
||||
VisitRRR(this, kRiscvMulHighU32, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitUint64MulHigh(Node* node) {
|
||||
VisitRRR(this, kRiscvMulHighU64, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitInt64Mul(Node* node) {
|
||||
RiscvOperandGenerator g(this);
|
||||
Int64BinopMatcher m(node);
|
||||
@ -1820,6 +1828,21 @@ void InstructionSelector::VisitInt64SubWithOverflow(Node* node) {
|
||||
VisitBinop(this, node, kRiscvSubOvf64, &cont);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitInt64MulWithOverflow(Node* node) {
|
||||
if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
|
||||
// RISCV64 doesn't set the overflow flag for multiplication, so we need to
|
||||
// test on kNotEqual. Here is the code sequence used:
|
||||
// mulh rdh, left, right
|
||||
// mul rdl, left, right
|
||||
// srai temp, rdl, 63
|
||||
// xor overflow, rdl, temp
|
||||
FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf);
|
||||
return VisitBinop(this, node, kRiscvMulOvf64, &cont);
|
||||
}
|
||||
FlagsContinuation cont;
|
||||
VisitBinop(this, node, kRiscvMulOvf64, &cont);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitWord64Equal(Node* const node) {
|
||||
FlagsContinuation cont = FlagsContinuation::ForSet(kEqual, node);
|
||||
Int64BinopMatcher m(node);
|
||||
|
Loading…
Reference in New Issue
Block a user