From 79182d64a9cdb85c25b723d9743ed82209d700bf Mon Sep 17 00:00:00 2001 From: Reza Yazdani Date: Wed, 14 Oct 2020 13:23:23 -0700 Subject: [PATCH] Added li_ptr to create 48 bit immediate addresses. --- src/codegen/riscv64/assembler-riscv64.cc | 128 +++++++++--------- src/codegen/riscv64/assembler-riscv64.h | 2 + .../riscv64/macro-assembler-riscv64.cc | 11 +- test/cctest/test-assembler-riscv64.cc | 22 ++- test/cctest/test-macro-assembler-riscv64.cc | 4 +- 5 files changed, 82 insertions(+), 85 deletions(-) diff --git a/src/codegen/riscv64/assembler-riscv64.cc b/src/codegen/riscv64/assembler-riscv64.cc index 2db126ca27b4..4841c541a0af 100644 --- a/src/codegen/riscv64/assembler-riscv64.cc +++ b/src/codegen/riscv64/assembler-riscv64.cc @@ -309,6 +309,9 @@ bool Assembler::IsAddiw(Instr instr) { bool Assembler::IsAddi(Instr instr) { return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ADDI; } +bool Assembler::IsOri(Instr instr) { + return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_ORI; +} bool Assembler::IsSlli(Instr instr) { return (instr & (kBaseOpcodeMask | kFunct3Mask)) == RO_SLLI; } @@ -2362,6 +2365,24 @@ int Assembler::li_estimate(int64_t imm, bool is_get_temp_reg) { return count; } +void Assembler::li_ptr(Register rd, int64_t imm) { + // Initialize rd with an address + // Pointers are 48 bits + // 6 fixed instructions are generated + DCHECK((imm & 0xfff0000000000000ll) == 0); + int64_t a6 = imm & 0x3f; // bits 0:6. 6 bits + int64_t b11 = (imm >> 6) & 0x7ff; //bits 6:11. 11 bits + int64_t high_31 = (imm >> 17) & 0x7fffffff; // 31 bits + int64_t high_20 = ((high_31 + 0x800) >> 12); // 19 bits + int64_t low_12 = high_31 & 0xfff; // 12 bits + lui(rd, (int32_t)high_20); + addi(rd, rd, low_12); // 31 bits in rd. + slli(rd, rd, 11); // Space for next 11 bis + ori(rd, rd, b11); // 11 bits are put in. 42 bit in rd + slli(rd, rd, 6); // Space for next 6 bits + ori(rd, rd, a6); // 6 bits are put in. 48 bis in rd +} + void Assembler::li_constant(Register rd, int64_t imm) { DEBUG_PRINTF("li_constant(%d, %lx <%ld>)\n", ToNumber(rd), imm, imm); lui(rd, (imm + (1LL << 47) + (1LL << 35) + (1LL << 23) + (1LL << 11)) >> @@ -2646,31 +2667,30 @@ Address Assembler::target_address_at(Address pc, Address constant_pool) { return target_address_at(pc); } } - Address Assembler::target_address_at(Address pc) { DEBUG_PRINTF("target_address_at: pc: %lx\t", pc); Instruction* instr0 = Instruction::At((unsigned char*)pc); Instruction* instr1 = Instruction::At((unsigned char*)(pc + 1 * kInstrSize)); + Instruction* instr2 = Instruction::At((unsigned char*)(pc + 2 * kInstrSize)); Instruction* instr3 = Instruction::At((unsigned char*)(pc + 3 * kInstrSize)); + Instruction* instr4 = Instruction::At((unsigned char*)(pc + 4 * kInstrSize)); Instruction* instr5 = Instruction::At((unsigned char*)(pc + 5 * kInstrSize)); - Instruction* instr7 = Instruction::At((unsigned char*)(pc + 7 * kInstrSize)); - // Interpret 5 instructions for address generated by li: See listing in + // Interpret instructions for address generated by li: See listing in // Assembler::set_target_address_at() just below. if (IsLui(*reinterpret_cast(instr0)) && - IsAddiw(*reinterpret_cast(instr1)) && - IsAddi(*reinterpret_cast(instr3)) && - IsAddi(*reinterpret_cast(instr5)) && - IsAddi(*reinterpret_cast(instr7))) { + IsAddi(*reinterpret_cast(instr1)) && + IsSlli(*reinterpret_cast(instr2)) && + IsOri(*reinterpret_cast(instr3)) && + IsSlli(*reinterpret_cast(instr4)) && + IsOri(*reinterpret_cast(instr5))) { // Assemble the 64 bit value. int64_t addr = (int64_t)(instr0->Imm20UValue() << kImm20Shift) + (int64_t)instr1->Imm12Value(); - addr <<= 12; - addr += (int64_t)instr3->Imm12Value(); - addr <<= 12; - addr += (int64_t)instr5->Imm12Value(); - addr <<= 12; - addr += (int64_t)instr7->Imm12Value(); + addr <<= 11; + addr |= (int64_t)instr3->Imm12Value(); + addr <<= 6; + addr |= (int64_t)instr5->Imm12Value(); DEBUG_PRINTF("addr: %lx\n", addr); return static_cast
(addr); @@ -2678,20 +2698,15 @@ Address Assembler::target_address_at(Address pc) { // We should never get here, force a bad address if we do. UNREACHABLE(); } - -// On RISC-V, a 64-bit target address is stored in an 8-instruction sequence: -// 0: lui(rd, (j.imm64_ + (1LL << 47) + (1LL << 35) + -// (1LL << 23) + (1LL << 11)) >> 48); -// 1: addiw(rd, rd, (j.imm64_ + (1LL << 35) + (1LL << 23) + (1LL << 11)) -// << 16 >> 52); -// 2: slli(rd, rd, 12); -// 3: addi(rd, rd, (j.imm64_ + (1LL << 23) + (1LL << 11)) << 28 >> 52); -// 4: slli(rd, rd, 12); -// 5: addi(rd, rd, (j.imm64_ + (1 << 11)) << 40 >> 52); -// 6: slli(rd, rd, 12); -// 7: addi(rd, rd, j.imm64_ << 52 >> 52); +// On RISC-V, a 48-bit target address is stored in an 6-instruction sequence: +// lui(reg, (int32_t)high_20); // 19 high bits +// addi(reg, reg, low_12); // 12 following bits. total is 31 high bits in reg. +// slli(reg, reg, 11); // Space for next 11 bits +// ori(reg, reg, b11); // 11 bits are put in. 42 bit in reg +// slli(reg, reg, 6); // Space for next 6 bits +// ori(reg, reg, a6); // 6 bits are put in. all 48 bis in reg // -// Patching the address must replace all the lui & addi instructions, +// Patching the address must replace all instructions, // and flush the i-cache. void Assembler::set_target_value_at(Address pc, uint64_t target, ICacheFlushMode icache_flush_mode) { @@ -2702,59 +2717,42 @@ void Assembler::set_target_value_at(Address pc, uint64_t target, // It relies on fact the upper [63:48] bits are not used for virtual address // translation and they have to be set according to value of bit 47 in order // get canonical address. - Instruction* instr0 = Instruction::At((unsigned char*)pc); DEBUG_PRINTF("set_target_value_at: pc: %lx\ttarget: %lx\n", pc, target); - int rd_code = instr0->RdValue(); uint32_t* p = reinterpret_cast(pc); - + DCHECK((target & 0xffff000000000000ll) == 0); #ifdef DEBUG // Check we have the result from a li macro-instruction. + Instruction* instr0 = Instruction::At((unsigned char*)pc); Instruction* instr1 = Instruction::At((unsigned char*)(pc + 1 * kInstrSize)); Instruction* instr3 = Instruction::At((unsigned char*)(pc + 3 * kInstrSize)); Instruction* instr5 = Instruction::At((unsigned char*)(pc + 5 * kInstrSize)); - Instruction* instr7 = Instruction::At((unsigned char*)(pc + 7 * kInstrSize)); DCHECK(IsLui(*reinterpret_cast(instr0)) && - IsAddiw(*reinterpret_cast(instr1)) && - IsAddi(*reinterpret_cast(instr3)) && - IsAddi(*reinterpret_cast(instr5)) && - IsAddi(*reinterpret_cast(instr7))); + IsAddi(*reinterpret_cast(instr1)) && + IsOri(*reinterpret_cast(instr3)) && + IsOri(*reinterpret_cast(instr5))); #endif - - // Must use 8 instructions to insure patchable code (see above comment). - *p = LUI | (rd_code << kRdShift) | - ((uint32_t)( - (target + (1LL << 47) + (1LL << 35) + (1LL << 23) + (1LL << 11)) >> - 48) - << kImm20Shift); - *(p + 1) = - OP_IMM_32 | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | - (rd_code << kRs1Shift) | - ((uint32_t)((target + (1LL << 35) + (1LL << 23) + (1LL << 11)) << 16 >> - 52) - << kImm12Shift); - *(p + 2) = OP_IMM | (rd_code << kRdShift) | (0b001 << kFunct3Shift) | - (rd_code << kRs1Shift) | (12 << kImm12Shift); - *(p + 3) = OP_IMM | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | - (rd_code << kRs1Shift) | - ((uint32_t)((target + (1LL << 23) + (1LL << 11)) << 28 >> 52) - << kImm12Shift); - *(p + 4) = OP_IMM | (rd_code << kRdShift) | (0b001 << kFunct3Shift) | - (rd_code << kRs1Shift) | (12 << kImm12Shift); - *(p + 5) = OP_IMM | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | - (rd_code << kRs1Shift) | - ((uint32_t)((target + (1LL << 11)) << 40 >> 52) << kImm12Shift); - *(p + 6) = OP_IMM | (rd_code << kRdShift) | (0b001 << kFunct3Shift) | - (rd_code << kRs1Shift) | (12 << kImm12Shift); - *(p + 7) = OP_IMM | (rd_code << kRdShift) | (0b000 << kFunct3Shift) | - (rd_code << kRs1Shift) | - ((uint32_t)(target << 52 >> 52) << kImm12Shift); - + int64_t a6 = target & 0x3f; // bits 0:6. 6 bits + int64_t b11 = (target >> 6) & 0x7ff; //bits 6:11. 11 bits + int64_t high_31 = (target >> 17) & 0x7fffffff; // 31 bits + int64_t high_20 = ((high_31 + 0x800) >> 12); // 19 bits + int64_t low_12 = high_31 & 0xfff; // 12 bits + *p = *p & 0xfff; + *p = *p | ((int32_t)high_20 << 12); + *(p + 1) = *(p + 1) & 0xfffff; + *(p + 1) = *(p + 1) | ((int32_t)low_12 << 20); + *(p + 2) = *(p + 2) & 0xfffff; + *(p + 2) = *(p + 2) | (11 << 20); + *(p + 3) = *(p + 3) & 0xfffff; + *(p + 3) = *(p + 3) | ((int32_t)b11 << 20); + *(p + 4) = *(p + 4) & 0xfffff; + *(p + 4) = *(p + 4) | (6 << 20); + *(p + 5) = *(p + 5) & 0xfffff; + *(p + 5) = *(p + 5) | ((int32_t)a6 << 20); if (icache_flush_mode != SKIP_ICACHE_FLUSH) { FlushInstructionCache(pc, 8 * kInstrSize); } DCHECK_EQ(target_address_at(pc), target); } - UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler) : available_(assembler->GetScratchRegisterList()), old_available_(*available_) {} diff --git a/src/codegen/riscv64/assembler-riscv64.h b/src/codegen/riscv64/assembler-riscv64.h index 0ad75af669fa..e06c7dad4c1a 100644 --- a/src/codegen/riscv64/assembler-riscv64.h +++ b/src/codegen/riscv64/assembler-riscv64.h @@ -625,6 +625,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { // Loads an immediate, always using 8 instructions, regardless of the value, // so that it can be modified later. void li_constant(Register rd, int64_t imm); + void li_ptr(Register rd, int64_t imm); void mv(Register rd, Register rs) { addi(rd, rs, 0); } void not_(Register rd, Register rs) { xori(rd, rs, -1); } @@ -836,6 +837,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { static bool IsAuipc(Instr instr); static bool IsAddiw(Instr instr); static bool IsAddi(Instr instr); + static bool IsOri(Instr instr); static bool IsSlli(Instr instr); static bool IsLd(Instr instr); diff --git a/src/codegen/riscv64/macro-assembler-riscv64.cc b/src/codegen/riscv64/macro-assembler-riscv64.cc index 53887cc2acb1..9b2b6d19a689 100644 --- a/src/codegen/riscv64/macro-assembler-riscv64.cc +++ b/src/codegen/riscv64/macro-assembler-riscv64.cc @@ -1462,16 +1462,15 @@ void TurboAssembler::li(Register rd, Operand j, LiFlags mode) { } RecordRelocInfo(j.rmode(), immediate); - // FIXME(RISC_V): Does this case need to be constant size? - li_constant(rd, immediate); + li_ptr(rd, immediate); } else if (mode == ADDRESS_LOAD) { // We always need the same number of instructions as we may need to patch - // this code to load another value which may need all 8 instructions. + // this code to load another value which may need all 6 instructions. RecordRelocInfo(j.rmode()); - li_constant(rd, j.immediate()); - } else { // mode == CONSTANT_SIZE - always emit the same instruction + li_ptr(rd, j.immediate()); + } else { // Always emit the same 48 bit instruction // sequence. - li_constant(rd, j.immediate()); + li_ptr(rd, j.immediate()); } } diff --git a/test/cctest/test-assembler-riscv64.cc b/test/cctest/test-assembler-riscv64.cc index 65dc0566531a..74b043773dcb 100644 --- a/test/cctest/test-assembler-riscv64.cc +++ b/test/cctest/test-assembler-riscv64.cc @@ -1319,6 +1319,7 @@ TEST(RVC_CA) { auto res = GenAndRunTest(LARGE_INT_UNDER_32_BIT, fn); CHECK_EQ(LARGE_INT_UNDER_32_BIT - MIN_VAL_IMM12, res); } + // Test c.addw { auto fn = [](MacroAssembler& assm) { @@ -1449,16 +1450,14 @@ TEST(TARGET_ADDR) { Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - // This is the series of instructions to load 0x123456789abcdef0 - uint32_t buffer[8] = {0x01234237, 0x5682021b, 0x00c21213, 0x89b20213, - 0x00c21213, 0xbce20213, 0x00c21213, 0xef020213}; - + // This is the series of instructions to load 48 bit address 0x0123456789ab + uint32_t buffer[6] = {0x091ab37, 0x2b330213, 0x00b21213, 0x62626213, + 0x00621213, 0x02b26213}; MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes); uintptr_t addr = reinterpret_cast(&buffer[0]); Address res = __ target_address_at(static_cast
(addr)); - - CHECK_EQ(0x123456789abcdef0L, res); + CHECK_EQ(0x0123456789abL, res); } TEST(SET_TARGET_ADDR) { @@ -1466,18 +1465,17 @@ TEST(SET_TARGET_ADDR) { Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - // This is the series of instructions to load 0x123456789abcdef0 - uint32_t buffer[8] = {0x01234237, 0x5682021b, 0x00c21213, 0x89b20213, - 0x00c21213, 0xbce20213, 0x00c21213, 0xef020213}; + // This is the series of instructions to load 48 bit address 0xba9876543210 + uint32_t buffer[6] = {0x091ab37, 0x2b330213, 0x00b21213, 0x62626213, + 0x00621213, 0x02b26213}; MacroAssembler assm(isolate, v8::internal::CodeObjectRequired::kYes); uintptr_t addr = reinterpret_cast(&buffer[0]); - __ set_target_value_at(static_cast
(addr), 0xfedcba9876543210, + __ set_target_value_at(static_cast
(addr), 0xba9876543210L, FLUSH_ICACHE_IF_NEEDED); Address res = __ target_address_at(static_cast
(addr)); - - CHECK_EQ(0xfedcba9876543210, res); + CHECK_EQ(0xba9876543210L, res); } // pair.first is the F_TYPE input to test, pair.second is I_TYPE expected diff --git a/test/cctest/test-macro-assembler-riscv64.cc b/test/cctest/test-macro-assembler-riscv64.cc index 0998c9af9c06..4a0bf7a371b9 100644 --- a/test/cctest/test-macro-assembler-riscv64.cc +++ b/test/cctest/test-macro-assembler-riscv64.cc @@ -158,9 +158,9 @@ TEST(LoadAddress) { RelocInfo::INTERNAL_REFERENCE_ENCODED), ADDRESS_LOAD); int check_size = masm.InstructionsGeneratedSince(&skip); - // NOTE (RISCV): current li generates 8 instructions, if the sequence is + // NOTE (RISCV): current li generates 6 instructions, if the sequence is // changed, need to adjust the CHECK_EQ value too - CHECK_EQ(8, check_size); + CHECK_EQ(6, check_size); __ jr(a4); __ nop(); __ stop();