Commit b10f21c6 authored by Ivica Bogosavljevic's avatar Ivica Bogosavljevic Committed by Commit Bot

MIPS[64]: Branch poisoning using conditional moves

Change-Id: I41c3945d72116dd501bf34bafd8d21c205aed17c
Reviewed-on: https://chromium-review.googlesource.com/973445Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarSreten Kovacevic <sreten.kovacevic@mips.com>
Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
Cr-Commit-Position: refs/heads/master@{#52248}
parent 39fcb540
......@@ -1166,7 +1166,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Ror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break;
case kMipsTst:
// Pseudo-instruction used for tst/branch. No opcode emitted here.
__ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
break;
case kMipsCmp:
// Pseudo-instruction used for cmp/branch. No opcode emitted here.
......@@ -2886,8 +2886,7 @@ void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
MipsOperandConverter i(gen, instr);
if (instr->arch_opcode() == kMipsTst) {
cc = FlagsConditionToConditionTst(condition);
__ And(at, i.InputRegister(0), i.InputOperand(1));
__ Branch(tlabel, cc, at, Operand(zero_reg));
__ Branch(tlabel, cc, kScratchReg, Operand(zero_reg));
} else if (instr->arch_opcode() == kMipsAddOvf ||
instr->arch_opcode() == kMipsSubOvf) {
// Overflow occurs if overflow register is negative
......@@ -2965,9 +2964,65 @@ void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition,
return;
}
// TODO(mips): insert instructions here that place 0 into the
// kSpeculationPoisonRegister if the negation of the condition is
// true.
MipsOperandConverter i(this, instr);
condition = NegateFlagsCondition(condition);
switch (instr->arch_opcode()) {
case kMipsCmp: {
__ LoadZeroOnCondition(kSpeculationPoisonRegister, i.InputRegister(0),
i.InputOperand(1),
FlagsConditionToConditionCmp(condition));
}
return;
case kMipsTst: {
switch (condition) {
case kEqual:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
break;
case kNotEqual:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
kScratchReg);
break;
default:
UNREACHABLE();
}
}
return;
case kMipsAddOvf:
case kMipsSubOvf: {
// Overflow occurs if overflow register is negative
__ Slt(kScratchReg2, kScratchReg, zero_reg);
switch (condition) {
case kOverflow:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
kScratchReg2);
break;
case kNotOverflow:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2);
break;
default:
UNSUPPORTED_COND(instr->arch_opcode(), condition);
}
}
return;
case kMipsMulOvf: {
// Overflow occurs if overflow register is not zero
switch (condition) {
case kOverflow:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
kScratchReg);
break;
case kNotOverflow:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
break;
default:
UNSUPPORTED_COND(instr->arch_opcode(), condition);
}
}
return;
default:
break;
}
}
void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
......@@ -3064,21 +3119,10 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
if (instr->arch_opcode() == kMipsTst) {
cc = FlagsConditionToConditionTst(condition);
if (instr->InputAt(1)->IsImmediate() &&
base::bits::IsPowerOfTwo(i.InputOperand(1).immediate())) {
uint16_t pos =
base::bits::CountTrailingZeros32(i.InputOperand(1).immediate());
__ Ext(result, i.InputRegister(0), pos, 1);
if (cc == eq) {
__ xori(result, result, 1);
}
if (cc == eq) {
__ Sltu(result, kScratchReg, 1);
} else {
__ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
if (cc == eq) {
__ Sltu(result, kScratchReg, 1);
} else {
__ Sltu(result, zero_reg, kScratchReg);
}
__ Sltu(result, zero_reg, kScratchReg);
}
return;
} else if (instr->arch_opcode() == kMipsAddOvf ||
......
......@@ -1315,6 +1315,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Dror(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break;
case kMips64Tst:
__ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
// Pseudo-instruction used for cmp/branch. No opcode emitted here.
break;
case kMips64Cmp:
......@@ -3103,8 +3104,7 @@ void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
if (instr->arch_opcode() == kMips64Tst) {
cc = FlagsConditionToConditionTst(condition);
__ And(at, i.InputRegister(0), i.InputOperand(1));
__ Branch(tlabel, cc, at, Operand(zero_reg));
__ Branch(tlabel, cc, kScratchReg, Operand(zero_reg));
} else if (instr->arch_opcode() == kMips64Dadd ||
instr->arch_opcode() == kMips64Dsub) {
cc = FlagsConditionToConditionOvf(condition);
......@@ -3189,9 +3189,83 @@ void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition,
return;
}
// TODO(mips64): insert instructions here that place 0 into the
// kSpeculationPoisonRegister if the negation of the condition is
// true.
MipsOperandConverter i(this, instr);
condition = NegateFlagsCondition(condition);
switch (instr->arch_opcode()) {
case kMips64Cmp: {
__ LoadZeroOnCondition(kSpeculationPoisonRegister, i.InputRegister(0),
i.InputOperand(1),
FlagsConditionToConditionCmp(condition));
}
return;
case kMips64Tst: {
switch (condition) {
case kEqual:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
break;
case kNotEqual:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
kScratchReg);
break;
default:
UNREACHABLE();
}
}
return;
case kMips64Dadd:
case kMips64Dsub: {
// Check for overflow creates 1 or 0 for result.
__ dsrl32(kScratchReg, i.OutputRegister(), 31);
__ srl(at, i.OutputRegister(), 31);
__ xor_(at, kScratchReg, at);
switch (condition) {
case kOverflow:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister, at);
break;
case kNotOverflow:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, at);
break;
default:
UNSUPPORTED_COND(instr->arch_opcode(), condition);
}
}
return;
case kMips64DaddOvf:
case kMips64DsubOvf: {
// Overflow occurs if overflow register is negative
__ Slt(kScratchReg2, kScratchReg, zero_reg);
switch (condition) {
case kOverflow:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
kScratchReg2);
break;
case kNotOverflow:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg2);
break;
default:
UNSUPPORTED_COND(instr->arch_opcode(), condition);
}
}
return;
case kMips64MulOvf: {
// Overflow occurs if overflow register is not zero
switch (condition) {
case kOverflow:
__ LoadZeroIfConditionNotZero(kSpeculationPoisonRegister,
kScratchReg);
break;
case kNotOverflow:
__ LoadZeroIfConditionZero(kSpeculationPoisonRegister, kScratchReg);
break;
default:
UNSUPPORTED_COND(instr->arch_opcode(), condition);
}
}
return;
default:
break;
}
}
void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
......@@ -3286,21 +3360,10 @@ void CodeGenerator::AssembleArchBoolean(Instruction* instr,
if (instr->arch_opcode() == kMips64Tst) {
cc = FlagsConditionToConditionTst(condition);
if (instr->InputAt(1)->IsImmediate() &&
base::bits::IsPowerOfTwo(i.InputOperand(1).immediate())) {
uint16_t pos =
base::bits::CountTrailingZeros64(i.InputOperand(1).immediate());
__ Dext(result, i.InputRegister(0), pos, 1);
if (cc == eq) {
__ xori(result, result, 1);
}
if (cc == eq) {
__ Sltu(result, kScratchReg, 1);
} else {
__ And(kScratchReg, i.InputRegister(0), i.InputOperand(1));
if (cc == eq) {
__ Sltu(result, kScratchReg, 1);
} else {
__ Sltu(result, zero_reg, kScratchReg);
}
__ Sltu(result, zero_reg, kScratchReg);
}
return;
} else if (instr->arch_opcode() == kMips64Dadd ||
......
......@@ -38,6 +38,14 @@ TurboAssembler::TurboAssembler(Isolate* isolate, void* buffer, int buffer_size,
}
}
static inline bool IsZero(const Operand& rt) {
if (rt.is_reg()) {
return rt.rm() == zero_reg;
} else {
return rt.immediate() == 0;
}
}
int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
Register exclusion1,
Register exclusion2,
......@@ -821,6 +829,44 @@ void TurboAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
}
}
void TurboAssembler::Sle(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
slt(rd, rt.rm(), rs);
} else {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
li(scratch, rt);
slt(rd, scratch, rs);
}
xori(rd, rd, 1);
}
void TurboAssembler::Sleu(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
sltu(rd, rt.rm(), rs);
} else {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
li(scratch, rt);
sltu(rd, scratch, rs);
}
xori(rd, rd, 1);
}
void TurboAssembler::Sge(Register rd, Register rs, const Operand& rt) {
Slt(rd, rs, rt);
xori(rd, rd, 1);
}
void TurboAssembler::Sgeu(Register rd, Register rs, const Operand& rt) {
Sltu(rd, rs, rt);
xori(rd, rd, 1);
}
void TurboAssembler::Sgt(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
slt(rd, rt.rm(), rs);
......@@ -2250,6 +2296,115 @@ void TurboAssembler::Move(FPURegister dst, uint64_t src) {
}
}
void TurboAssembler::LoadZeroOnCondition(Register rd, Register rs,
const Operand& rt, Condition cond) {
switch (cond) {
case cc_always:
mov(rd, zero_reg);
break;
case eq:
if (rs == zero_reg) {
if (rt.is_reg()) {
LoadZeroIfConditionZero(rd, rt.rm());
} else {
if (rt.immediate() == 0) {
mov(rd, zero_reg);
} else {
nop();
}
}
} else if (IsZero(rt)) {
LoadZeroIfConditionZero(rd, rs);
} else {
Subu(t9, rs, rt);
LoadZeroIfConditionZero(rd, t9);
}
break;
case ne:
if (rs == zero_reg) {
if (rt.is_reg()) {
LoadZeroIfConditionNotZero(rd, rt.rm());
} else {
if (rt.immediate() != 0) {
mov(rd, zero_reg);
} else {
nop();
}
}
} else if (IsZero(rt)) {
LoadZeroIfConditionNotZero(rd, rs);
} else {
Subu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
}
break;
// Signed comparison.
case greater:
Sgt(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
break;
case greater_equal:
Sge(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs >= rt
break;
case less:
Slt(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs < rt
break;
case less_equal:
Sle(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs <= rt
break;
// Unsigned comparison.
case Ugreater:
Sgtu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs > rt
break;
case Ugreater_equal:
Sgeu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs >= rt
break;
case Uless:
Sltu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs < rt
break;
case Uless_equal:
Sleu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs <= rt
break;
default:
UNREACHABLE();
}
}
void TurboAssembler::LoadZeroIfConditionNotZero(Register dest,
Register condition) {
if (IsMipsArchVariant(kMips32r6)) {
seleqz(dest, dest, condition);
} else {
Movn(dest, zero_reg, condition);
}
}
void TurboAssembler::LoadZeroIfConditionZero(Register dest,
Register condition) {
if (IsMipsArchVariant(kMips32r6)) {
selnez(dest, dest, condition);
} else {
Movz(dest, zero_reg, condition);
}
}
void TurboAssembler::Movz(Register rd, Register rs, Register rt) {
if (IsMipsArchVariant(kLoongson) || IsMipsArchVariant(kMips32r6)) {
Label done;
......@@ -2638,14 +2793,6 @@ void TurboAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) {
}
static inline bool IsZero(const Operand& rt) {
if (rt.is_reg()) {
return rt.rm() == zero_reg;
} else {
return rt.immediate() == 0;
}
}
int32_t TurboAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) {
if (L) {
offset = branch_offset_helper(L, bits) >> 2;
......
......@@ -461,8 +461,12 @@ class TurboAssembler : public Assembler {
DEFINE_INSTRUCTION(Slt);
DEFINE_INSTRUCTION(Sltu);
DEFINE_INSTRUCTION(Sle);
DEFINE_INSTRUCTION(Sleu);
DEFINE_INSTRUCTION(Sgt);
DEFINE_INSTRUCTION(Sgtu);
DEFINE_INSTRUCTION(Sge);
DEFINE_INSTRUCTION(Sgeu);
// MIPS32 R2 instruction macro.
DEFINE_INSTRUCTION(Ror);
......@@ -563,6 +567,11 @@ class TurboAssembler : public Assembler {
void Movt(Register rd, Register rs, uint16_t cc = 0);
void Movf(Register rd, Register rs, uint16_t cc = 0);
void LoadZeroIfConditionNotZero(Register dest, Register condition);
void LoadZeroIfConditionZero(Register dest, Register condition);
void LoadZeroOnCondition(Register rd, Register rs, const Operand& rt,
Condition cond);
void Clz(Register rd, Register rs);
void Ctz(Register rd, Register rs);
void Popcnt(Register rd, Register rs);
......
......@@ -38,6 +38,14 @@ TurboAssembler::TurboAssembler(Isolate* isolate, void* buffer, int buffer_size,
}
}
static inline bool IsZero(const Operand& rt) {
if (rt.is_reg()) {
return rt.rm() == zero_reg;
} else {
return rt.immediate() == 0;
}
}
int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
Register exclusion1,
Register exclusion2,
......@@ -959,6 +967,44 @@ void TurboAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
}
}
void TurboAssembler::Sle(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
slt(rd, rt.rm(), rs);
} else {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
li(scratch, rt);
slt(rd, scratch, rs);
}
xori(rd, rd, 1);
}
void TurboAssembler::Sleu(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
sltu(rd, rt.rm(), rs);
} else {
// li handles the relocation.
UseScratchRegisterScope temps(this);
Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
DCHECK(rs != scratch);
li(scratch, rt);
sltu(rd, scratch, rs);
}
xori(rd, rd, 1);
}
void TurboAssembler::Sge(Register rd, Register rs, const Operand& rt) {
Slt(rd, rs, rt);
xori(rd, rd, 1);
}
void TurboAssembler::Sgeu(Register rd, Register rs, const Operand& rt) {
Sltu(rd, rs, rt);
xori(rd, rd, 1);
}
void TurboAssembler::Sgt(Register rd, Register rs, const Operand& rt) {
if (rt.is_reg()) {
slt(rd, rt.rm(), rs);
......@@ -2792,6 +2838,115 @@ void TurboAssembler::Movn(Register rd, Register rs, Register rt) {
}
}
void TurboAssembler::LoadZeroOnCondition(Register rd, Register rs,
const Operand& rt, Condition cond) {
switch (cond) {
case cc_always:
mov(rd, zero_reg);
break;
case eq:
if (rs == zero_reg) {
if (rt.is_reg()) {
LoadZeroIfConditionZero(rd, rt.rm());
} else {
if (rt.immediate() == 0) {
mov(rd, zero_reg);
} else {
nop();
}
}
} else if (IsZero(rt)) {
LoadZeroIfConditionZero(rd, rs);
} else {
Dsubu(t9, rs, rt);
LoadZeroIfConditionZero(rd, t9);
}
break;
case ne:
if (rs == zero_reg) {
if (rt.is_reg()) {
LoadZeroIfConditionNotZero(rd, rt.rm());
} else {
if (rt.immediate() != 0) {
mov(rd, zero_reg);
} else {
nop();
}
}
} else if (IsZero(rt)) {
LoadZeroIfConditionNotZero(rd, rs);
} else {
Dsubu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
}
break;
// Signed comparison.
case greater:
Sgt(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
break;
case greater_equal:
Sge(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs >= rt
break;
case less:
Slt(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs < rt
break;
case less_equal:
Sle(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs <= rt
break;
// Unsigned comparison.
case Ugreater:
Sgtu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs > rt
break;
case Ugreater_equal:
Sgeu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs >= rt
break;
case Uless:
Sltu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs < rt
break;
case Uless_equal:
Sleu(t9, rs, rt);
LoadZeroIfConditionNotZero(rd, t9);
// rs <= rt
break;
default:
UNREACHABLE();
}
}
void TurboAssembler::LoadZeroIfConditionNotZero(Register dest,
Register condition) {
if (kArchVariant == kMips64r6) {
seleqz(dest, dest, condition);
} else {
Movn(dest, zero_reg, condition);
}
}
void TurboAssembler::LoadZeroIfConditionZero(Register dest,
Register condition) {
if (kArchVariant == kMips64r6) {
selnez(dest, dest, condition);
} else {
Movz(dest, zero_reg, condition);
}
}
void TurboAssembler::Movt(Register rd, Register rs, uint16_t cc) {
movt(rd, rs, cc);
}
......@@ -3149,14 +3304,6 @@ void TurboAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) {
}
static inline bool IsZero(const Operand& rt) {
if (rt.is_reg()) {
return rt.rm() == zero_reg;
} else {
return rt.immediate() == 0;
}
}
int32_t TurboAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) {
if (L) {
offset = branch_offset_helper(L, bits) >> 2;
......
......@@ -495,8 +495,12 @@ class TurboAssembler : public Assembler {
DEFINE_INSTRUCTION(Slt);
DEFINE_INSTRUCTION(Sltu);
DEFINE_INSTRUCTION(Sle);
DEFINE_INSTRUCTION(Sleu);
DEFINE_INSTRUCTION(Sgt);
DEFINE_INSTRUCTION(Sgtu);
DEFINE_INSTRUCTION(Sge);
DEFINE_INSTRUCTION(Sgeu);
// MIPS32 R2 instruction macro.
DEFINE_INSTRUCTION(Ror);
......@@ -605,6 +609,11 @@ class TurboAssembler : public Assembler {
void Movt(Register rd, Register rs, uint16_t cc = 0);
void Movf(Register rd, Register rs, uint16_t cc = 0);
void LoadZeroIfConditionNotZero(Register dest, Register condition);
void LoadZeroIfConditionZero(Register dest, Register condition);
void LoadZeroOnCondition(Register rd, Register rs, const Operand& rt,
Condition cond);
void Clz(Register rd, Register rs);
void Ctz(Register rd, Register rs);
void Dctz(Register rd, Register rs);
......
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