aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-09 04:17:18 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-09 04:17:18 +0000
commit1771efed7401fd557a5bb6834c754a613bd241ff (patch)
tree4c9984e83bda6e975d9b321d5b8565617947866a
parent1a4ad5d18eedbfdedc342f817b5898e5c41219ab (diff)
parent160d6f3d4434fd8cbd006d505bc1b4b375ff3237 (diff)
downloadbinary_translation-1771efed7401fd557a5bb6834c754a613bd241ff.tar.gz
Snap for 11200327 from 160d6f3d4434fd8cbd006d505bc1b4b375ff3237 to 24Q1-release
Change-Id: Ifd8f3e34183f06bea2e83009fb222947db5b66e7
-rw-r--r--Android.bp1
-rw-r--r--base/include/berberis/base/config.h4
-rw-r--r--base/include/berberis/base/format_buffer.h8
-rw-r--r--base/tracing.cc2
-rw-r--r--decoder/include/berberis/decoder/riscv64/decoder.h30
-rw-r--r--decoder/include/berberis/decoder/riscv64/semantics_player.h6
-rw-r--r--guest_abi/include/berberis/guest_abi/function_wrappers.h77
-rw-r--r--heavy_optimizer/riscv64/frontend.cc47
-rw-r--r--interpreter/riscv64/interpreter.cc174
-rw-r--r--interpreter/riscv64/interpreter_test.cc111
-rw-r--r--intrinsics/common_to_x86/gen_text_asm_intrinsics.cc4
-rwxr-xr-xintrinsics/gen_intrinsics.py22
-rw-r--r--intrinsics/riscv64/include/berberis/intrinsics/riscv64/vector_intrinsics.h28
-rw-r--r--intrinsics/riscv64_to_x86_64/include/berberis/intrinsics/macro_assembler.h2
-rw-r--r--native_bridge/native_bridge.cc248
-rw-r--r--runtime/execute_guest.cc5
-rw-r--r--test_utils/include/berberis/test_utils/insn_tests_riscv64-inl.h5
-rwxr-xr-xtools/symbolize_trace.py214
18 files changed, 782 insertions, 206 deletions
diff --git a/Android.bp b/Android.bp
index 0b9acbc5..364e1772 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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())
+