diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-09 04:17:18 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-09 04:17:18 +0000 |
commit | 1771efed7401fd557a5bb6834c754a613bd241ff (patch) | |
tree | 4c9984e83bda6e975d9b321d5b8565617947866a | |
parent | 1a4ad5d18eedbfdedc342f817b5898e5c41219ab (diff) | |
parent | 160d6f3d4434fd8cbd006d505bc1b4b375ff3237 (diff) | |
download | binary_translation-1771efed7401fd557a5bb6834c754a613bd241ff.tar.gz |
Snap for 11200327 from 160d6f3d4434fd8cbd006d505bc1b4b375ff3237 to 24Q1-release
Change-Id: Ifd8f3e34183f06bea2e83009fb222947db5b66e7
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | base/include/berberis/base/config.h | 4 | ||||
-rw-r--r-- | base/include/berberis/base/format_buffer.h | 8 | ||||
-rw-r--r-- | base/tracing.cc | 2 | ||||
-rw-r--r-- | decoder/include/berberis/decoder/riscv64/decoder.h | 30 | ||||
-rw-r--r-- | decoder/include/berberis/decoder/riscv64/semantics_player.h | 6 | ||||
-rw-r--r-- | guest_abi/include/berberis/guest_abi/function_wrappers.h | 77 | ||||
-rw-r--r-- | heavy_optimizer/riscv64/frontend.cc | 47 | ||||
-rw-r--r-- | interpreter/riscv64/interpreter.cc | 174 | ||||
-rw-r--r-- | interpreter/riscv64/interpreter_test.cc | 111 | ||||
-rw-r--r-- | intrinsics/common_to_x86/gen_text_asm_intrinsics.cc | 4 | ||||
-rwxr-xr-x | intrinsics/gen_intrinsics.py | 22 | ||||
-rw-r--r-- | intrinsics/riscv64/include/berberis/intrinsics/riscv64/vector_intrinsics.h | 28 | ||||
-rw-r--r-- | intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler.h | 2 | ||||
-rw-r--r-- | native_bridge/native_bridge.cc | 248 | ||||
-rw-r--r-- | runtime/execute_guest.cc | 5 | ||||
-rw-r--r-- | test_utils/include/berberis/test_utils/insn_tests_riscv64-inl.h | 5 | ||||
-rwxr-xr-x | tools/symbolize_trace.py | 214 |
18 files changed, 782 insertions, 206 deletions
@@ -148,6 +148,7 @@ cc_library_shared { ], shared_libs: [ "libandroid", + "libdl_android", ], }, }, diff --git a/base/include/berberis/base/config.h b/base/include/berberis/base/config.h index 1be0e36b..bd0323fc 100644 --- a/base/include/berberis/base/config.h +++ b/base/include/berberis/base/config.h @@ -34,6 +34,10 @@ namespace berberis::config { // TODO(b/232598137): 12 is what we get on x86-32 after stack alignment, update // with, say, 90-percentile of (dynamic) frame size. inline constexpr uint32_t kFrameSizeAtTranslatedCode = sizeof(size_t) == 4 ? 12u : 8u; +// Attention: This flag traces every entry to RunGeneratedCode which +// may be *very* slow especially if kAllJumpsExitGeneratedCode flag is +// enabled. +inline constexpr bool kTraceGeneratedCode = false; // Setting this to true enables instrumentation of every executed region in the // main execution loop (ExecuteGuest). inline constexpr bool kAllJumpsExitGeneratedCode = false; diff --git a/base/include/berberis/base/format_buffer.h b/base/include/berberis/base/format_buffer.h index b00dbab1..b7eab85e 100644 --- a/base/include/berberis/base/format_buffer.h +++ b/base/include/berberis/base/format_buffer.h @@ -186,7 +186,7 @@ class FormatAndArgs { private: bool PutSpec(Out* out) { Style style = ParseStyle(); - switch (char c = *format_++) { + switch (*format_++) { case '%': return out->Put('%'); case 'c': @@ -211,7 +211,7 @@ class FormatAndArgs { } bool PutLongSpec(Out* out, const Style& style) { - switch (char c = *format_++) { + switch (*format_++) { case 'd': return PutInt(out, style, args_->GetLong(), 10); case 'u': @@ -226,7 +226,7 @@ class FormatAndArgs { } bool PutLongLongSpec(Out* out, const Style& style) { - switch (char c = *format_++) { + switch (*format_++) { case 'd': return PutInt(out, style, args_->GetLongLong(), 10); case 'u': @@ -239,7 +239,7 @@ class FormatAndArgs { } bool PutSizeTSpec(Out* out, const Style& style) { - switch (char c = *format_++) { + switch (*format_++) { case 'u': return PutUInt(out, style, nullptr, 0, args_->GetSizeT(), 10); case 'x': diff --git a/base/tracing.cc b/base/tracing.cc index be346292..59541788 100644 --- a/base/tracing.cc +++ b/base/tracing.cc @@ -120,7 +120,7 @@ void Tracing::InitImpl() { ScopedErrno scoped_errno; auto env = GetTracingConfig(); - if (!env) { + if (!env || !env[0]) { return; } diff --git a/decoder/include/berberis/decoder/riscv64/decoder.h b/decoder/include/berberis/decoder/riscv64/decoder.h index 2f36fddc..ff3929e8 100644 --- a/decoder/include/berberis/decoder/riscv64/decoder.h +++ b/decoder/include/berberis/decoder/riscv64/decoder.h @@ -265,7 +265,7 @@ class Decoder { kMaxValue = 0b111111111111'11111'111'11111, }; - enum class VOpViOpcode { + enum class VOpIViOpcode { kVaddvi = 0b000000, kVrsubvi = 0b000011, kVandvi = 0b001001, @@ -298,7 +298,7 @@ class Decoder { kMaxValue = 0b111111, }; - enum class VOpVvOpcode { + enum class VOpIVvOpcode { kVaddvv = 0b000000, kVsubvv = 0b000010, kVminuvv = 0b000100, @@ -340,7 +340,7 @@ class Decoder { kMaxValue = 0b111111 }; - enum class VOpVxOpcode { + enum class VOpIVxOpcode { kVaddvx = 0b000000, kVsubvx = 0b000010, kVrsubvx = 0b000011, @@ -620,24 +620,24 @@ class Decoder { using OpImmArgs = OpImmArgsTemplate<OpImmOpcode>; using OpImm32Args = OpImmArgsTemplate<OpImm32Opcode>; - struct VOpViArgs { - VOpViOpcode opcode; + struct VOpIViArgs { + VOpIViOpcode opcode; bool vm; uint8_t dst; uint8_t src; int8_t imm; }; - struct VOpVvArgs { - VOpVvOpcode opcode; + struct VOpIVvArgs { + VOpIVvOpcode opcode; bool vm; uint8_t dst; uint8_t src1; uint8_t src2; }; - struct VOpVxArgs { - VOpVxOpcode opcode; + struct VOpIVxArgs { + VOpIVxOpcode opcode; bool vm; uint8_t dst; uint8_t src1; @@ -1711,8 +1711,8 @@ class Decoder { uint8_t src2 = GetBits<uint8_t, 15, 5>(); switch (low_opcode) { case 0b000: { - const VOpVvArgs args = { - .opcode = VOpVvOpcode(opcode), + const VOpIVvArgs args = { + .opcode = VOpIVvOpcode(opcode), .vm = vm, .dst = dst, .src1 = src1, @@ -1721,8 +1721,8 @@ class Decoder { return insn_consumer_->OpVector(args); } case 0b011: { - const VOpViArgs args = { - .opcode = VOpViOpcode(opcode), + const VOpIViArgs args = { + .opcode = VOpIViOpcode(opcode), .vm = vm, .dst = dst, .src = src1, @@ -1731,8 +1731,8 @@ class Decoder { return insn_consumer_->OpVector(args); } case 0b100: { - const VOpVxArgs args = { - .opcode = VOpVxOpcode(opcode), + const VOpIVxArgs args = { + .opcode = VOpIVxOpcode(opcode), .vm = vm, .dst = dst, .src1 = src1, diff --git a/decoder/include/berberis/decoder/riscv64/semantics_player.h b/decoder/include/berberis/decoder/riscv64/semantics_player.h index 4b922db9..cfa707c7 100644 --- a/decoder/include/berberis/decoder/riscv64/semantics_player.h +++ b/decoder/include/berberis/decoder/riscv64/semantics_player.h @@ -789,19 +789,19 @@ class SemanticsPlayer { SetRegOrIgnore(args.dst, result); } - void OpVector(const typename Decoder::VOpViArgs& args) { + void OpVector(const typename Decoder::VOpIViArgs& args) { // TODO(300690740): develop and implement strategy which would allow us to support vector // intrinsics not just in the interpreter. listener_->OpVector(args); } - void OpVector(const typename Decoder::VOpVvArgs& args) { + void OpVector(const typename Decoder::VOpIVvArgs& args) { // TODO(300690740): develop and implement strategy which would allow us to support vector // intrinsics not just in the interpreter. listener_->OpVector(args); } - void OpVector(const typename Decoder::VOpVxArgs& args) { + void OpVector(const typename Decoder::VOpIVxArgs& args) { // TODO(300690740): develop and implement strategy which would allow us to support vector // intrinsics not just in the interpreter. Register arg2 = GetRegOrZero(args.src2); diff --git a/guest_abi/include/berberis/guest_abi/function_wrappers.h b/guest_abi/include/berberis/guest_abi/function_wrappers.h index 400452f6..1f4918c3 100644 --- a/guest_abi/include/berberis/guest_abi/function_wrappers.h +++ b/guest_abi/include/berberis/guest_abi/function_wrappers.h @@ -33,6 +33,53 @@ template <typename Func, GuestAbi::CallingConventionsVariant kCallingConventionsVariant = GuestAbi::kDefaultAbi> class TrampolineFuncGenerator; +template <typename Arg, + GuestAbi::CallingConventionsVariant kCallingConventionsVariant = GuestAbi::kDefaultAbi> +struct GetGuestArgumentClass { + public: + static_assert(!std::is_pointer_v<Arg> || !std::is_function_v<std::remove_pointer_t<Arg>>); + decltype(auto) operator()(Arg arg) const { return arg; } +}; + +template <typename Res, + typename... Args, + GuestAbi::CallingConventionsVariant kCallingConventionsVariant> +struct GetGuestArgumentClass<Res (*)(Args...), kCallingConventionsVariant> { + public: + decltype(auto) operator()(GuestType<Res (*)(Args...)> func) const { + return WrapGuestFunction(func, "AutoGeneratedWrapper"); + } +}; + +template <typename Arg, + GuestAbi::CallingConventionsVariant kCallingConventionsVariant = GuestAbi::kDefaultAbi> +inline constexpr auto GetGuestArgument = GetGuestArgumentClass<Arg, kCallingConventionsVariant>{}; + +template <typename Arg, + GuestAbi::CallingConventionsVariant kCallingConventionsVariant = GuestAbi::kDefaultAbi> +struct GetGuestResultClass { + public: + static_assert(!std::is_pointer_v<Arg> || !std::is_function_v<std::remove_pointer_t<Arg>>); + decltype(auto) operator()(Arg arg) const { return arg; } +}; + +template <typename Res, + typename... Args, + GuestAbi::CallingConventionsVariant kCallingConventionsVariant> +struct GetGuestResultClass<Res (*)(Args...), kCallingConventionsVariant> { + public: + decltype(auto) operator()(Res (*func)(Args...)) const { + WrapHostFunctionImpl(reinterpret_cast<HostCode>(func), + TrampolineFuncGenerator<Res(Args...), kCallingConventionsVariant>::Func, + "AutoGeneratedWrapper"); + return func; + } +}; + +template <typename Arg, + GuestAbi::CallingConventionsVariant kCallingConventionsVariant = GuestAbi::kDefaultAbi> +inline constexpr auto GetGuestResult = GetGuestResultClass<Arg, kCallingConventionsVariant>{}; + template <typename Res, typename... Args, GuestAbi::CallingConventionsVariant kCallingConventionsVariant> @@ -49,35 +96,15 @@ class TrampolineFuncGenerator<Res(Args...), kCallingConventionsVariant> { static void FuncImpl(Func func, ThreadState* state, std::index_sequence<I...>) { GuestParamsValues<Func, kCallingConventionsVariant> params(state); if constexpr (std::is_same_v<Res, void>) { - func(GetArgument<I>(params)...); - } else if constexpr (std::is_pointer_v<Res> && std::is_function_v<std::remove_pointer_t<Res>>) { - auto&& [ret] = GuestReturnReference<Func, kCallingConventionsVariant>(state); - ret = WrapResultFunction(func(GetArgument<I>(params)...)); + func(GetGuestArgument<std::tuple_element_t<I, std::tuple<Args...>>, + kCallingConventionsVariant>(params.template get<I>())...); } else { auto&& [ret] = GuestReturnReference<Func, kCallingConventionsVariant>(state); - ret = func(GetArgument<I>(params)...); - } - } - - template <std::size_t index, typename GuestParams> - static auto GetArgument(const GuestParams& params) { - using Arg = std::tuple_element_t<index, std::tuple<Args...>>; - if constexpr (std::is_pointer_v<Arg> && std::is_function_v<std::remove_pointer_t<Arg>>) { - return WrapGuestFunction(params.template get<index>(), "AutoGeneratedWrapper"); - } else { - return params.template get<index>(); + ret = GetGuestResult<Res, kCallingConventionsVariant>( + func(GetGuestArgument<std::tuple_element_t<I, std::tuple<Args...>>, + kCallingConventionsVariant>(params.template get<I>())...)); } } - - template <typename ResultRes, typename... ResultArgs> - static GuestType<ResultRes (*)(ResultArgs...)> WrapResultFunction( - ResultRes (*func)(ResultArgs...)) { - WrapHostFunctionImpl( - reinterpret_cast<HostCode>(func), - TrampolineFuncGenerator<ResultRes(ResultArgs...), kCallingConventionsVariant>::Func, - "AutoGeneratedWrapper"); - return func; - } }; // Pointer to function. diff --git a/heavy_optimizer/riscv64/frontend.cc b/heavy_optimizer/riscv64/frontend.cc index 11b6a5e4..b04144cb 100644 --- a/heavy_optimizer/riscv64/frontend.cc +++ b/heavy_optimizer/riscv64/frontend.cc @@ -604,7 +604,23 @@ void HeavyOptimizerFrontend::Store(Decoder::StoreOperandType operand_type, int16_t offset, Register data) { int32_t sx_offset{offset}; - StoreWithoutRecovery(operand_type, arg, sx_offset, data); + switch (operand_type) { + case Decoder::StoreOperandType::k8bit: + Gen<x86_64::MovbMemBaseDispReg>(arg, sx_offset, data); + break; + case Decoder::StoreOperandType::k16bit: + Gen<x86_64::MovwMemBaseDispReg>(arg, sx_offset, data); + break; + case Decoder::StoreOperandType::k32bit: + Gen<x86_64::MovlMemBaseDispReg>(arg, sx_offset, data); + break; + case Decoder::StoreOperandType::k64bit: + Gen<x86_64::MovqMemBaseDispReg>(arg, sx_offset, data); + break; + default: + return Unimplemented(); + } + GenRecoveryBlockForLastInsn(); } @@ -612,7 +628,34 @@ Register HeavyOptimizerFrontend::Load(Decoder::LoadOperandType operand_type, Register arg, int16_t offset) { int32_t sx_offset{offset}; - auto res = LoadWithoutRecovery(operand_type, arg, sx_offset); + auto res = AllocTempReg(); + switch (operand_type) { + case Decoder::LoadOperandType::k8bitUnsigned: + Gen<x86_64::MovzxblRegMemBaseDisp>(res, arg, sx_offset); + break; + case Decoder::LoadOperandType::k16bitUnsigned: + Gen<x86_64::MovzxwlRegMemBaseDisp>(res, arg, sx_offset); + break; + case Decoder::LoadOperandType::k32bitUnsigned: + Gen<x86_64::MovlRegMemBaseDisp>(res, arg, sx_offset); + break; + case Decoder::LoadOperandType::k64bit: + Gen<x86_64::MovqRegMemBaseDisp>(res, arg, sx_offset); + break; + case Decoder::LoadOperandType::k8bitSigned: + Gen<x86_64::MovsxbqRegMemBaseDisp>(res, arg, sx_offset); + break; + case Decoder::LoadOperandType::k16bitSigned: + Gen<x86_64::MovsxwqRegMemBaseDisp>(res, arg, sx_offset); + break; + case Decoder::LoadOperandType::k32bitSigned: + Gen<x86_64::MovsxlqRegMemBaseDisp>(res, arg, sx_offset); + break; + default: + Unimplemented(); + return {}; + } + GenRecoveryBlockForLastInsn(); return res; } diff --git a/interpreter/riscv64/interpreter.cc b/interpreter/riscv64/interpreter.cc index e628f65f..6785b4fa 100644 --- a/interpreter/riscv64/interpreter.cc +++ b/interpreter/riscv64/interpreter.cc @@ -548,160 +548,169 @@ class Interpreter { } template <typename ElementType, VectorRegisterGroupMultiplier vlmul, TailProcessing vta> - void OpVector(const Decoder::VOpViArgs& args) { + void OpVector(const Decoder::VOpIViArgs& args) { switch (args.opcode) { - case Decoder::VOpViOpcode::kVaddvi: + case Decoder::VOpIViOpcode::kVaddvi: return OpVectorvx<intrinsics::Vaddvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVrsubvi: + case Decoder::VOpIViOpcode::kVrsubvi: return OpVectorvx<intrinsics::Vrsubvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVandvi: + case Decoder::VOpIViOpcode::kVandvi: return OpVectorvx<intrinsics::Vandvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVorvi: + case Decoder::VOpIViOpcode::kVorvi: return OpVectorvx<intrinsics::Vorvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVxorvi: + case Decoder::VOpIViOpcode::kVxorvi: return OpVectorvx<intrinsics::Vxorvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmseqvi: + case Decoder::VOpIViOpcode::kVmseqvi: return OpVectorvx<intrinsics::Vmseqvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsnevi: + case Decoder::VOpIViOpcode::kVmsnevi: return OpVectorvx<intrinsics::Vmsnevx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsleuvi: + case Decoder::VOpIViOpcode::kVmsleuvi: return OpVectorvx<intrinsics::Vmslevx<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmslevi: + case Decoder::VOpIViOpcode::kVmslevi: return OpVectorvx<intrinsics::Vmslevx<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsgtuvi: + case Decoder::VOpIViOpcode::kVmsgtuvi: return OpVectorvx<intrinsics::Vmsgtvx<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsgtvi: + case Decoder::VOpIViOpcode::kVmsgtvi: return OpVectorvx<intrinsics::Vmsgtvx<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src, args.imm); + case Decoder::VOpIViOpcode::kVsllvi: + return OpVectorvx<intrinsics::Vsllvx<ElementType, vta>, ElementType, vlmul, vta>( + args.dst, args.src, args.imm); default: Unimplemented(); } } template <typename ElementType, VectorRegisterGroupMultiplier vlmul, TailProcessing vta> - void OpVector(const Decoder::VOpVvArgs& args) { + void OpVector(const Decoder::VOpIVvArgs& args) { switch (args.opcode) { - case Decoder::VOpVvOpcode::kVaddvv: + case Decoder::VOpIVvOpcode::kVaddvv: return OpVectorvv<intrinsics::Vaddvv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVsubvv: + case Decoder::VOpIVvOpcode::kVsubvv: return OpVectorvv<intrinsics::Vsubvv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVandvv: + case Decoder::VOpIVvOpcode::kVandvv: return OpVectorvv<intrinsics::Vandvv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVorvv: + case Decoder::VOpIVvOpcode::kVorvv: return OpVectorvv<intrinsics::Vorvv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVxorvv: + case Decoder::VOpIVvOpcode::kVxorvv: return OpVectorvv<intrinsics::Vxorvv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmseqvv: + case Decoder::VOpIVvOpcode::kVmseqvv: return OpVectorvv<intrinsics::Vmseqvv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsnevv: + case Decoder::VOpIVvOpcode::kVmsnevv: return OpVectorvv<intrinsics::Vmsnevv<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsltuvv: + case Decoder::VOpIVvOpcode::kVmsltuvv: return OpVectorvv<intrinsics::Vmsltvv<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsltvv: + case Decoder::VOpIVvOpcode::kVmsltvv: return OpVectorvv<intrinsics::Vmsltvv<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsleuvv: + case Decoder::VOpIVvOpcode::kVmsleuvv: return OpVectorvv<intrinsics::Vmslevv<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmslevv: + case Decoder::VOpIVvOpcode::kVmslevv: return OpVectorvv<intrinsics::Vmslevv<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, args.src2); + case Decoder::VOpIVvOpcode::kVsllvv: + return OpVectorvv<intrinsics::Vsllvv<ElementType, vta>, ElementType, vlmul, vta>( + args.dst, args.src1, args.src2); default: Unimplemented(); } } template <typename ElementType, VectorRegisterGroupMultiplier vlmul, TailProcessing vta> - void OpVector(const Decoder::VOpVxArgs& args, Register arg2) { + void OpVector(const Decoder::VOpIVxArgs& args, Register arg2) { switch (args.opcode) { - case Decoder::VOpVxOpcode::kVaddvx: + case Decoder::VOpIVxOpcode::kVaddvx: return OpVectorvx<intrinsics::Vaddvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVsubvx: + case Decoder::VOpIVxOpcode::kVsubvx: return OpVectorvx<intrinsics::Vsubvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVrsubvx: + case Decoder::VOpIVxOpcode::kVrsubvx: return OpVectorvx<intrinsics::Vrsubvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVandvx: + case Decoder::VOpIVxOpcode::kVandvx: return OpVectorvx<intrinsics::Vandvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVorvx: + case Decoder::VOpIVxOpcode::kVorvx: return OpVectorvx<intrinsics::Vorvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVxorvx: + case Decoder::VOpIVxOpcode::kVxorvx: return OpVectorvx<intrinsics::Vxorvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmseqvx: + case Decoder::VOpIVxOpcode::kVmseqvx: return OpVectorvx<intrinsics::Vmseqvx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsnevx: + case Decoder::VOpIVxOpcode::kVmsnevx: return OpVectorvx<intrinsics::Vmsnevx<ElementType, vta>, ElementType, vlmul, vta>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsltuvx: + case Decoder::VOpIVxOpcode::kVmsltuvx: return OpVectorvx<intrinsics::Vmsltvx<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsltvx: + case Decoder::VOpIVxOpcode::kVmsltvx: return OpVectorvx<intrinsics::Vmsltvx<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsleuvx: + case Decoder::VOpIVxOpcode::kVmsleuvx: return OpVectorvx<intrinsics::Vmslevx<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmslevx: + case Decoder::VOpIVxOpcode::kVmslevx: return OpVectorvx<intrinsics::Vmslevx<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsgtuvx: + case Decoder::VOpIVxOpcode::kVmsgtuvx: return OpVectorvx<intrinsics::Vmsgtvx<std::make_unsigned_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsgtvx: + case Decoder::VOpIVxOpcode::kVmsgtvx: return OpVectorvx<intrinsics::Vmsgtvx<std::make_signed_t<ElementType>, vta>, ElementType, vlmul, vta>(args.dst, args.src1, arg2); + case Decoder::VOpIVxOpcode::kVsllvx: + return OpVectorvx<intrinsics::Vsllvx<ElementType, vta>, ElementType, vlmul, vta>( + args.dst, args.src1, arg2); default: Unimplemented(); } @@ -763,59 +772,62 @@ class Interpreter { VectorRegisterGroupMultiplier vlmul, TailProcessing vta, InactiveProcessing vma> - void OpVector(const Decoder::VOpViArgs& args) { + void OpVector(const Decoder::VOpIViArgs& args) { switch (args.opcode) { - case Decoder::VOpViOpcode::kVaddvi: + case Decoder::VOpIViOpcode::kVaddvi: return OpVectorvx<intrinsics::Vaddvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVrsubvi: + case Decoder::VOpIViOpcode::kVrsubvi: return OpVectorvx<intrinsics::Vrsubvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVandvi: + case Decoder::VOpIViOpcode::kVandvi: return OpVectorvx<intrinsics::Vandvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVorvi: + case Decoder::VOpIViOpcode::kVorvi: return OpVectorvx<intrinsics::Vorvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVxorvi: + case Decoder::VOpIViOpcode::kVxorvi: return OpVectorvx<intrinsics::Vxorvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmseqvi: + case Decoder::VOpIViOpcode::kVmseqvi: return OpVectorvx<intrinsics::Vmseqvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsnevi: + case Decoder::VOpIViOpcode::kVmsnevi: return OpVectorvx<intrinsics::Vmsnevxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsleuvi: + case Decoder::VOpIViOpcode::kVmsleuvi: return OpVectorvx<intrinsics::Vmslevxm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmslevi: + case Decoder::VOpIViOpcode::kVmslevi: return OpVectorvx<intrinsics::Vmslevxm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsgtuvi: + case Decoder::VOpIViOpcode::kVmsgtuvi: return OpVectorvx<intrinsics::Vmsgtvxm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src, args.imm); - case Decoder::VOpViOpcode::kVmsgtvi: + case Decoder::VOpIViOpcode::kVmsgtvi: return OpVectorvx<intrinsics::Vmsgtvxm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src, args.imm); + case Decoder::VOpIViOpcode::kVsllvi: + return OpVectorvx<intrinsics::Vsllvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( + args.dst, args.src, args.imm); default: Unimplemented(); } @@ -825,59 +837,62 @@ class Interpreter { VectorRegisterGroupMultiplier vlmul, TailProcessing vta, InactiveProcessing vma> - void OpVector(const Decoder::VOpVvArgs& args) { + void OpVector(const Decoder::VOpIVvArgs& args) { switch (args.opcode) { - case Decoder::VOpVvOpcode::kVaddvv: + case Decoder::VOpIVvOpcode::kVaddvv: return OpVectorvv<intrinsics::Vaddvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVsubvv: + case Decoder::VOpIVvOpcode::kVsubvv: return OpVectorvv<intrinsics::Vsubvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVandvv: + case Decoder::VOpIVvOpcode::kVandvv: return OpVectorvv<intrinsics::Vandvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVorvv: + case Decoder::VOpIVvOpcode::kVorvv: return OpVectorvv<intrinsics::Vorvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVxorvv: + case Decoder::VOpIVvOpcode::kVxorvv: return OpVectorvv<intrinsics::Vxorvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmseqvv: + case Decoder::VOpIVvOpcode::kVmseqvv: return OpVectorvv<intrinsics::Vmseqvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsnevv: + case Decoder::VOpIVvOpcode::kVmsnevv: return OpVectorvv<intrinsics::Vmsnevvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsltuvv: + case Decoder::VOpIVvOpcode::kVmsltuvv: return OpVectorvv<intrinsics::Vmsltvvm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsltvv: + case Decoder::VOpIVvOpcode::kVmsltvv: return OpVectorvv<intrinsics::Vmsltvvm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmsleuvv: + case Decoder::VOpIVvOpcode::kVmsleuvv: return OpVectorvv<intrinsics::Vmslevvm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, args.src2); - case Decoder::VOpVvOpcode::kVmslevv: + case Decoder::VOpIVvOpcode::kVmslevv: return OpVectorvv<intrinsics::Vmslevvm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, args.src2); + case Decoder::VOpIVvOpcode::kVsllvv: + return OpVectorvv<intrinsics::Vsllvvm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( + args.dst, args.src1, args.src2); default: Unimplemented(); } @@ -887,74 +902,77 @@ class Interpreter { VectorRegisterGroupMultiplier vlmul, TailProcessing vta, InactiveProcessing vma> - void OpVector(const Decoder::VOpVxArgs& args, Register arg2) { + void OpVector(const Decoder::VOpIVxArgs& args, Register arg2) { switch (args.opcode) { - case Decoder::VOpVxOpcode::kVaddvx: + case Decoder::VOpIVxOpcode::kVaddvx: return OpVectorvx<intrinsics::Vaddvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVsubvx: + case Decoder::VOpIVxOpcode::kVsubvx: return OpVectorvx<intrinsics::Vsubvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVrsubvx: + case Decoder::VOpIVxOpcode::kVrsubvx: return OpVectorvx<intrinsics::Vrsubvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVandvx: + case Decoder::VOpIVxOpcode::kVandvx: return OpVectorvx<intrinsics::Vandvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVorvx: + case Decoder::VOpIVxOpcode::kVorvx: return OpVectorvx<intrinsics::Vorvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVxorvx: + case Decoder::VOpIVxOpcode::kVxorvx: return OpVectorvx<intrinsics::Vxorvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmseqvx: + case Decoder::VOpIVxOpcode::kVmseqvx: return OpVectorvx<intrinsics::Vmseqvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsnevx: + case Decoder::VOpIVxOpcode::kVmsnevx: return OpVectorvx<intrinsics::Vmsnevxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsltuvx: + case Decoder::VOpIVxOpcode::kVmsltuvx: return OpVectorvx<intrinsics::Vmsltvxm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsltvx: + case Decoder::VOpIVxOpcode::kVmsltvx: return OpVectorvx<intrinsics::Vmsltvxm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsleuvx: + case Decoder::VOpIVxOpcode::kVmsleuvx: return OpVectorvx<intrinsics::Vmslevxm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmslevx: + case Decoder::VOpIVxOpcode::kVmslevx: return OpVectorvx<intrinsics::Vmslevxm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsgtuvx: + case Decoder::VOpIVxOpcode::kVmsgtuvx: return OpVectorvx<intrinsics::Vmsgtvxm<std::make_unsigned_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); - case Decoder::VOpVxOpcode::kVmsgtvx: + case Decoder::VOpIVxOpcode::kVmsgtvx: return OpVectorvx<intrinsics::Vmsgtvxm<std::make_signed_t<ElementType>, vta, vma>, ElementType, vlmul, vta, vma>(args.dst, args.src1, arg2); + case Decoder::VOpIVxOpcode::kVsllvx: + return OpVectorvx<intrinsics::Vsllvxm<ElementType, vta, vma>, ElementType, vlmul, vta, vma>( + args.dst, args.src1, arg2); default: Unimplemented(); } diff --git a/interpreter/riscv64/interpreter_test.cc b/interpreter/riscv64/interpreter_test.cc index dc4df358..49ed2776 100644 --- a/interpreter/riscv64/interpreter_test.cc +++ b/interpreter/riscv64/interpreter_test.cc @@ -423,7 +423,7 @@ TEST_F(Riscv64InterpreterTest, AtomicStoreInstructionDifferentLoadFailure) { TEST_F(Riscv64InterpreterTest, TestVadd) { TestVectorInstruction( - 0x10c0457, // Vadd.vv v8, v16, v24, v0.t + 0x10c0457, // Vadd.vv v8, v16, v24, v0.t {{0, 3, 6, 9, 13, 15, 18, 21, 25, 27, 30, 33, 36, 39, 42, 45}, {48, 51, 54, 57, 61, 63, 66, 69, 73, 75, 78, 81, 84, 87, 90, 93}, {96, 99, 102, 105, 109, 111, 114, 117, 121, 123, 126, 129, 132, 135, 138, 141}, @@ -457,7 +457,7 @@ TEST_F(Riscv64InterpreterTest, TestVadd) { {0x3633'302e'2a27'2420, 0x4e4b'4845'423f'3c39}, {0x6663'605e'5a57'5450, 0x7e7b'7875'726f'6c69}}); TestVectorInstruction( - 0x100c457, // Vadd.vv v8, v16, x1, v0.t + 0x100c457, // Vadd.vx v8, v16, x1, v0.t {{170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185}, {186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201}, {202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217}, @@ -491,7 +491,7 @@ TEST_F(Riscv64InterpreterTest, TestVadd) { {0x1211'100f'0e0d'0c0a, 0x1a19'1817'1615'1412}, {0x2221'201f'1e1d'1c1a, 0x2a29'2827'2625'2422}}); TestVectorInstruction( - 0x10ab457, // Vadd.vv v8, v16, -0xb, v0.t + 0x10ab457, // Vadd.vi v8, v16, -0xb, v0.t {{245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 0, 1, 2, 3, 4}, {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, {21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36}, @@ -1680,6 +1680,111 @@ TEST_F(Riscv64InterpreterTest, TestVmsgt) { kVectorComparisonSource); } +TEST_F(Riscv64InterpreterTest, TestVsll) { + TestVectorInstruction( + 0x950c0457, // Vsll.vv v8, v16, v24, v0.t + {{0, 4, 32, 192, 8, 20, 96, 192, 16, 36, 160, 192, 12, 52, 224, 192}, + {16, 68, 32, 192, 40, 84, 96, 192, 48, 100, 160, 192, 28, 116, 224, 192}, + {32, 132, 32, 192, 72, 148, 96, 192, 80, 164, 160, 192, 44, 180, 224, 192}, + {48, 196, 32, 192, 104, 212, 96, 192, 112, 228, 160, 192, 60, 244, 224, 192}, + {64, 4, 32, 192, 136, 20, 96, 192, 144, 36, 160, 192, 76, 52, 224, 192}, + {80, 68, 32, 192, 168, 84, 96, 192, 176, 100, 160, 192, 92, 116, 224, 192}, + {96, 132, 32, 192, 200, 148, 96, 192, 208, 164, 160, 192, 108, 180, 224, 192}, + {112, 196, 32, 192, 232, 212, 96, 192, 240, 228, 160, 192, 124, 244, 224, 192}}, + {{0x0100, 0x3020, 0x0800, 0x6000, 0x1210, 0xb0a0, 0x0c00, 0xe000}, + {0x1110, 0x3120, 0x2800, 0x6000, 0x3230, 0xb1a0, 0x1c00, 0xe000}, + {0x2120, 0x3220, 0x4800, 0x6000, 0x5250, 0xb2a0, 0x2c00, 0xe000}, + {0x3130, 0x3320, 0x6800, 0x6000, 0x7270, 0xb3a0, 0x3c00, 0xe000}, + {0x4140, 0x3420, 0x8800, 0x6000, 0x9290, 0xb4a0, 0x4c00, 0xe000}, + {0x5150, 0x3520, 0xa800, 0x6000, 0xb2b0, 0xb5a0, 0x5c00, 0xe000}, + {0x6160, 0x3620, 0xc800, 0x6000, 0xd2d0, 0xb6a0, 0x6c00, 0xe000}, + {0x7170, 0x3720, 0xe800, 0x6000, 0xf2f0, 0xb7a0, 0x7c00, 0xe000}}, + {{0x0302'0100, 0x0c0a'0800, 0x1210'0000, 0x0c00'0000}, + {0x1312'1110, 0x2c2a'2800, 0x3230'0000, 0x1c00'0000}, + {0x2322'2120, 0x4c4a'4800, 0x5250'0000, 0x2c00'0000}, + {0x3332'3130, 0x6c6a'6800, 0x7270'0000, 0x3c00'0000}, + {0x4342'4140, 0x8c8a'8800, 0x9290'0000, 0x4c00'0000}, + {0x5352'5150, 0xacaa'a800, 0xb2b0'0000, 0x5c00'0000}, + {0x6362'6160, 0xccca'c800, 0xd2d0'0000, 0x6c00'0000}, + {0x7372'7170, 0xecea'e800, 0xf2f0'0000, 0x7c00'0000}}, + {{0x0706'0504'0302'0100, 0x1a18'1614'1210'0000}, + {0x1312'1110'0000'0000, 0x3230'0000'0000'0000}, + {0x2726'2524'2322'2120, 0x5a58'5654'5250'0000}, + {0x3332'3130'0000'0000, 0x7270'0000'0000'0000}, + {0x4746'4544'4342'4140, 0x9a98'9694'9290'0000}, + {0x5352'5150'0000'0000, 0xb2b0'0000'0000'0000}, + {0x6766'6564'6362'6160, 0xdad8'd6d4'd2d0'0000}, + {0x7372'7170'0000'0000, 0xf2f0'0000'0000'0000}}); + TestVectorInstruction( + 0x9500c457, // Vsll.vx v8, v16, x1, v0.t + {{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60}, + {64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124}, + {128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188}, + {192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252}, + {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60}, + {64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124}, + {128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188}, + {192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252}}, + {{0x0000, 0x0800, 0x1000, 0x1800, 0x2000, 0x2800, 0x3000, 0x3800}, + {0x4000, 0x4800, 0x5000, 0x5800, 0x6000, 0x6800, 0x7000, 0x7800}, + {0x8000, 0x8800, 0x9000, 0x9800, 0xa000, 0xa800, 0xb000, 0xb800}, + {0xc000, 0xc800, 0xd000, 0xd800, 0xe000, 0xe800, 0xf000, 0xf800}, + {0x0000, 0x0800, 0x1000, 0x1800, 0x2000, 0x2800, 0x3000, 0x3800}, + {0x4000, 0x4800, 0x5000, 0x5800, 0x6000, 0x6800, 0x7000, 0x7800}, + {0x8000, 0x8800, 0x9000, 0x9800, 0xa000, 0xa800, 0xb000, 0xb800}, + {0xc000, 0xc800, 0xd000, 0xd800, 0xe000, 0xe800, 0xf000, 0xf800}}, + {{0x0804'0000, 0x1814'1000, 0x2824'2000, 0x3834'3000}, + {0x4844'4000, 0x5854'5000, 0x6864'6000, 0x7874'7000}, + {0x8884'8000, 0x9894'9000, 0xa8a4'a000, 0xb8b4'b000}, + {0xc8c4'c000, 0xd8d4'd000, 0xe8e4'e000, 0xf8f4'f000}, + {0x0905'0000, 0x1915'1000, 0x2925'2000, 0x3935'3000}, + {0x4945'4000, 0x5955'5000, 0x6965'6000, 0x7975'7000}, + {0x8985'8000, 0x9995'9000, 0xa9a5'a000, 0xb9b5'b000}, + {0xc9c5'c000, 0xd9d5'd000, 0xe9e5'e000, 0xf9f5'f000}}, + {{0x0804'0000'0000'0000, 0x2824'2000'0000'0000}, + {0x4844'4000'0000'0000, 0x6864'6000'0000'0000}, + {0x8884'8000'0000'0000, 0xa8a4'a000'0000'0000}, + {0xc8c4'c000'0000'0000, 0xe8e4'e000'0000'0000}, + {0x0905'0000'0000'0000, 0x2925'2000'0000'0000}, + {0x4945'4000'0000'0000, 0x6965'6000'0000'0000}, + {0x8985'8000'0000'0000, 0xa9a5'a000'0000'0000}, + {0xc9c5'c000'0000'0000, 0xe9e5'e000'0000'0000}}); + TestVectorInstruction( + 0x9505b457, // Vsll.vi v8, v16, 0xb, v0.t + {{0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120}, + {128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120}, + {128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120}, + {128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120}, + {128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248}}, + {{0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000}, + {0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000}, + {0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000}, + {0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000}, + {0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000}, + {0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000}, + {0x0000, 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000}, + {0x8000, 0x9000, 0xa000, 0xb000, 0xc000, 0xd000, 0xe000, 0xf000}}, + {{0x1008'0000, 0x3028'2000, 0x5048'4000, 0x7068'6000}, + {0x9088'8000, 0xb0a8'a000, 0xd0c8'c000, 0xf0e8'e000}, + {0x1109'0000, 0x3129'2000, 0x5149'4000, 0x7169'6000}, + {0x9189'8000, 0xb1a9'a000, 0xd1c9'c000, 0xf1e9'e000}, + {0x120a'0000, 0x322a'2000, 0x524a'4000, 0x726a'6000}, + {0x928a'8000, 0xb2aa'a000, 0xd2ca'c000, 0xf2ea'e000}, + {0x130b'0000, 0x332b'2000, 0x534b'4000, 0x736b'6000}, + {0x938b'8000, 0xb3ab'a000, 0xd3cb'c000, 0xf3eb'e000}}, + {{0x3028'2018'1008'0000, 0x7068'6058'5048'4000}, + {0xb0a8'a098'9088'8000, 0xf0e8'e0d8'd0c8'c000}, + {0x3129'2119'1109'0000, 0x7169'6159'5149'4000}, + {0xb1a9'a199'9189'8000, 0xf1e9'e1d9'd1c9'c000}, + {0x322a'221a'120a'0000, 0x726a'625a'524a'4000}, + {0xb2aa'a29a'928a'8000, 0xf2ea'e2da'd2ca'c000}, + {0x332b'231b'130b'0000, 0x736b'635b'534b'4000}, + {0xb3ab'a39b'938b'8000, 0xf3eb'e3db'd3cb'c000}}); +} + } // namespace } // namespace berberis diff --git a/intrinsics/common_to_x86/gen_text_asm_intrinsics.cc b/intrinsics/common_to_x86/gen_text_asm_intrinsics.cc index 4459623b..67816881 100644 --- a/intrinsics/common_to_x86/gen_text_asm_intrinsics.cc +++ b/intrinsics/common_to_x86/gen_text_asm_intrinsics.cc @@ -602,7 +602,9 @@ void GenerateTextAsmIntrinsics(FILE* out) { intrinsics::bindings::kNoCPUIDRestriction; bool if_opened = false; std::string running_name; - ProcessAllBindings<TextAssemblerX86<TextAssembler>, TextAssembler, MacroAssembler<TextAssembler>>( + ProcessAllBindings<TextAssemblerX86<TextAssembler>, + TextAssembler, + MacroAssembler<TextAssembler>::MacroAssemblers>( [&running_name, &if_opened, &cpuid_restriction, out](auto&& asm_call_generator) { using AsmCallInfo = std::decay_t<decltype(asm_call_generator)>; std::string full_name = std::string(asm_call_generator.kIntrinsic, diff --git a/intrinsics/gen_intrinsics.py b/intrinsics/gen_intrinsics.py index 7cc8f95b..2d56a66b 100755 --- a/intrinsics/gen_intrinsics.py +++ b/intrinsics/gen_intrinsics.py @@ -950,7 +950,7 @@ def _gen_c_intrinsic(name, yield ' %s>(),' % ( ',\n '.join( [name_label, - _get_asm_reference(asm, gen_builder), + _get_asm_reference(asm), mnemo_label, _get_builder_reference(intr, asm) if gen_builder else 'void', cpuid_restriction, @@ -997,7 +997,7 @@ def _get_asm_operand_type(arg, prefix=''): assert False -def _get_asm_reference(asm, gen_builder): +def _get_asm_reference(asm): # Because of misfeature of Itanium C++ ABI we couldn't just use MacroAssembler # to static cast these references if we want to use them as template argument: # https://ibob.bg/blog/2018/08/18/a-bug-in-the-cpp-standard/ @@ -1015,14 +1015,8 @@ def _get_asm_reference(asm, gen_builder): # &Assembler_common_x86::Lzcntl) if 'arch' in asm: assembler = 'Assembler_%s' % asm['arch'] - elif gen_builder: - assembler = 'std::tuple_element_t<0, MacroAssembler>' - elif any(arg['class'].startswith('Imm') for arg in asm['args']): - assembler = 'MacroAssembler' else: - return '&MacroAssembler::%s%s' % ( - 'template ' if '<' in asm['asm'] else '', - asm['asm']) + assembler = 'std::tuple_element_t<%s, MacroAssembler>' % asm['macroassembler'] return 'static_cast<void (%s::*)(%s)>(%s&%s::%s%s)' % ( assembler, _get_asm_type(asm, 'typename %s::' % assembler), @@ -1054,11 +1048,14 @@ def _load_intrs_arch_def(intrs_defs): return json_data -def _load_macro_def(intrs, arch_intrs, insns_def): +def _load_macro_def(intrs, arch_intrs, insns_def, macroassembler): arch, insns = asm_defs.load_asm_defs(insns_def) if arch is not None: for insn in insns: insn['arch'] = arch + else: + for insn in insns: + insn['macroassembler'] = macroassembler insns_map = dict((insn['name'], insn) for insn in insns) unprocessed_intrs = [] for arch_intr in arch_intrs: @@ -1136,10 +1133,13 @@ def _open_asm_def_files(def_files, arch_def_files, asm_def_files, need_archs=Tru expanded_intrs = _expand_template_intrinsics(intrs) arch_intrs = _load_intrs_arch_def(arch_def_files) archs = [] + macro_assemblers = 0 for macro_def in asm_def_files: - arch, arch_intrs = _load_macro_def(expanded_intrs, arch_intrs, macro_def) + arch, arch_intrs = _load_macro_def(expanded_intrs, arch_intrs, macro_def, macro_assemblers) if arch is not None: archs.append(arch) + else: + macro_assemblers += 1 # Make sure that all intrinsics were found during processing of arch_intrs. assert arch_intrs == [] if need_archs: diff --git a/intrinsics/riscv64/include/berberis/intrinsics/riscv64/vector_intrinsics.h b/intrinsics/riscv64/include/berberis/intrinsics/riscv64/vector_intrinsics.h index ed5cdd00..48c32d1a 100644 --- a/intrinsics/riscv64/include/berberis/intrinsics/riscv64/vector_intrinsics.h +++ b/intrinsics/riscv64/include/berberis/intrinsics/riscv64/vector_intrinsics.h @@ -93,13 +93,13 @@ inline std::tuple<SIMD128Register> VectorArithmetic(Lambda lambda, result.Set<ElementType>(lambda(VectorElement<ElementType>(source, index)...), index); } } else { - #pragma clang loop unroll(disable) +#pragma clang loop unroll(disable) for (int index = vstart; index < vl; ++index) { result.Set<ElementType>(lambda(VectorElement<ElementType>(source, index)...), index); } if constexpr (vta == TailProcessing::kAgnostic) { if (vl < static_cast<int>(16 / sizeof(ElementType))) { - #pragma clang loop unroll(disable) +#pragma clang loop unroll(disable) for (int index = vl; index < 16 / static_cast<int>(sizeof(ElementType)); ++index) { result.Set<ElementType>(fill_value, index); } @@ -137,7 +137,7 @@ inline std::tuple<SIMD128Register> VectorArithmetic(Lambda lambda, if (vl > static_cast<int>(16 / sizeof(ElementType))) { vl = 16 / sizeof(ElementType); } - #pragma clang loop unroll(disable) +#pragma clang loop unroll(disable) for (int index = vstart; index < vl; ++index) { if (mask & (1 << index)) { result.Set<ElementType>(lambda(VectorElement<ElementType>(source, index)...), index); @@ -147,7 +147,7 @@ inline std::tuple<SIMD128Register> VectorArithmetic(Lambda lambda, } if constexpr (vta == TailProcessing::kAgnostic) { if (vl < static_cast<int>(16 / sizeof(ElementType))) { - #pragma clang loop unroll(disable) +#pragma clang loop unroll(disable) for (int index = vl; index < 16 / static_cast<int>(sizeof(ElementType)); ++index) { result.Set<ElementType>(fill_value, index); } @@ -156,6 +156,22 @@ inline std::tuple<SIMD128Register> VectorArithmetic(Lambda lambda, return result; } +template <typename ElementType> +inline ElementType mask_bits(ElementType val) { + // Return only the low n-bits of val, where n is log2(SEW) and SEW is standard element width. + if constexpr (sizeof(ElementType) <= sizeof(uint8_t)) { + return val & ((1 << 3) - 1); + } else if constexpr (sizeof(ElementType) <= sizeof(uint16_t)) { + return val & ((1 << 4) - 1); + } else if constexpr (sizeof(ElementType) <= sizeof(uint32_t)) { + return val & ((1 << 5) - 1); + } else if constexpr (sizeof(ElementType) <= sizeof(uint64_t)) { + return val & ((1 << 6) - 1); + } else { + static_assert(kDependentTypeFalse<ElementType>, "Unsupported vector element type"); + } +} + #define DEFINE_ARITHMETIC_PARAMETERS_OR_ARGUMENTS(...) __VA_ARGS__ #define DEFINE_ARITHMETIC_INTRINSIC(Name, arithmetic, parameters, arguments) \ \ @@ -226,6 +242,10 @@ DEFINE_2OP_ARITHMETIC_INTRINSIC_VX(mslt, (args < ...)) DEFINE_2OP_ARITHMETIC_INTRINSIC_VV(msle, (args <= ...)) DEFINE_2OP_ARITHMETIC_INTRINSIC_VX(msle, (args <= ...)) DEFINE_2OP_ARITHMETIC_INTRINSIC_VX(msgt, (args > ...)) +DEFINE_2OP_ARITHMETIC_INTRINSIC_VV(sll, auto [arg1, arg2] = std::tuple{args...}; + (arg1 << mask_bits(arg2))) +DEFINE_2OP_ARITHMETIC_INTRINSIC_VX(sll, auto [arg1, arg2] = std::tuple{args...}; + (arg1 << mask_bits(arg2))) #undef DEFINE_ARITHMETIC_INTRINSIC #undef DEFINE_ARITHMETIC_PARAMETERS_OR_ARGUMENTS diff --git a/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler.h b/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler.h index 991253b5..1b903ba5 100644 --- a/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler.h +++ b/intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler.h @@ -32,6 +32,8 @@ namespace berberis { template <typename Assembler> class MacroAssembler : public Assembler { public: + using MacroAssemblers = std::tuple<MacroAssembler<Assembler>>; + template <typename... Args> explicit MacroAssembler(Args&&... args) : Assembler(std::forward<Args>(args)...) { } diff --git a/native_bridge/native_bridge.cc b/native_bridge/native_bridge.cc index 1947ee4f..fc089f22 100644 --- a/native_bridge/native_bridge.cc +++ b/native_bridge/native_bridge.cc @@ -21,10 +21,16 @@ #include <stdio.h> #include <sys/system_properties.h> +#include <deque> +#include <map> +#include <mutex> +#include <set> +#include <string> #include <string_view> #include "procinfo/process_map.h" +#include "berberis/base/algorithm.h" #include "berberis/base/bit_util.h" #include "berberis/base/config_globals.h" #include "berberis/base/logging.h" @@ -42,6 +48,39 @@ #define LOG_NB ALOGV // redefine to ALOGD for debugging +extern "C" { + +// Extended android loader functions for namespace management + +bool android_init_anonymous_namespace(const char* shared_libs_sonames, + const char* library_search_path); + +struct android_namespace_t* android_create_namespace(const char* name, + const char* ld_library_path, + const char* default_library_path, + uint64_t type, + const char* permitted_when_isolated_path, + struct android_namespace_t* parent); + +bool android_link_namespaces(struct android_namespace_t* from, + struct android_namespace_t* to, + const char* shared_libs_sonames); + +struct android_namespace_t* android_get_exported_namespace(const char* name); + +} // extern "C" + +namespace android { + +// We maintain host namespace here to provide ability to open host +// libraries via native bridge. See http://b/308371292 for details. +struct native_bridge_namespace_t { + android_namespace_t* guest_namespace; + android_namespace_t* host_namespace; +}; + +} // namespace android + namespace { // See android/system/core/libnativebridge/native_bridge.cc @@ -54,17 +93,12 @@ const constexpr uint32_t kNativeBridgeCallbackMaxVersion = kNativeBridgeCallback const android::NativeBridgeRuntimeCallbacks* g_runtime_callbacks = nullptr; +using native_bridge_namespace_t = android::native_bridge_namespace_t; +using GuestAddr = berberis::GuestAddr; + // Treble uses "sphal" name for the vendor namespace. constexpr const char* kVendorNamespaceName = "sphal"; -android::native_bridge_namespace_t* ToNbNamespace(android_namespace_t* android_ns) { - return reinterpret_cast<android::native_bridge_namespace_t*>(android_ns); -} - -android_namespace_t* ToAndroidNamespace(android::native_bridge_namespace_t* nb_ns) { - return reinterpret_cast<android_namespace_t*>(nb_ns); -} - class NdktNativeBridge { public: NdktNativeBridge(); @@ -72,26 +106,37 @@ class NdktNativeBridge { bool Initialize(std::string* error_msg); void* LoadLibrary(const char* libpath, int flags); - void* LoadLibrary(const char* libpath, int flags, const android_dlextinfo* extinfo); - berberis::GuestAddr DlSym(void* handle, const char* name); + void* LoadLibrary(const char* libpath, int flags, const native_bridge_namespace_t* ns); + GuestAddr DlSym(void* handle, const char* name); const char* DlError(); bool InitAnonymousNamespace(const char* public_ns_sonames, const char* anon_ns_library_path); - android::native_bridge_namespace_t* CreateNamespace( - const char* name, - const char* ld_library_path, - const char* default_library_path, - uint64_t type, - const char* permitted_when_isolated_path, - android::native_bridge_namespace_t* parent_ns); - android::native_bridge_namespace_t* GetExportedNamespace(const char* name); - bool LinkNamespaces(android::native_bridge_namespace_t* from, - android::native_bridge_namespace_t* to, + native_bridge_namespace_t* CreateNamespace(const char* name, + const char* ld_library_path, + const char* default_library_path, + uint64_t type, + const char* permitted_when_isolated_path, + native_bridge_namespace_t* parent_ns); + native_bridge_namespace_t* GetExportedNamespace(const char* name); + bool LinkNamespaces(native_bridge_namespace_t* from, + native_bridge_namespace_t* to, const char* shared_libs_sonames); + bool IsHostHandle(void* handle) const; + private: bool FinalizeInit(); + native_bridge_namespace_t* CreateNativeBridgeNamespace(android_namespace_t* host_namespace, + android_namespace_t* guest_namespace); + void AddHostLibrary(void* handle); berberis::GuestLoader* guest_loader_; + + mutable std::mutex host_libraries_lock_; + std::set<void*> host_libraries_; + + std::mutex namespaces_lock_; + std::deque<native_bridge_namespace_t> namespaces_; + std::map<std::string, native_bridge_namespace_t> exported_namespaces_; }; NdktNativeBridge::NdktNativeBridge() : guest_loader_(nullptr) {} @@ -112,51 +157,139 @@ void* NdktNativeBridge::LoadLibrary(const char* libpath, int flags) { void* NdktNativeBridge::LoadLibrary(const char* libpath, int flags, - const android_dlextinfo* extinfo) { + const native_bridge_namespace_t* ns) { // We don't have a callback after all java initialization is finished. So we call the finalizing // routine from here, just before we load any app's native code. static bool init_finalized = FinalizeInit(); UNUSED(init_finalized); - return guest_loader_->DlOpenExt(libpath, flags, extinfo); + + android_dlextinfo extinfo_holder; + android_dlextinfo* extinfo = nullptr; + + if (ns != nullptr) { + extinfo_holder.flags = ANDROID_DLEXT_USE_NAMESPACE; + extinfo_holder.library_namespace = ns->guest_namespace; + extinfo = &extinfo_holder; + } + + void* handle = guest_loader_->DlOpenExt(libpath, flags, extinfo); + if (handle == nullptr) { + // Try falling back to host loader. + if (ns != nullptr) { + extinfo_holder.library_namespace = ns->host_namespace; + } + handle = android_dlopen_ext(libpath, flags, extinfo); + if (handle != nullptr) { + ALOGI("'%s' library was loaded for the host platform.", libpath); + AddHostLibrary(handle); + } + } + + return handle; +} + +void NdktNativeBridge::AddHostLibrary(void* handle) { + const std::lock_guard<std::mutex> guard(host_libraries_lock_); + host_libraries_.insert(handle); +} + +bool NdktNativeBridge::IsHostHandle(void* handle) const { + const std::lock_guard<std::mutex> guard(host_libraries_lock_); + return berberis::Contains(host_libraries_, handle); } -berberis::GuestAddr NdktNativeBridge::DlSym(void* handle, const char* name) { +GuestAddr NdktNativeBridge::DlSym(void* handle, const char* name) { + CHECK(!IsHostHandle(handle)); return guest_loader_->DlSym(handle, name); } const char* NdktNativeBridge::DlError() { - return guest_loader_->DlError(); + // There is no good way of knowing where the error happened, - prioritize the guest loader. + const char* error = guest_loader_->DlError(); + if (error != nullptr) { + return error; + } + + return dlerror(); } -android::native_bridge_namespace_t* NdktNativeBridge::CreateNamespace( +native_bridge_namespace_t* NdktNativeBridge::CreateNamespace( const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type, const char* permitted_when_isolated_path, - android::native_bridge_namespace_t* parent_ns) { - return ToNbNamespace(guest_loader_->CreateNamespace(name, - ld_library_path, - default_library_path, - type, - permitted_when_isolated_path, - ToAndroidNamespace(parent_ns))); -} + native_bridge_namespace_t* parent_ns) { + // Android SDK libraries do not have a good mechanism for using JNI libraries. + // The only way to make it work is to put them to system search path and make + // the library public (visible from apps). See http://b/308371292 for details. + // + // Since `ClassLoader.findLibrary` is looking for the library in 'java.library.path' + // in addition to paths used here it is able to find a JNI library located in system + // library path. If then such a library appears to be a public library, the android + // loader will be able to load it from the system linker namespace. + // + // It could also happen so that the app puts different architecture libraries + // in the same folder (say x86_64 libraries to arm64 folder), in which case + // they will work if the architecture happens to match with host one. This is + // why we preserve guest search path for the host namespace. + auto* host_namespace = android_create_namespace(name, + ld_library_path, + default_library_path, + type, + permitted_when_isolated_path, + parent_ns->host_namespace); + + auto* guest_namespace = guest_loader_->CreateNamespace(name, + ld_library_path, + default_library_path, + type, + permitted_when_isolated_path, + parent_ns->guest_namespace); + + return CreateNativeBridgeNamespace(host_namespace, guest_namespace); +} + +native_bridge_namespace_t* NdktNativeBridge::GetExportedNamespace(const char* name) { + const std::lock_guard<std::mutex> guard(namespaces_lock_); + auto it = exported_namespaces_.find(name); + if (it != exported_namespaces_.end()) { + return &it->second; + } -android::native_bridge_namespace_t* NdktNativeBridge::GetExportedNamespace(const char* name) { - return ToNbNamespace(guest_loader_->GetExportedNamespace(name)); + auto host_namespace = android_get_exported_namespace(name); + auto guest_namespace = guest_loader_->GetExportedNamespace(name); + + auto [insert_it, inserted] = + exported_namespaces_.try_emplace(std::string(name), + native_bridge_namespace_t{.guest_namespace = guest_namespace, + .host_namespace = host_namespace}); + CHECK(inserted); + + return &insert_it->second; } bool NdktNativeBridge::InitAnonymousNamespace(const char* public_ns_sonames, const char* anon_ns_library_path) { - return guest_loader_->InitAnonymousNamespace(public_ns_sonames, anon_ns_library_path); + return guest_loader_->InitAnonymousNamespace(public_ns_sonames, anon_ns_library_path) && + android_init_anonymous_namespace(public_ns_sonames, anon_ns_library_path); } -bool NdktNativeBridge::LinkNamespaces(android::native_bridge_namespace_t* from, - android::native_bridge_namespace_t* to, +bool NdktNativeBridge::LinkNamespaces(native_bridge_namespace_t* from, + native_bridge_namespace_t* to, const char* shared_libs_sonames) { return guest_loader_->LinkNamespaces( - ToAndroidNamespace(from), ToAndroidNamespace(to), shared_libs_sonames); + from->guest_namespace, to->guest_namespace, shared_libs_sonames) && + android_link_namespaces(from->host_namespace, to->host_namespace, shared_libs_sonames); +} + +native_bridge_namespace_t* NdktNativeBridge::CreateNativeBridgeNamespace( + android_namespace_t* host_namespace, + android_namespace_t* guest_namespace) { + const std::lock_guard<std::mutex> guard(namespaces_lock_); + namespaces_.emplace_back(native_bridge_namespace_t{.guest_namespace = guest_namespace, + .host_namespace = host_namespace}); + return &namespaces_.back(); } void ProtectMappingsFromGuest() { @@ -293,7 +426,11 @@ void* native_bridge_getTrampolineWithJNICallType(void* handle, len, jni_call_type); - berberis::GuestAddr guest_addr = g_ndkt_native_bridge.DlSym(handle, name); + if (g_ndkt_native_bridge.IsHostHandle(handle)) { + return dlsym(handle, name); + } + + GuestAddr guest_addr = g_ndkt_native_bridge.DlSym(handle, name); if (!guest_addr) { return nullptr; } @@ -374,20 +511,19 @@ bool native_bridge_initAnonymousNamespace(const char* public_ns_sonames, return g_ndkt_native_bridge.InitAnonymousNamespace(public_ns_sonames, anon_ns_library_path); } -android::native_bridge_namespace_t* native_bridge_createNamespace( - const char* name, - const char* ld_library_path, - const char* default_library_path, - uint64_t type, - const char* permitted_when_isolated_path, - android::native_bridge_namespace_t* parent_ns) { +native_bridge_namespace_t* native_bridge_createNamespace(const char* name, + const char* ld_library_path, + const char* default_library_path, + uint64_t type, + const char* permitted_when_isolated_path, + native_bridge_namespace_t* parent_ns) { LOG_NB("native_bridge_createNamespace(name=%s, path=%s)", name, ld_library_path); return g_ndkt_native_bridge.CreateNamespace( name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent_ns); } -bool native_bridge_linkNamespaces(android::native_bridge_namespace_t* from, - android::native_bridge_namespace_t* to, +bool native_bridge_linkNamespaces(native_bridge_namespace_t* from, + native_bridge_namespace_t* to, const char* shared_libs_sonames) { LOG_NB("native_bridge_linkNamespaces(from=%p, to=%p, shared_libs=%s)", from, @@ -397,25 +533,19 @@ bool native_bridge_linkNamespaces(android::native_bridge_namespace_t* from, return g_ndkt_native_bridge.LinkNamespaces(from, to, shared_libs_sonames); } -void* native_bridge_loadLibraryExt(const char* libpath, - int flag, - android::native_bridge_namespace_t* ns) { +void* native_bridge_loadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) { LOG_NB("native_bridge_loadLibraryExt(path=%s)", libpath); - android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; - extinfo.library_namespace = ToAndroidNamespace(ns); - - return g_ndkt_native_bridge.LoadLibrary(libpath, flag, &extinfo); + return g_ndkt_native_bridge.LoadLibrary(libpath, flag, ns); } -android::native_bridge_namespace_t* native_bridge_getVendorNamespace() { +native_bridge_namespace_t* native_bridge_getVendorNamespace() { LOG_NB("native_bridge_getVendorNamespace()"); // This method is retained for backwards compatibility. return g_ndkt_native_bridge.GetExportedNamespace(kVendorNamespaceName); } -android::native_bridge_namespace_t* native_bridge_getExportedNamespace(const char* name) { +native_bridge_namespace_t* native_bridge_getExportedNamespace(const char* name) { LOG_NB("native_bridge_getExportedNamespace(name=%s)", name); return g_ndkt_native_bridge.GetExportedNamespace(name); } diff --git a/runtime/execute_guest.cc b/runtime/execute_guest.cc index 1bf9746b..18d35bcb 100644 --- a/runtime/execute_guest.cc +++ b/runtime/execute_guest.cc @@ -17,6 +17,7 @@ #include "berberis/runtime/execute_guest.h" #include "berberis/base/checks.h" +#include "berberis/base/config.h" #include "berberis/base/tracing.h" #include "berberis/guest_os_primitives/guest_thread.h" #include "berberis/guest_state/guest_addr.h" @@ -53,6 +54,10 @@ void ExecuteGuest(ThreadState* state) { break; } + if (config::kTraceGeneratedCode) { + TRACE("RunGeneratedCode @ 0x%zx", pc); + } + // ATTENTION: this should be the only place to run translated code! berberis_RunGeneratedCode(state, code); } diff --git a/test_utils/include/berberis/test_utils/insn_tests_riscv64-inl.h b/test_utils/include/berberis/test_utils/insn_tests_riscv64-inl.h index 9f8dadac..43b5e9c4 100644 --- a/test_utils/include/berberis/test_utils/insn_tests_riscv64-inl.h +++ b/test_utils/include/berberis/test_utils/insn_tests_riscv64-inl.h @@ -236,6 +236,10 @@ class TESTSUITE : public ::testing::Test { EXPECT_EQ(state_.cpu.frm, expected_rm); } +#endif // defined(TESTING_INTERPRETER) || defined(TESTING_LITE_TRANSLATOR) +#if defined(TESTING_INTERPRETER) || defined(TESTING_LITE_TRANSLATOR) || \ + defined(TESTING_HEAVY_OPTIMIZER) + void TestOp(uint32_t insn_bytes, std::initializer_list<std::tuple<uint64_t, uint64_t, uint64_t>> args) { for (auto [arg1, arg2, expected_result] : args) { @@ -1753,6 +1757,7 @@ TEST_F(TESTSUITE, StoreInstructions) { #endif // defined(TESTING_INTERPRETER) || defined(TESTING_LITE_TRANSLATOR) || // defined(TESTING_HEAVY_OPTIMIZER) + #if defined(TESTING_INTERPRETER) || defined(TESTING_LITE_TRANSLATOR) TEST_F(TESTSUITE, FmaInstructions) { diff --git a/tools/symbolize_trace.py b/tools/symbolize_trace.py new file mode 100755 index 00000000..fad83907 --- /dev/null +++ b/tools/symbolize_trace.py @@ -0,0 +1,214 @@ +#!/usr/bin/python +# +# Copyright (C) 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import argparse +import bisect +import os +import subprocess +import sys + +PROT_READ = 1 +PROT_WRITE = 2 +PROT_EXEC = 4 + + +class MapEntry: + start = -1 + end = -1 + prot = 0 + offset = 0 + file = "" + base_addr = -1 + + +class TraceParser: + + def __init__(self, tombstone, trace, symbols_dir): + self.maps = {} + self.tombstone = tombstone + self.trace = trace + self.symbols_dir = symbols_dir + + def parse_prot(self, prot_str): + prot = 0 + if prot_str[0] == "r": + prot |= PROT_READ + if prot_str[1] == "w": + prot |= PROT_WRITE + if prot_str[2] == "x": + prot |= PROT_EXEC + + return prot + + def parse_tombstone_map_entry(self, line, line_number): + if not line.startswith(" ") and not line.startswith("--->"): + raise Exception( + "Unexpected line (" + line_number + ") in maps section: " + line + ) + + if line.startswith("--->Fault address"): + return + + line = line[3:] # throw away indent/prefix + + entries = line.split(maxsplit=5) + + addrs = entries[0].split("-") + map_entry = MapEntry() + map_entry.start = int(addrs[0].replace("'", ""), 16) + map_entry.end = int(addrs[1].replace("'", ""), 16) + map_entry.prot = self.parse_prot(entries[1]) + map_entry.offset = int(entries[2], 16) + map_entry.size = int(entries[3], 16) + if len(entries) >= 5: + map_entry.file = entries[4] + + # The default base address is start + map_entry.base_addr = map_entry.start + + # Skip PROT_NONE mappings so they do not interfere with + # file mappings + if map_entry.prot == 0: + return + + self.maps[map_entry.start] = map_entry + + def read_maps_from_tombstone(self): + with open(self.tombstone, "r") as f: + maps_section_started = False + line_number = 0 + for line in f: + line_number += 1 + if maps_section_started: + # Maps section ends when we hit either '---------' or end of file + if line.startswith("---------"): + break + self.parse_tombstone_map_entry(line, line_number) + else: + maps_section_started = line.startswith("memory map") + + def calculate_base_addr_for_map_entries(self): + # Ascending order of start_addr (key) is important here + last_file = None + current_base_addr = -1 + for key in sorted(self.maps): + # For now we are assuming load_bias is 0, revisit once proved otherwise + # note that load_bias printed in tombstone is incorrect atm + map = self.maps[key] + if not map.file: + continue + + # treat /memfd as if it was anon mapping + if map.file.startswith("/memfd:"): + continue + + if map.file != last_file: + last_file = map.file + current_base_addr = map.start + + map.base_addr = current_base_addr + + def addr2line(self, address, file): + if not file: + print("error: no file") + return None + + p = subprocess.run( + ["addr2line", "-e", self.symbols_dir + file, hex(address)], + capture_output=True, + text=True, + ) + if p.returncode != 0: + # print("error: ", p.stderr) + return None + return p.stdout.strip() + + def symbolize_trace(self): + with open(self.trace, "r") as f: + sorted_start_addresses = sorted(self.maps.keys()) + + for line in f: + tokens = line.split(maxsplit=2) + if len(tokens) <= 2: + continue + msg = tokens[2] + if not msg.startswith("RunGeneratedCode @"): + continue + + address = int(msg.split("@")[1].strip(), 16) + + pos = bisect.bisect_right(sorted_start_addresses, address) + map = self.maps[sorted_start_addresses[pos]] + + if address > map.end: + print("%x (not maped)" % address) + continue + + relative_addr = address - map.base_addr + + file_and_line = self.addr2line(relative_addr, map.file) + if file_and_line: + print( + "%x (%s+%x) %s" % (address, map.file, relative_addr, file_and_line) + ) + else: + print("%x (%s+%x)" % (address, map.file, relative_addr)) + + def parse(self): + self.read_maps_from_tombstone() + self.calculate_base_addr_for_map_entries() + self.symbolize_trace() + + +def get_symbol_dir(args): + if args.symbols_dir: + return symbols_dir + + product_out = os.environ.get("ANDROID_PRODUCT_OUT") + if not product_out: + raise Error( + "--symbols_dir is not set and unable to resolve ANDROID_PRODUCT_OUT via" + " environment variable" + ) + + return product_out + "/symbols" + + +def main(): + argument_parser = argparse.ArgumentParser() + argument_parser.add_argument( + "trace", help="file containing berberis trace output" + ) + # TODO(b/232598137): Make it possible to read maps from /proc/pid/maps format as an + # alternative option + argument_parser.add_argument( + "tombstone", help="Tombstone of the corresponding crash" + ) + argument_parser.add_argument( + "--symbols_dir", + help="Symbols dir (default is '$ANDROID_PRODUCT_OUT/symbols')", + ) + + args = argument_parser.parse_args() + + parser = TraceParser(args.tombstone, args.trace, get_symbol_dir(args)) + parser.parse() + + +if __name__ == "__main__": + sys.exit(main()) + |