You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
8.9 KiB
259 lines
8.9 KiB
/*
|
|
* Copyright (C) 2015 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.
|
|
*/
|
|
|
|
#ifndef ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
|
|
#define ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
|
|
|
|
// This `#include` should never be used by compilation, as this file (`nodes_shared.h`) is included
|
|
// in `nodes.h`. However it helps editing tools (e.g. YouCompleteMe) by giving them better context
|
|
// (defining `HInstruction` and co).
|
|
#include "nodes.h"
|
|
|
|
namespace art {
|
|
|
|
class HMultiplyAccumulate final : public HExpression<3> {
|
|
public:
|
|
HMultiplyAccumulate(DataType::Type type,
|
|
InstructionKind op,
|
|
HInstruction* accumulator,
|
|
HInstruction* mul_left,
|
|
HInstruction* mul_right,
|
|
uint32_t dex_pc = kNoDexPc)
|
|
: HExpression(kMultiplyAccumulate, type, SideEffects::None(), dex_pc),
|
|
op_kind_(op) {
|
|
SetRawInputAt(kInputAccumulatorIndex, accumulator);
|
|
SetRawInputAt(kInputMulLeftIndex, mul_left);
|
|
SetRawInputAt(kInputMulRightIndex, mul_right);
|
|
}
|
|
|
|
bool IsClonable() const override { return true; }
|
|
|
|
static constexpr int kInputAccumulatorIndex = 0;
|
|
static constexpr int kInputMulLeftIndex = 1;
|
|
static constexpr int kInputMulRightIndex = 2;
|
|
|
|
bool CanBeMoved() const override { return true; }
|
|
bool InstructionDataEquals(const HInstruction* other) const override {
|
|
return op_kind_ == other->AsMultiplyAccumulate()->op_kind_;
|
|
}
|
|
|
|
InstructionKind GetOpKind() const { return op_kind_; }
|
|
|
|
DECLARE_INSTRUCTION(MultiplyAccumulate);
|
|
|
|
protected:
|
|
DEFAULT_COPY_CONSTRUCTOR(MultiplyAccumulate);
|
|
|
|
private:
|
|
// Indicates if this is a MADD or MSUB.
|
|
const InstructionKind op_kind_;
|
|
};
|
|
|
|
class HBitwiseNegatedRight final : public HBinaryOperation {
|
|
public:
|
|
HBitwiseNegatedRight(DataType::Type result_type,
|
|
InstructionKind op,
|
|
HInstruction* left,
|
|
HInstruction* right,
|
|
uint32_t dex_pc = kNoDexPc)
|
|
: HBinaryOperation(kBitwiseNegatedRight,
|
|
result_type,
|
|
left,
|
|
right,
|
|
SideEffects::None(),
|
|
dex_pc),
|
|
op_kind_(op) {
|
|
DCHECK(op == HInstruction::kAnd || op == HInstruction::kOr || op == HInstruction::kXor) << op;
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
auto Compute(T x, U y) const -> decltype(x & ~y) {
|
|
static_assert(std::is_same<decltype(x & ~y), decltype(x | ~y)>::value &&
|
|
std::is_same<decltype(x & ~y), decltype(x ^ ~y)>::value,
|
|
"Inconsistent negated bitwise types");
|
|
switch (op_kind_) {
|
|
case HInstruction::kAnd:
|
|
return x & ~y;
|
|
case HInstruction::kOr:
|
|
return x | ~y;
|
|
case HInstruction::kXor:
|
|
return x ^ ~y;
|
|
default:
|
|
LOG(FATAL) << "Unreachable";
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const override {
|
|
return GetBlock()->GetGraph()->GetIntConstant(
|
|
Compute(x->GetValue(), y->GetValue()), GetDexPc());
|
|
}
|
|
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const override {
|
|
return GetBlock()->GetGraph()->GetLongConstant(
|
|
Compute(x->GetValue(), y->GetValue()), GetDexPc());
|
|
}
|
|
HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED,
|
|
HFloatConstant* y ATTRIBUTE_UNUSED) const override {
|
|
LOG(FATAL) << DebugName() << " is not defined for float values";
|
|
UNREACHABLE();
|
|
}
|
|
HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED,
|
|
HDoubleConstant* y ATTRIBUTE_UNUSED) const override {
|
|
LOG(FATAL) << DebugName() << " is not defined for double values";
|
|
UNREACHABLE();
|
|
}
|
|
|
|
InstructionKind GetOpKind() const { return op_kind_; }
|
|
|
|
DECLARE_INSTRUCTION(BitwiseNegatedRight);
|
|
|
|
protected:
|
|
DEFAULT_COPY_CONSTRUCTOR(BitwiseNegatedRight);
|
|
|
|
private:
|
|
// Specifies the bitwise operation, which will be then negated.
|
|
const InstructionKind op_kind_;
|
|
};
|
|
|
|
// This instruction computes part of the array access offset (data and index offset).
|
|
//
|
|
// For array accesses the element address has the following structure:
|
|
// Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT. Taking into account LDR/STR addressing
|
|
// modes address part (CONST_OFFSET + index << ELEM_SHIFT) can be shared across array access with
|
|
// the same data type and index. For example, for the following loop 5 accesses can share address
|
|
// computation:
|
|
//
|
|
// void foo(int[] a, int[] b, int[] c) {
|
|
// for (i...) {
|
|
// a[i] = a[i] + 5;
|
|
// b[i] = b[i] + c[i];
|
|
// }
|
|
// }
|
|
//
|
|
// Note: as the instruction doesn't involve base array address into computations it has no side
|
|
// effects (in comparison of HIntermediateAddress).
|
|
class HIntermediateAddressIndex final : public HExpression<3> {
|
|
public:
|
|
HIntermediateAddressIndex(
|
|
HInstruction* index, HInstruction* offset, HInstruction* shift, uint32_t dex_pc)
|
|
: HExpression(kIntermediateAddressIndex,
|
|
DataType::Type::kInt32,
|
|
SideEffects::None(),
|
|
dex_pc) {
|
|
SetRawInputAt(0, index);
|
|
SetRawInputAt(1, offset);
|
|
SetRawInputAt(2, shift);
|
|
}
|
|
|
|
bool IsClonable() const override { return true; }
|
|
bool CanBeMoved() const override { return true; }
|
|
bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const override {
|
|
return true;
|
|
}
|
|
bool IsActualObject() const override { return false; }
|
|
|
|
HInstruction* GetIndex() const { return InputAt(0); }
|
|
HInstruction* GetOffset() const { return InputAt(1); }
|
|
HInstruction* GetShift() const { return InputAt(2); }
|
|
|
|
DECLARE_INSTRUCTION(IntermediateAddressIndex);
|
|
|
|
protected:
|
|
DEFAULT_COPY_CONSTRUCTOR(IntermediateAddressIndex);
|
|
};
|
|
|
|
class HDataProcWithShifterOp final : public HExpression<2> {
|
|
public:
|
|
enum OpKind {
|
|
kLSL, // Logical shift left.
|
|
kLSR, // Logical shift right.
|
|
kASR, // Arithmetic shift right.
|
|
kUXTB, // Unsigned extend byte.
|
|
kUXTH, // Unsigned extend half-word.
|
|
kUXTW, // Unsigned extend word.
|
|
kSXTB, // Signed extend byte.
|
|
kSXTH, // Signed extend half-word.
|
|
kSXTW, // Signed extend word.
|
|
|
|
// Aliases.
|
|
kFirstShiftOp = kLSL,
|
|
kLastShiftOp = kASR,
|
|
kFirstExtensionOp = kUXTB,
|
|
kLastExtensionOp = kSXTW
|
|
};
|
|
HDataProcWithShifterOp(HInstruction* instr,
|
|
HInstruction* left,
|
|
HInstruction* right,
|
|
OpKind op,
|
|
// The shift argument is unused if the operation
|
|
// is an extension.
|
|
int shift = 0,
|
|
uint32_t dex_pc = kNoDexPc)
|
|
: HExpression(kDataProcWithShifterOp, instr->GetType(), SideEffects::None(), dex_pc),
|
|
instr_kind_(instr->GetKind()), op_kind_(op),
|
|
shift_amount_(shift & (instr->GetType() == DataType::Type::kInt32
|
|
? kMaxIntShiftDistance
|
|
: kMaxLongShiftDistance)) {
|
|
DCHECK(!instr->HasSideEffects());
|
|
SetRawInputAt(0, left);
|
|
SetRawInputAt(1, right);
|
|
}
|
|
|
|
bool IsClonable() const override { return true; }
|
|
bool CanBeMoved() const override { return true; }
|
|
bool InstructionDataEquals(const HInstruction* other_instr) const override {
|
|
const HDataProcWithShifterOp* other = other_instr->AsDataProcWithShifterOp();
|
|
return instr_kind_ == other->instr_kind_ &&
|
|
op_kind_ == other->op_kind_ &&
|
|
shift_amount_ == other->shift_amount_;
|
|
}
|
|
|
|
static bool IsShiftOp(OpKind op_kind) {
|
|
return kFirstShiftOp <= op_kind && op_kind <= kLastShiftOp;
|
|
}
|
|
|
|
static bool IsExtensionOp(OpKind op_kind) {
|
|
return kFirstExtensionOp <= op_kind && op_kind <= kLastExtensionOp;
|
|
}
|
|
|
|
// Find the operation kind and shift amount from a bitfield move instruction.
|
|
static void GetOpInfoFromInstruction(HInstruction* bitfield_op,
|
|
/*out*/OpKind* op_kind,
|
|
/*out*/int* shift_amount);
|
|
|
|
InstructionKind GetInstrKind() const { return instr_kind_; }
|
|
OpKind GetOpKind() const { return op_kind_; }
|
|
int GetShiftAmount() const { return shift_amount_; }
|
|
|
|
DECLARE_INSTRUCTION(DataProcWithShifterOp);
|
|
|
|
protected:
|
|
DEFAULT_COPY_CONSTRUCTOR(DataProcWithShifterOp);
|
|
|
|
private:
|
|
InstructionKind instr_kind_;
|
|
OpKind op_kind_;
|
|
int shift_amount_;
|
|
|
|
friend std::ostream& operator<<(std::ostream& os, OpKind op);
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const HDataProcWithShifterOp::OpKind op);
|
|
|
|
} // namespace art
|
|
|
|
#endif // ART_COMPILER_OPTIMIZING_NODES_SHARED_H_
|