[vm] Add `LoadThreadInstr`
Introduces a new IL instruction to load the THR register as an untagged
value in IL.
Split off from https://dart-review.googlesource.com/c/sdk/+/229544.
TEST=runtime/vm/compiler/backend/il_test.cc vm/cc/IRTest_LoadThread
Bug: https://github.com/dart-lang/sdk/issues/47777
Change-Id: Ic6bf59b05c89593773dbc91d623cd0078657c8ab
Cq-Include-Trybots: luci.dart.try:vm-kernel-win-debug-x64-try,vm-kernel-linux-debug-ia32-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/235602
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index eed551a..9cf2ade 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -1454,6 +1454,10 @@
SetValue(instr, non_constant_);
}
+void ConstantPropagator::VisitLoadThread(LoadThreadInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
void ConstantPropagator::VisitUnaryUint32Op(UnaryUint32OpInstr* instr) {
// TODO(kmillikin): Handle unary operations.
SetValue(instr, non_constant_);
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 5a742d0..e69dc63 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -13,6 +13,7 @@
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/compiler/backend/linearscan.h"
#include "vm/compiler/backend/locations.h"
+#include "vm/compiler/backend/locations_helpers.h"
#include "vm/compiler/backend/loops.h"
#include "vm/compiler/backend/range_analysis.h"
#include "vm/compiler/ffi/frame_rebase.h"
@@ -6863,6 +6864,11 @@
return marshaller_.RepInFfiCall(compiler::ffi::kResultIndex);
}
+// TODO(http://dartbug.com/48543): integrate with register allocator directly.
+DEFINE_BACKEND(LoadThread, (Register out)) {
+ __ MoveRegister(out, THR);
+}
+
// SIMD
SimdOpInstr::Kind SimdOpInstr::KindForOperator(MethodRecognizer::Kind kind) {
@@ -7038,12 +7044,10 @@
// Define the metadata array.
static const SimdOpInfo simd_op_information[] = {
-#define PP_APPLY(M, Args) M Args
#define CASE(Arity, Mask, Name, Args, Result) \
{Arity, HAS_##Mask, REP(Result), {PP_APPLY(ENCODE_INPUTS_##Arity, Args)}},
SIMD_OP_LIST(CASE, CASE)
#undef CASE
-#undef PP_APPLY
};
// Undef all auxiliary macros.
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index d8d0c57..6e916cd 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -512,6 +512,7 @@
M(BoxSmallInt, kNoGC) \
M(IntConverter, kNoGC) \
M(BitCast, kNoGC) \
+ M(LoadThread, kNoGC) \
M(Deoptimize, kNoGC) \
M(SimdOp, kNoGC)
@@ -9279,6 +9280,32 @@
DISALLOW_COPY_AND_ASSIGN(BitCastInstr);
};
+class LoadThreadInstr : public TemplateDefinition<0, NoThrow, Pure> {
+ public:
+ LoadThreadInstr() : TemplateDefinition(DeoptId::kNone) {}
+
+ virtual bool ComputeCanDeoptimize() const { return false; }
+
+ virtual Representation representation() const { return kUntagged; }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ UNREACHABLE();
+ }
+
+ virtual CompileType ComputeType() const { return CompileType::Int(); }
+
+ // CSE is allowed. The thread should always be the same value.
+ virtual bool AttributesEqual(const Instruction& other) const {
+ ASSERT(other.IsLoadThread());
+ return true;
+ }
+
+ DECLARE_INSTRUCTION(LoadThread);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoadThreadInstr);
+};
+
// SimdOpInstr
//
// All SIMD intrinsics and recognized methods are represented via instances
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index 0ce40bd..65dadc0 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -872,4 +872,84 @@
EXPECT_EQ(100, ptr2);
}
+ISOLATE_UNIT_TEST_CASE(IRTest_LoadThread) {
+ // clang-format off
+ auto kScript = R"(
+ import 'dart:ffi';
+
+ int myFunction() {
+ return 100;
+ }
+
+ void anotherFunction() {}
+ )";
+ // clang-format on
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+ Zone* const zone = Thread::Current()->zone();
+ auto& invoke_result = Instance::Handle(zone);
+ invoke_result ^= Invoke(root_library, "myFunction");
+ EXPECT_EQ(Smi::New(100), invoke_result.ptr());
+
+ const auto& my_function =
+ Function::Handle(GetFunction(root_library, "myFunction"));
+
+ TestPipeline pipeline(my_function, CompilerPass::kJIT);
+ FlowGraph* flow_graph = pipeline.RunPasses({
+ CompilerPass::kComputeSSA,
+ });
+
+ ReturnInstr* return_instr = nullptr;
+ {
+ ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
+
+ EXPECT(cursor.TryMatch({
+ kMoveGlob,
+ {kMatchReturn, &return_instr},
+ }));
+ }
+
+ auto* const load_thread_instr = new (zone) LoadThreadInstr();
+ flow_graph->InsertBefore(return_instr, load_thread_instr, nullptr,
+ FlowGraph::kValue);
+ auto load_thread_value = Value(load_thread_instr);
+
+ auto* const convert_instr = new (zone) IntConverterInstr(
+ kUntagged, kUnboxedFfiIntPtr, &load_thread_value, DeoptId::kNone);
+ flow_graph->InsertBefore(return_instr, convert_instr, nullptr,
+ FlowGraph::kValue);
+ auto convert_value = Value(convert_instr);
+
+ auto* const box_instr = BoxInstr::Create(kUnboxedFfiIntPtr, &convert_value);
+ flow_graph->InsertBefore(return_instr, box_instr, nullptr, FlowGraph::kValue);
+
+ return_instr->InputAt(0)->definition()->ReplaceUsesWith(box_instr);
+
+ {
+ // Check we constructed the right graph.
+ ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
+ EXPECT(cursor.TryMatch({
+ kMoveGlob,
+ kMatchAndMoveLoadThread,
+ kMatchAndMoveIntConverter,
+ kMatchAndMoveBox,
+ kMatchReturn,
+ }));
+ }
+
+ pipeline.RunForcedOptimizedAfterSSAPasses();
+
+ {
+#if !defined(PRODUCT)
+ SetFlagScope<bool> sfs(&FLAG_disassemble_optimized, true);
+#endif
+ pipeline.CompileGraphAndAttachFunction();
+ }
+
+ // Ensure we can successfully invoke the function.
+ invoke_result ^= Invoke(root_library, "myFunction");
+ intptr_t result_int = Integer::Cast(invoke_result).AsInt64Value();
+ EXPECT_EQ(reinterpret_cast<intptr_t>(thread), result_int);
+}
+
} // namespace dart