summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/instruction_builder.cc')
-rw-r--r--compiler/optimizing/instruction_builder.cc145
1 files changed, 145 insertions, 0 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 4364d39263..8ec28e0ab1 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1168,6 +1168,149 @@ static bool VarHandleAccessorNeedsReturnTypeCheck(HInvoke* invoke, DataType::Typ
}
}
+// This function initializes `VarHandleOptimizations`, does a number of static checks and disables
+// the intrinsic if some of the checks fail. This is necessary for the code generator to work (for
+// both the baseline and the optimizing compiler).
+static void DecideVarHandleIntrinsic(HInvoke* invoke) {
+ switch (invoke->GetIntrinsic()) {
+ case Intrinsics::kVarHandleCompareAndExchange:
+ case Intrinsics::kVarHandleCompareAndExchangeAcquire:
+ case Intrinsics::kVarHandleCompareAndExchangeRelease:
+ case Intrinsics::kVarHandleCompareAndSet:
+ case Intrinsics::kVarHandleGet:
+ case Intrinsics::kVarHandleGetAcquire:
+ case Intrinsics::kVarHandleGetAndAdd:
+ case Intrinsics::kVarHandleGetAndAddAcquire:
+ case Intrinsics::kVarHandleGetAndAddRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseAnd:
+ case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseOr:
+ case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseXor:
+ case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
+ case Intrinsics::kVarHandleGetAndSet:
+ case Intrinsics::kVarHandleGetAndSetAcquire:
+ case Intrinsics::kVarHandleGetAndSetRelease:
+ case Intrinsics::kVarHandleGetOpaque:
+ case Intrinsics::kVarHandleGetVolatile:
+ case Intrinsics::kVarHandleSet:
+ case Intrinsics::kVarHandleSetOpaque:
+ case Intrinsics::kVarHandleSetRelease:
+ case Intrinsics::kVarHandleSetVolatile:
+ case Intrinsics::kVarHandleWeakCompareAndSet:
+ case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
+ case Intrinsics::kVarHandleWeakCompareAndSetPlain:
+ case Intrinsics::kVarHandleWeakCompareAndSetRelease:
+ break;
+ default:
+ return; // Not a VarHandle intrinsic, skip.
+ }
+
+ DCHECK(invoke->IsInvokePolymorphic());
+ VarHandleOptimizations optimizations(invoke);
+
+ // Do only simple static checks here (those for which we have enough information). More complex
+ // checks should be done in instruction simplifier, which runs after other optimization passes
+ // that may provide useful information.
+
+ size_t expected_coordinates_count = GetExpectedVarHandleCoordinatesCount(invoke);
+ if (expected_coordinates_count > 2u) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ if (expected_coordinates_count != 0u) {
+ // Except for static fields (no coordinates), the first coordinate must be a reference.
+ // Do not intrinsify if the reference is null as we would always go to slow path anyway.
+ HInstruction* object = invoke->InputAt(1);
+ if (object->GetType() != DataType::Type::kReference || object->IsNullConstant()) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ }
+ if (expected_coordinates_count == 2u) {
+ // For arrays and views, the second coordinate must be convertible to `int`.
+ // In this context, `boolean` is not convertible but we have to look at the shorty
+ // as compiler transformations can give the invoke a valid boolean input.
+ DataType::Type index_type = GetDataTypeFromShorty(invoke, 2);
+ if (index_type == DataType::Type::kBool ||
+ DataType::Kind(index_type) != DataType::Type::kInt32) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ }
+
+ uint32_t number_of_arguments = invoke->GetNumberOfArguments();
+ DataType::Type return_type = invoke->GetType();
+ mirror::VarHandle::AccessModeTemplate access_mode_template =
+ mirror::VarHandle::GetAccessModeTemplateByIntrinsic(invoke->GetIntrinsic());
+ switch (access_mode_template) {
+ case mirror::VarHandle::AccessModeTemplate::kGet:
+ // The return type should be the same as varType, so it shouldn't be void.
+ if (return_type == DataType::Type::kVoid) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kSet:
+ if (return_type != DataType::Type::kVoid) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ break;
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndSet: {
+ if (return_type != DataType::Type::kBool) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+ if (expected_value_type != new_value_type) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kCompareAndExchange: {
+ uint32_t expected_value_index = number_of_arguments - 2;
+ uint32_t new_value_index = number_of_arguments - 1;
+ DataType::Type expected_value_type = GetDataTypeFromShorty(invoke, expected_value_index);
+ DataType::Type new_value_type = GetDataTypeFromShorty(invoke, new_value_index);
+ if (expected_value_type != new_value_type || return_type != expected_value_type) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ break;
+ }
+ case mirror::VarHandle::AccessModeTemplate::kGetAndUpdate: {
+ DataType::Type value_type = GetDataTypeFromShorty(invoke, number_of_arguments - 1);
+ if (IsVarHandleGetAndAdd(invoke) &&
+ (value_type == DataType::Type::kReference || value_type == DataType::Type::kBool)) {
+ // We should only add numerical types.
+ optimizations.SetDoNotIntrinsify();
+ return;
+ } else if (IsVarHandleGetAndBitwiseOp(invoke) && !DataType::IsIntegralType(value_type)) {
+ // We can only apply operators to bitwise integral types.
+ // Note that bitwise VarHandle operations accept a non-integral boolean type and
+ // perform the appropriate logical operation. However, the result is the same as
+ // using the bitwise operation on our boolean representation and this fits well
+ // with DataType::IsIntegralType() treating the compiler type kBool as integral.
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ if (value_type != return_type) {
+ optimizations.SetDoNotIntrinsify();
+ return;
+ }
+ break;
+ }
+ }
+}
+
bool HInstructionBuilder::BuildInvokePolymorphic(uint32_t dex_pc,
uint32_t method_idx,
dex::ProtoIndex proto_idx,
@@ -1217,6 +1360,8 @@ bool HInstructionBuilder::BuildInvokePolymorphic(uint32_t dex_pc,
latest_result_ = current_block_->GetLastInstruction();
}
+ DecideVarHandleIntrinsic(invoke);
+
return true;
}