Commit f0da6bc4 authored by Vasili Skurydzin's avatar Vasili Skurydzin Committed by Commit Bot

s390: Optimize branches by brxh/brxhg

Change-Id: Icb92a52112f5e709c3cdbc6f1a5555674633cb89
Reviewed-on: https://chromium-review.googlesource.com/1093554
Commit-Queue: Junliang Yan <jyan@ca.ibm.com>
Reviewed-by: 's avatarJoran Siu <joransiu@ca.ibm.com>
Reviewed-by: 's avatarJunliang Yan <jyan@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#53771}
parent cf00d6f0
......@@ -469,24 +469,24 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ ShiftLeftP(r5, r5, Operand(kPointerSizeLog2));
__ SubP(sp, r5);
// r1 = stack offset
// ip = stack offset
// r5 = parameter array offset
__ LoadImmP(r1, Operand::Zero());
__ LoadImmP(ip, Operand::Zero());
__ SubP(r5, Operand(kPointerSize));
__ blt(&done_loop);
__ lgfi(r1, Operand(-kPointerSize));
__ bind(&loop);
// parameter copy loop
__ LoadP(r0, FieldMemOperand(r4, r5, FixedArray::kHeaderSize));
__ StoreP(r0, MemOperand(sp, r1));
__ StoreP(r0, MemOperand(sp, ip));
// update offsets
__ lay(r1, MemOperand(r1, kPointerSize));
// TODO(john-yan): combine SubP/bge with brxh/brxhg
__ SubP(r5, Operand(kPointerSize));
__ lay(ip, MemOperand(ip, kPointerSize));
__ bge(&loop);
__ BranchRelativeOnIdxHighP(r5, r1, &loop);
__ bind(&done_loop);
}
......@@ -495,7 +495,7 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
if (FLAG_debug_code) {
__ LoadP(r5, FieldMemOperand(r6, JSFunction::kSharedFunctionInfoOffset));
__ LoadP(r5, FieldMemOperand(r5, SharedFunctionInfo::kFunctionDataOffset));
GetSharedFunctionInfoBytecode(masm, r5, r1);
GetSharedFunctionInfoBytecode(masm, r5, ip);
__ CompareObjectType(r5, r5, r5, BYTECODE_ARRAY_TYPE);
__ Assert(eq, AbortReason::kMissingBytecodeArray);
}
......
......@@ -421,9 +421,9 @@ int Assembler::target_at(int pos) {
// check which type of branch this is 16 or 26 bit offset
Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
if (BRC == opcode || BRCT == opcode || BRCTG == opcode) {
if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
imm16 <<= 1; // BRC immediate is in # of halfwords
imm16 <<= 1; // immediate is in # of halfwords
if (imm16 == 0) return kEndOfChain;
return pos + imm16;
} else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
......@@ -434,6 +434,13 @@ int Assembler::target_at(int pos) {
imm32 <<= 1; // BR* + LARL treat immediate in # of halfwords
if (imm32 == 0) return kEndOfChain;
return pos + imm32;
} else if (BRXHG == opcode) {
// offset is in bits 16-31 of 48 bit instruction
instr = instr >> 16;
int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
imm16 <<= 1; // immediate is in # of halfwords
if (imm16 == 0) return kEndOfChain;
return pos + imm16;
}
// Unknown condition
......@@ -448,10 +455,11 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
if (is_branch != nullptr) {
*is_branch = (opcode == BRC || opcode == BRCT || opcode == BRCTG ||
opcode == BRCL || opcode == BRASL);
opcode == BRCL || opcode == BRASL || opcode == BRXH ||
opcode == BRXHG);
}
if (BRC == opcode || BRCT == opcode || BRCTG == opcode) {
if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
int16_t imm16 = target_pos - pos;
instr &= (~0xFFFF);
DCHECK(is_int16(imm16));
......@@ -471,6 +479,15 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
instr_at_put<SixByteInstr>(pos, instr | imm32);
return;
} else if (BRXHG == opcode) {
// Immediate is in bits 16-31 of 48 bit instruction
int32_t imm16 = target_pos - pos;
instr &= (0xFFFF0000FFFF); // clear bits 16-31
imm16 &= 0xFFFF; // clear high halfword
imm16 <<= 16;
// Immediate is in # of halfwords
instr_at_put<SixByteInstr>(pos, instr | (imm16 >> 1));
return;
}
DCHECK(false);
}
......@@ -478,10 +495,10 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
// Returns the maximum number of bits given instruction can address.
int Assembler::max_reach_from(int pos) {
Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
// Check which type of instr. In theory, we can return
// the values below + 1, given offset is # of halfwords
if (BRC == opcode || BRCT == opcode || BRCTG == opcode) {
if (BRC == opcode || BRCT == opcode || BRCTG == opcode|| BRXH == opcode ||
BRXHG == opcode) {
return 16;
} else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
BRASL == opcode) {
......
......@@ -1198,6 +1198,25 @@ inline void rie_d_format(Opcode opcode, int f1, int f2, int f3, int f4) {
#undef DECLARE_S390_RIE_D_INSTRUCTIONS
inline void rie_e_format(Opcode opcode, int f1, int f2, int f3) {
uint32_t op1 = opcode >> 8;
uint32_t op2 = opcode & 0xff;
uint64_t code = getfield<uint64_t, 6, 0, 8>(op1) |
getfield<uint64_t, 6, 8, 12>(f1) |
getfield<uint64_t, 6, 12, 16>(f2) |
getfield<uint64_t, 6, 16, 32>(f3) |
getfield<uint64_t, 6, 40, 48>(op2);
emit6bytes(code);
}
#define DECLARE_S390_RIE_E_INSTRUCTIONS(name, op_name, op_value) \
void name(Register r1, Register r3, const Operand& i2) { \
rie_e_format(op_name, r1.code(), r3.code(), i2.immediate()); \
}
S390_RIE_E_OPCODE_LIST(DECLARE_S390_RIE_E_INSTRUCTIONS)
#undef DECLARE_S390_RIE_E_INSTRUCTIONS
inline void rie_f_format(Opcode opcode, int f1, int f2, int f3, int f4,
int f5) {
uint32_t op1 = opcode >> 8;
......@@ -1303,6 +1322,19 @@ inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
void bunordered(Register r) { b(unordered, r); }
void bordered(Register r) { b(ordered, r); }
// wrappers around asm instr
void brxh(Register dst, Register inc, Label* L) {
int offset_halfwords = branch_offset(L) / 2;
CHECK(is_int16(offset_halfwords));
brxh(dst, inc, Operand(offset_halfwords));
}
void brxhg(Register dst, Register inc, Label* L) {
int offset_halfwords = branch_offset(L) / 2;
CHECK(is_int16(offset_halfwords));
brxhg(dst, inc, Operand(offset_halfwords));
}
// ---------------------------------------------------------------------------
// Code generation
......
......@@ -2231,6 +2231,17 @@ class RSInstruction : Instruction {
inline int size() const { return 4; }
};
// RSI Instruction
class RSIInstruction : Instruction {
public:
inline int R1Value() const { return Bits<FourByteInstr, int>(23, 20); }
inline int R3Value() const { return Bits<FourByteInstr, int>(19, 16); }
inline int I2Value() const {
return static_cast<int32_t>(Bits<FourByteInstr, int16_t>(15, 0));
}
inline int size() const { return 4; }
};
// RSY Instruction
class RSYInstruction : Instruction {
public:
......
......@@ -1069,6 +1069,9 @@ bool Decoder::DecodeFourByte(Instruction* instr) {
case LPGFR:
Format(instr, "lpgfr\t'r5,'r6");
break;
case BRXH:
Format(instr, "brxh\t'r1,'r2,'i4");
break;
default:
return false;
}
......@@ -1481,6 +1484,9 @@ bool Decoder::DecodeSixByte(Instruction* instr) {
case PFD:
Format(instr, "pfd\t'm1,'d2('r2d,'r3)");
break;
case BRXHG:
Format(instr, "brxhg\t'r1,'r2,'i4");
break;
default:
return false;
}
......
......@@ -415,6 +415,15 @@ void TurboAssembler::RotateInsertSelectBits(Register dst, Register src,
risbg(dst, src, startBit, endBit, shiftAmt);
}
void TurboAssembler::BranchRelativeOnIdxHighP(Register dst, Register inc,
Label* L) {
#if V8_TARGET_ARCH_S390X
brxhg(dst, inc, L);
#else
brxh(dst, inc, L);
#endif // V8_TARGET_ARCH_S390X
}
void TurboAssembler::MultiPush(RegList regs, Register location) {
int16_t num_to_push = base::bits::CountPopulation(regs);
int16_t stack_offset = num_to_push * kPointerSize;
......
......@@ -244,6 +244,8 @@ class TurboAssembler : public TurboAssemblerBase {
const Operand& startBit, const Operand& endBit,
const Operand& shiftAmt, bool zeroBits);
void BranchRelativeOnIdxHighP(Register dst, Register inc, Label* L);
void SaveRegisters(RegList registers);
void RestoreRegisters(RegList registers);
......
......@@ -2680,6 +2680,12 @@ uintptr_t Simulator::PopAddress() {
int d2 = AS(RSInstruction)->D2Value(); \
int length = 4;
#define DECODE_RSI_INSTRUCTION(r1, r3, i2) \
int r1 = AS(RSIInstruction)->R1Value(); \
int r3 = AS(RSIInstruction)->R3Value(); \
int32_t i2 = AS(RSIInstruction)->I2Value(); \
int length = 4;
#define DECODE_SI_INSTRUCTION_I_UINT8(b1, d1_val, imm_val) \
int b1 = AS(SIInstruction)->B1Value(); \
intptr_t d1_val = AS(SIInstruction)->D1Value(); \
......@@ -2749,6 +2755,12 @@ uintptr_t Simulator::PopAddress() {
int32_t i2 = AS(RIEInstruction)->I6Value(); \
int length = 6;
#define DECODE_RIE_E_INSTRUCTION(r1, r2, i2) \
int r1 = AS(RIEInstruction)->R1Value(); \
int r2 = AS(RIEInstruction)->R2Value(); \
int32_t i2 = AS(RIEInstruction)->I6Value(); \
int length = 6;
#define DECODE_RIE_F_INSTRUCTION(r1, r2, i3, i4, i5) \
int r1 = AS(RIEInstruction)->R1Value(); \
int r2 = AS(RIEInstruction)->R2Value(); \
......@@ -3866,9 +3878,19 @@ EVALUATE(LE) {
}
EVALUATE(BRXH) {
UNIMPLEMENTED();
USE(instr);
return 0;
DCHECK_OPCODE(BRXH);
DECODE_RSI_INSTRUCTION(r1, r3, i2);
int32_t r1_val = (r1 == 0) ? 0 : get_low_register<int32_t>(r1);
int32_t r3_val = (r3 == 0) ? 0 : get_low_register<int32_t>(r3);
intptr_t branch_address = get_pc() + (2 * i2);
r1_val += r3_val;
int32_t compare_val = r3 % 2 == 0 ?
get_low_register<int32_t>(r3 + 1) : r3_val;
if (r1_val > compare_val) {
set_pc(branch_address);
}
set_low_register(r1, r1_val);
return length;
}
EVALUATE(BRXLE) {
......@@ -9212,7 +9234,7 @@ EVALUATE(LAN) {
EVALUATE(LAO) {
DCHECK_OPCODE(LAO);
ATOMIC_LOAD_AND_UPDATE_WORD32(__atomic_fetch_or);
ATOMIC_LOAD_AND_UPDATE_WORD32(__atomic_fetch_or);
return length;
}
......@@ -9237,9 +9259,18 @@ EVALUATE(LAAL) {
#undef ATOMIC_LOAD_AND_UPDATE_WORD32
EVALUATE(BRXHG) {
UNIMPLEMENTED();
USE(instr);
return 0;
DCHECK_OPCODE(BRXHG);
DECODE_RIE_E_INSTRUCTION(r1, r3, i2);
int64_t r1_val = (r1 == 0) ? 0 : get_register(r1);
int64_t r3_val = (r3 == 0) ? 0 : get_register(r3);
intptr_t branch_address = get_pc() + (2 * i2);
r1_val += r3_val;
int64_t compare_val = r3 % 2 == 0 ? get_register(r3 + 1) : r3_val;
if (r1_val > compare_val) {
set_pc(branch_address);
}
set_register(r1, r1_val);
return length;
}
EVALUATE(BRXLG) {
......
......@@ -496,6 +496,129 @@ TEST(10) {
CHECK_EQ(0, static_cast<int>(res));
}
// brxh
TEST(11) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, nullptr, 0);
Label ok, failed, continue1, continue2;
// r1 - operand; r3 - inc / test val
__ lgfi(r1, Operand(1));
__ lgfi(r3, Operand(1));
__ brxh(r1, r3, &continue1);
__ b(&failed);
__ bind(&continue1);
__ lgfi(r1, Operand(-2));
__ lgfi(r3, Operand(1));
__ brxh(r1, r3, &failed);
__ brxh(r1, r3, &failed);
__ brxh(r1, r3, &failed);
__ brxh(r1, r3, &continue2);
__ b(&failed);
//r1 - operand; r4 - inc; r5 - test val
__ bind(&continue2);
__ lgfi(r1, Operand(-2));
__ lgfi(r4, Operand(1));
__ lgfi(r5, Operand(-1));
__ brxh(r1, r4, &failed);
__ brxh(r1, r4, &ok);
__ b(&failed);
__ bind(&ok);
__ lgfi(r2, Operand::Zero());
__ b(r14); // test done.
__ bind(&failed);
__ lgfi(r2, Operand(1));
__ b(r14); // test done.
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::STUB, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
// brxhg
TEST(12) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
Assembler assm(isolate, nullptr, 0);
Label ok, failed, continue1, continue2;
// r1 - operand; r3 - inc / test val
__ lgfi(r1, Operand(1));
__ lgfi(r3, Operand(1));
__ brxhg(r1, r3, &continue1);
__ b(&failed);
__ bind(&continue1);
__ lgfi(r1, Operand(-2));
__ lgfi(r3, Operand(1));
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &continue2);
__ b(&failed);
__ lgfi(r1, Operand(1));
__ lgfi(r3, Operand(1));
__ brxhg(r1, r3, &continue1);
__ b(&failed);
__ bind(&continue1);
__ lgfi(r1, Operand(-2));
__ lgfi(r3, Operand(1));
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &failed);
__ brxhg(r1, r3, &continue2);
__ b(&failed);
//r1 - operand; r4 - inc; r5 - test val
__ bind(&continue2);
__ lgfi(r1, Operand(-2));
__ lgfi(r4, Operand(1));
__ lgfi(r5, Operand(-1));
__ brxhg(r1, r4, &failed);
__ brxhg(r1, r4, &ok);
__ b(&failed);
__ bind(&ok);
__ lgfi(r2, Operand::Zero());
__ b(r14); // test done.
__ bind(&failed);
__ lgfi(r2, Operand(1));
__ b(r14); // test done.
CodeDesc desc;
assm.GetCode(isolate, &desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::STUB, Handle<Code>());
#ifdef DEBUG
code->Print();
#endif
auto f = GeneratedCode<F1>::FromCode(*code);
intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
::printf("f() = %" V8PRIdPTR "\n", res);
CHECK_EQ(0, static_cast<int>(res));
}
#undef __
} // namespace internal
......
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