[vm, compiler] Use bit-manipulation extensions when targeting Android or Fuchsia RISC-V.

Use Zbb instructions when available for ClampedUint8List stores.
Use Zba instructions when available for IntConverter zero extensions.
Fix LslImmediate(kUnsignedFourBytes) when Zba is enabled.

TEST=locally switch to RV64GCB
Change-Id: If9fc0ac3fd2c5248785322f949e2003024e5152a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/385640
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2024-10-28 17:08:39 +00:00
committed by Commit Queue
parent 36da75d075
commit e25601e129
9 changed files with 69 additions and 340 deletions
@@ -2406,9 +2406,7 @@ void MicroAssembler::EmitJType(intptr_t imm, Register rd, Opcode opcode) {
Assembler::Assembler(ObjectPoolBuilder* object_pool_builder,
intptr_t far_branch_level)
: MicroAssembler(object_pool_builder,
far_branch_level,
FLAG_use_compressed_instructions ? RV_GC : RV_G),
: MicroAssembler(object_pool_builder, far_branch_level, RV_baseline),
constant_pool_allowed_(false) {
generate_invoke_write_barrier_wrapper_ = [&](Register reg) {
// Note this does not destroy RA.
@@ -2572,7 +2570,7 @@ void Assembler::ExtendValue(Register rd, Register rn, OperandSize sz) {
return mv(rd, rn);
case kUnsignedFourBytes:
if (Supports(RV_Zba)) {
return adduw(rd, rn, ZR);
return zextw(rd, rn);
}
slli(rd, rn, XLEN - 32);
return srli(rd, rn, XLEN - 32);
@@ -3311,13 +3309,12 @@ void Assembler::LslImmediate(Register rd,
return slliw(rd, rn, shift);
}
if (sz == kUnsignedFourBytes) {
if (Supports(RV_Zba)) {
return slliuw(rd, rn, shift);
} else {
// Clear upper bits in addition to the shift.
slli(rd, rn, shift + (XLEN / 2));
return srli(rd, rn, XLEN / 2);
}
// Not slliuw even when available. That zero extends the input, not the
// output.
// Clear upper bits in addition to the shift.
slli(rd, rn, shift + (XLEN / 2));
return srli(rd, rn, XLEN / 2);
}
#endif
slli(rd, rn, shift);
@@ -69,6 +69,7 @@ class MicroAssembler : public AssemblerBase {
#if defined(TESTING)
void SetExtensions(ExtensionSet extensions) { extensions_ = extensions; }
#endif
ExtensionSet extensions() const { return extensions_; }
bool Supports(Extension extension) const {
return extensions_.Includes(extension);
}
@@ -562,6 +563,8 @@ class MicroAssembler : public AssemblerBase {
void sh3adduw(Register rd, Register rs1, Register rs2);
void slliuw(Register rd, Register rs1, intx_t imm);
void zextw(Register rd, Register rs) { adduw(rd, rs, ZR); }
// ==== Zbb: Basic bit-manipulation ====
void andn(Register rd, Register rs1, Register rs2);
void orn(Register rd, Register rs1, Register rs2);
File diff suppressed because it is too large Load Diff
@@ -196,6 +196,12 @@ class Disassembler : public AllStatic {
static void DisassembleStub(const char* name, const Code& code);
#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
static void SetExtensions(ExtensionSet extensions) {
extensions_ = extensions;
}
#endif
private:
static void DisassembleCodeHelper(const char* function_fullname,
const char* function_info,
@@ -204,6 +210,10 @@ class Disassembler : public AllStatic {
static constexpr int kHexadecimalBufferSize = 32;
static constexpr int kUserReadableBufferSize = 256;
#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
static ExtensionSet extensions_;
#endif
};
} // namespace dart
@@ -993,7 +993,11 @@ void RISCVDisassembler::DisassembleOP32_ADDUW(Instr instr) {
switch (instr.funct3()) {
#if XLEN >= 64
case F3_0:
Print("add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
if (instr.rs2() == ZR) {
Print("zext.w 'rd, 'rs1", instr, RV_Zba);
} else {
Print("add.uw 'rd, 'rs1, 'rs2", instr, RV_Zba);
}
break;
case ZEXT:
Print("zext.h 'rd, 'rs1", instr, RV_Zbb);
@@ -1592,8 +1596,6 @@ void RISCVDisassembler::UnknownInstruction(CInstr instr) {
void RISCVDisassembler::Print(const char* format,
Instr instr,
ExtensionSet ex) {
// Printf(" %08x ", instr.encoding());
while (format[0] != '\0') {
if (format[0] == '\'') {
format = PrintOption(format + 1, instr);
@@ -1603,14 +1605,14 @@ void RISCVDisassembler::Print(const char* format,
}
}
// Printf("\n");
if (!Supports(ex)) {
Printf(" ;; from unsupported extension");
}
}
void RISCVDisassembler::Print(const char* format,
CInstr instr,
ExtensionSet ex) {
// Printf(" %04x ", instr.encoding());
while (format[0] != '\0') {
if (format[0] == '\'') {
format = PrintOption(format + 1, instr);
@@ -1620,7 +1622,9 @@ void RISCVDisassembler::Print(const char* format,
}
}
// Printf("\n");
if (!Supports(ex)) {
Printf(" ;; from unsupported extension");
}
}
#define STRING_STARTS_WITH(string, compare_string) \
@@ -1816,6 +1820,8 @@ const char* RISCVDisassembler::PrintOption(const char* format, CInstr instr) {
return nullptr;
}
ExtensionSet Disassembler::extensions_ = RV_baseline;
void Disassembler::DecodeInstruction(char* hex_buffer,
intptr_t hex_size,
char* human_buffer,
@@ -1824,8 +1830,7 @@ void Disassembler::DecodeInstruction(char* hex_buffer,
const Code& code,
Object** object,
uword pc) {
RISCVDisassembler decoder(human_buffer, human_size,
FLAG_use_compressed_instructions ? RV_GC : RV_G);
RISCVDisassembler decoder(human_buffer, human_size, extensions_);
int instr_size = decoder.Disassemble(pc);
if (instr_size == 2) {
Utils::SNPrint(hex_buffer, hex_size, " %04x",
+22 -21
View File
@@ -2392,23 +2392,29 @@ void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
} else {
const Register value = locs()->in(2).reg();
if (__ Supports(RV_Zbb)) {
__ li(TMP, 255);
__ min(TMP, TMP, value);
__ max(TMP, TMP, ZR);
__ sb(TMP, element_address);
} else {
compiler::Label store_zero, store_ff, done;
__ blt(value, ZR, &store_zero, compiler::Assembler::kNearJump);
compiler::Label store_zero, store_ff, done;
__ blt(value, ZR, &store_zero, compiler::Assembler::kNearJump);
__ li(TMP, 0xFF);
__ bgt(value, TMP, &store_ff, compiler::Assembler::kNearJump);
__ li(TMP, 0xFF);
__ bgt(value, TMP, &store_ff, compiler::Assembler::kNearJump);
__ sb(value, element_address);
__ j(&done, compiler::Assembler::kNearJump);
__ sb(value, element_address);
__ j(&done, compiler::Assembler::kNearJump);
__ Bind(&store_zero);
__ mv(TMP, ZR);
__ Bind(&store_zero);
__ mv(TMP, ZR);
__ Bind(&store_ff);
__ sb(TMP, element_address);
__ Bind(&store_ff);
__ sb(TMP, element_address);
__ Bind(&done);
__ Bind(&done);
}
}
} else if (RepresentationUtils::IsUnboxedInteger(rep)) {
if (rep == kUnboxedUint8 || rep == kUnboxedInt8) {
@@ -6993,15 +6999,12 @@ void IntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
} else if (from() == kUnboxedInt64) {
if (to() == kUnboxedInt32) {
if (is_truncating() || out != value) {
__ sextw(out, value); // Signed extension 64->32.
__ ExtendValue(out, value, compiler::kFourBytes);
}
} else {
ASSERT(to() == kUnboxedUint32);
if (is_truncating() || out != value) {
// Unsigned extension 64->32.
// TODO(riscv): Might be a shorter way to do this.
__ slli(out, value, 32);
__ srli(out, out, 32);
__ ExtendValue(out, value, compiler::kUnsignedFourBytes);
}
}
if (CanDeoptimize()) {
@@ -7011,12 +7014,10 @@ void IntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
} else if (to() == kUnboxedInt64) {
if (from() == kUnboxedUint32) {
// TODO(riscv): Might be a shorter way to do this.
__ slli(out, value, 32);
__ srli(out, out, 32);
__ ExtendValue(out, value, compiler::kUnsignedFourBytes);
} else {
ASSERT(from() == kUnboxedInt32);
__ sextw(out, value); // Signed extension 32->64.
__ ExtendValue(out, value, compiler::kFourBytes);
}
} else {
UNREACHABLE();
-7
View File
@@ -10,13 +10,6 @@
namespace dart {
#if !defined(FFI_UNIT_TESTS)
DEFINE_FLAG(bool,
use_compressed_instructions,
true,
"Use instructions from the C extension");
#endif
const char* const cpu_reg_names[kNumberOfCpuRegisters] = {
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "thr", "a0",
"a1", "a2", "tmp", "tmp2", "pp", "a6", "a7", "s2", "s3", "s4", "s5",
+6 -2
View File
@@ -20,8 +20,6 @@
namespace dart {
DECLARE_FLAG(bool, use_compressed_instructions);
#if defined(TARGET_ARCH_RISCV32)
typedef uint32_t uintx_t;
typedef int32_t intx_t;
@@ -1603,6 +1601,12 @@ static constexpr ExtensionSet RV_GCB = RV_GC | RV_B;
static constexpr Extension RV_Zbc(9); // Carry-less multiplication
static constexpr Extension RV_Zalasr(10); // Load-acquire, store-release
#if defined(DART_TARGET_OS_FUCHSIA) || defined(DART_TARGET_OS_ANDROID)
static constexpr ExtensionSet RV_baseline = RV_GCB;
#else
static constexpr ExtensionSet RV_baseline = RV_GC;
#endif
#undef R
inline Register ConcreteRegister(Register r) {
+6 -3
View File
@@ -726,13 +726,16 @@ void AssemblerTest::Assemble() {
// Disassemble relative since code addresses are not stable from run to run.
SetFlagScope<bool> sfs(&FLAG_disassemble_relative, true);
uword start = code_.PayloadStart();
uword end = start + assembler_->CodeSize();
#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
Disassembler::SetExtensions(assembler_->extensions());
#endif
if (FLAG_disassemble) {
OS::PrintErr("Code for test '%s' {\n", name_);
Disassembler::Disassemble(start, start + assembler_->CodeSize());
Disassembler::Disassemble(start, end);
OS::PrintErr("}\n");
}
Disassembler::Disassemble(start, start + assembler_->CodeSize(), disassembly_,
DISASSEMBLY_SIZE);
Disassembler::Disassemble(start, end, disassembly_, DISASSEMBLY_SIZE);
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
// Blank out absolute addressing constants on ia32, since they are not stable
// from run to run.