/*
|
* Copyright (C) 2017 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_DATA_TYPE_H_
|
#define ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
|
|
#include <iosfwd>
|
|
#include <android-base/logging.h>
|
|
#include "base/bit_utils.h"
|
|
namespace art {
|
|
class DataType {
|
public:
|
enum class Type : uint8_t {
|
kReference = 0,
|
kBool,
|
kUint8,
|
kInt8,
|
kUint16,
|
kInt16,
|
kUint32,
|
kInt32,
|
kUint64,
|
kInt64,
|
kFloat32,
|
kFloat64,
|
kVoid,
|
kLast = kVoid
|
};
|
|
static constexpr Type FromShorty(char type);
|
static constexpr char TypeId(DataType::Type type);
|
|
static constexpr size_t SizeShift(Type type) {
|
switch (type) {
|
case Type::kVoid:
|
case Type::kBool:
|
case Type::kUint8:
|
case Type::kInt8:
|
return 0;
|
case Type::kUint16:
|
case Type::kInt16:
|
return 1;
|
case Type::kUint32:
|
case Type::kInt32:
|
case Type::kFloat32:
|
return 2;
|
case Type::kUint64:
|
case Type::kInt64:
|
case Type::kFloat64:
|
return 3;
|
case Type::kReference:
|
return WhichPowerOf2(kObjectReferenceSize);
|
default:
|
LOG(FATAL) << "Invalid type " << static_cast<int>(type);
|
return 0;
|
}
|
}
|
|
static constexpr size_t Size(Type type) {
|
switch (type) {
|
case Type::kVoid:
|
return 0;
|
case Type::kBool:
|
case Type::kUint8:
|
case Type::kInt8:
|
return 1;
|
case Type::kUint16:
|
case Type::kInt16:
|
return 2;
|
case Type::kUint32:
|
case Type::kInt32:
|
case Type::kFloat32:
|
return 4;
|
case Type::kUint64:
|
case Type::kInt64:
|
case Type::kFloat64:
|
return 8;
|
case Type::kReference:
|
return kObjectReferenceSize;
|
default:
|
LOG(FATAL) << "Invalid type " << static_cast<int>(type);
|
return 0;
|
}
|
}
|
|
static bool IsFloatingPointType(Type type) {
|
return type == Type::kFloat32 || type == Type::kFloat64;
|
}
|
|
static bool IsIntegralType(Type type) {
|
// The Java language does not allow treating boolean as an integral type but
|
// our bit representation makes it safe.
|
switch (type) {
|
case Type::kBool:
|
case Type::kUint8:
|
case Type::kInt8:
|
case Type::kUint16:
|
case Type::kInt16:
|
case Type::kUint32:
|
case Type::kInt32:
|
case Type::kUint64:
|
case Type::kInt64:
|
return true;
|
default:
|
return false;
|
}
|
}
|
|
static bool IsIntOrLongType(Type type) {
|
return type == Type::kInt32 || type == Type::kInt64;
|
}
|
|
static bool Is64BitType(Type type) {
|
return type == Type::kUint64 || type == Type::kInt64 || type == Type::kFloat64;
|
}
|
|
static bool IsUnsignedType(Type type) {
|
return type == Type::kBool || type == Type::kUint8 || type == Type::kUint16 ||
|
type == Type::kUint32 || type == Type::kUint64;
|
}
|
|
// Return the general kind of `type`, fusing integer-like types as Type::kInt.
|
static Type Kind(Type type) {
|
switch (type) {
|
case Type::kBool:
|
case Type::kUint8:
|
case Type::kInt8:
|
case Type::kUint16:
|
case Type::kInt16:
|
case Type::kUint32:
|
case Type::kInt32:
|
return Type::kInt32;
|
case Type::kUint64:
|
case Type::kInt64:
|
return Type::kInt64;
|
default:
|
return type;
|
}
|
}
|
|
static int64_t MinValueOfIntegralType(Type type) {
|
switch (type) {
|
case Type::kBool:
|
return std::numeric_limits<bool>::min();
|
case Type::kUint8:
|
return std::numeric_limits<uint8_t>::min();
|
case Type::kInt8:
|
return std::numeric_limits<int8_t>::min();
|
case Type::kUint16:
|
return std::numeric_limits<uint16_t>::min();
|
case Type::kInt16:
|
return std::numeric_limits<int16_t>::min();
|
case Type::kUint32:
|
return std::numeric_limits<uint32_t>::min();
|
case Type::kInt32:
|
return std::numeric_limits<int32_t>::min();
|
case Type::kUint64:
|
return std::numeric_limits<uint64_t>::min();
|
case Type::kInt64:
|
return std::numeric_limits<int64_t>::min();
|
default:
|
LOG(FATAL) << "non integral type";
|
}
|
return 0;
|
}
|
|
static int64_t MaxValueOfIntegralType(Type type) {
|
switch (type) {
|
case Type::kBool:
|
return std::numeric_limits<bool>::max();
|
case Type::kUint8:
|
return std::numeric_limits<uint8_t>::max();
|
case Type::kInt8:
|
return std::numeric_limits<int8_t>::max();
|
case Type::kUint16:
|
return std::numeric_limits<uint16_t>::max();
|
case Type::kInt16:
|
return std::numeric_limits<int16_t>::max();
|
case Type::kUint32:
|
return std::numeric_limits<uint32_t>::max();
|
case Type::kInt32:
|
return std::numeric_limits<int32_t>::max();
|
case Type::kUint64:
|
return std::numeric_limits<uint64_t>::max();
|
case Type::kInt64:
|
return std::numeric_limits<int64_t>::max();
|
default:
|
LOG(FATAL) << "non integral type";
|
}
|
return 0;
|
}
|
|
static bool IsTypeConversionImplicit(Type input_type, Type result_type);
|
static bool IsTypeConversionImplicit(int64_t value, Type result_type);
|
|
static bool IsZeroExtension(Type input_type, Type result_type) {
|
return IsIntOrLongType(result_type) &&
|
IsUnsignedType(input_type) &&
|
Size(result_type) > Size(input_type);
|
}
|
|
static Type ToSigned(Type type) {
|
switch (type) {
|
case Type::kUint8:
|
return Type::kInt8;
|
case Type::kUint16:
|
return Type::kInt16;
|
case Type::kUint32:
|
return Type::kInt32;
|
case Type::kUint64:
|
return Type::kInt64;
|
default:
|
return type;
|
}
|
}
|
|
static Type ToUnsigned(Type type) {
|
switch (type) {
|
case Type::kInt8:
|
return Type::kUint8;
|
case Type::kInt16:
|
return Type::kUint16;
|
case Type::kInt32:
|
return Type::kUint32;
|
case Type::kInt64:
|
return Type::kUint64;
|
default:
|
return type;
|
}
|
}
|
|
static const char* PrettyDescriptor(Type type);
|
|
private:
|
static constexpr size_t kObjectReferenceSize = 4u;
|
};
|
std::ostream& operator<<(std::ostream& os, DataType::Type data_type);
|
|
// Defined outside DataType to have the operator<< available for DCHECK_NE().
|
inline bool DataType::IsTypeConversionImplicit(Type input_type, Type result_type) {
|
DCHECK_NE(DataType::Type::kVoid, result_type);
|
DCHECK_NE(DataType::Type::kVoid, input_type);
|
|
// Invariant: We should never generate a conversion to a Boolean value.
|
DCHECK_NE(DataType::Type::kBool, result_type);
|
|
// Besides conversion to the same type, integral conversions to non-Int64 types
|
// are implicit if the result value range covers the input value range, i.e.
|
// widening conversions that do not need to trim the sign bits.
|
return result_type == input_type ||
|
(result_type != Type::kInt64 &&
|
IsIntegralType(input_type) &&
|
IsIntegralType(result_type) &&
|
MinValueOfIntegralType(input_type) >= MinValueOfIntegralType(result_type) &&
|
MaxValueOfIntegralType(input_type) <= MaxValueOfIntegralType(result_type));
|
}
|
|
inline bool DataType::IsTypeConversionImplicit(int64_t value, Type result_type) {
|
if (IsIntegralType(result_type) && result_type != Type::kInt64) {
|
// If the constant value falls in the range of the result_type, type
|
// conversion isn't needed.
|
return value >= MinValueOfIntegralType(result_type) &&
|
value <= MaxValueOfIntegralType(result_type);
|
}
|
// Conversion isn't implicit if it's into non-integer types, or 64-bit int
|
// which may have different number of registers.
|
return false;
|
}
|
|
} // namespace art
|
|
#endif // ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
|