Commit 57074692 authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[torque] Add bitfield declarations

This change is the first part of adding Torque support for a "bitfield
struct", which represents a set of bitfields packed together into an
integer value. With this change, Torque can generate the list of
BitField template specializations that allow runtime code to use the
bitfield values. The flags used in SharedFunctionInfo are converted to
Torque to exercise this functionality. Bitfield values are not yet
accessible directly from Torque code.

Bug: v8:7793
Change-Id: I9e4a3df7c847111b6e02e513f175dbf938b0be35
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1949047
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65371}
parent 31e9ebee
......@@ -188,7 +188,7 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_asm_wasm_broken,
SharedFunctionInfo::IsAsmWasmBrokenBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags,
requires_instance_members_initializer,
SharedFunctionInfo::RequiresInstanceMembersInitializer)
SharedFunctionInfo::RequiresInstanceMembersInitializerBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, name_should_print_as_anonymous,
SharedFunctionInfo::NameShouldPrintAsAnonymousBit)
......@@ -199,7 +199,7 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_toplevel,
SharedFunctionInfo::IsTopLevelBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags,
is_oneshot_iife_or_properties_are_final,
SharedFunctionInfo::IsOneshotIIFEOrPropertiesAreFinalBit)
SharedFunctionInfo::IsOneshotIifeOrPropertiesAreFinalBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags,
is_safe_to_skip_arguments_adaptor,
SharedFunctionInfo::IsSafeToSkipArgumentsAdaptorBit)
......
......@@ -18,6 +18,7 @@
#include "src/objects/smi.h"
#include "src/objects/struct.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "torque-generated/bit-fields-tq.h"
#include "torque-generated/field-offsets-tq.h"
// Has to be the last include (doesn't have include guards):
......@@ -165,7 +166,8 @@ class InterpreterData : public Struct {
// SharedFunctionInfo describes the JSFunction information that can be
// shared by multiple instances of the function.
class SharedFunctionInfo : public HeapObject {
class SharedFunctionInfo : public HeapObject,
public TorqueGeneratedSharedFunctionInfoFlagsFields {
public:
NEVER_READ_ONLY_SPACE
......@@ -616,31 +618,6 @@ class SharedFunctionInfo : public HeapObject {
class BodyDescriptor;
// Bit positions in |flags|.
#define FLAGS_BIT_FIELDS(V, _) \
/* Have FunctionKind first to make it cheaper to access */ \
V(FunctionKindBits, FunctionKind, 5, _) \
V(IsNativeBit, bool, 1, _) \
V(IsStrictBit, bool, 1, _) \
V(FunctionSyntaxKindBits, FunctionSyntaxKind, 3, _) \
V(IsClassConstructorBit, bool, 1, _) \
V(HasDuplicateParametersBit, bool, 1, _) \
V(AllowLazyCompilationBit, bool, 1, _) \
V(NeedsHomeObjectBit, bool, 1, _) \
V(IsAsmWasmBrokenBit, bool, 1, _) \
V(FunctionMapIndexBits, int, 5, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 4, _) \
V(RequiresInstanceMembersInitializer, bool, 1, _) \
V(ConstructAsBuiltinBit, bool, 1, _) \
V(NameShouldPrintAsAnonymousBit, bool, 1, _) \
V(HasReportedBinaryCoverageBit, bool, 1, _) \
V(IsTopLevelBit, bool, 1, _) \
V(IsOneshotIIFEOrPropertiesAreFinalBit, bool, 1, _) \
V(IsSafeToSkipArgumentsAdaptorBit, bool, 1, _) \
V(PrivateNameLookupSkipsOuterClassBit, bool, 1, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS
// Bailout reasons must fit in the DisabledOptimizationReason bitfield.
STATIC_ASSERT(BailoutReason::kLastErrorMessage <=
DisabledOptimizationReasonBits::kMax);
......
......@@ -14,6 +14,34 @@ extern class InterpreterData extends Struct {
interpreter_trampoline: Code;
}
type FunctionKind extends uint8 constexpr 'v8::internal::FunctionKind';
type FunctionSyntaxKind extends uint8
constexpr 'v8::internal::FunctionSyntaxKind';
type BailoutReason extends uint8 constexpr 'v8::internal::BailoutReason';
bitfield struct SharedFunctionInfoFlags extends uint32 {
// Have FunctionKind first to make it cheaper to access.
function_kind: FunctionKind: 5 bit;
is_native: bool: 1 bit;
is_strict: bool: 1 bit;
function_syntax_kind: FunctionSyntaxKind: 3 bit;
is_class_constructor: bool: 1 bit;
has_duplicate_parameters: bool: 1 bit;
allow_lazy_compilation: bool: 1 bit;
needs_home_object: bool: 1 bit;
is_asm_wasm_broken: bool: 1 bit;
function_map_index: int32: 5 bit;
disabled_optimization_reason: BailoutReason: 4 bit;
requires_instance_members_initializer: bool: 1 bit;
construct_as_builtin: bool: 1 bit;
name_should_print_as_anonymous: bool: 1 bit;
has_reported_binary_coverage: bool: 1 bit;
is_top_level: bool: 1 bit;
is_oneshot_iife_or_properties_are_final: bool: 1 bit;
is_safe_to_skip_arguments_adaptor: bool: 1 bit;
private_name_lookup_skips_outer_class: bool: 1 bit;
}
extern class SharedFunctionInfo extends HeapObject {
weak function_data: Object;
name_or_scope_info: String|NoSharedNameSentinel|ScopeInfo;
......@@ -24,7 +52,7 @@ extern class SharedFunctionInfo extends HeapObject {
// Currently set to uint16, can be set to uint8 to save space.
expected_nof_properties: uint16;
function_token_offset: int16;
flags: int32;
flags: SharedFunctionInfoFlags;
function_literal_id: int32;
@if(V8_SFI_HAS_UNIQUE_ID) unique_id: int32;
}
......
......@@ -66,6 +66,7 @@ namespace torque {
#define AST_TYPE_DECLARATION_NODE_KIND_LIST(V) \
V(AbstractTypeDeclaration) \
V(TypeAliasDeclaration) \
V(BitFieldStructDeclaration) \
V(ClassDeclaration) \
V(StructDeclaration)
......@@ -839,6 +840,11 @@ struct StructFieldExpression {
bool const_qualified;
};
struct BitFieldDeclaration {
NameAndTypeExpression name_and_type;
int num_bits;
};
enum class ConditionalAnnotationType {
kPositive,
kNegative,
......@@ -849,9 +855,15 @@ struct ConditionalAnnotation {
ConditionalAnnotationType type;
};
struct AnnotationParameter {
std::string string_value;
int int_value;
bool is_int;
};
struct Annotation {
Identifier* name;
base::Optional<std::string> param;
base::Optional<AnnotationParameter> param;
};
struct ClassFieldExpression {
......@@ -1101,6 +1113,18 @@ struct StructDeclaration : TypeDeclaration {
std::vector<StructFieldExpression> fields;
};
struct BitFieldStructDeclaration : TypeDeclaration {
DEFINE_AST_NODE_LEAF_BOILERPLATE(BitFieldStructDeclaration)
BitFieldStructDeclaration(SourcePosition pos, Identifier* name,
TypeExpression* parent,
std::vector<BitFieldDeclaration> fields)
: TypeDeclaration(kKind, pos, name),
parent(parent),
fields(std::move(fields)) {}
TypeExpression* parent;
std::vector<BitFieldDeclaration> fields;
};
struct ClassBody : AstNode {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ClassBody)
ClassBody(SourcePosition pos, std::vector<Declaration*> methods,
......
......@@ -81,15 +81,7 @@ class DebugFieldType {
? (*field_class_type)->GetGeneratedTNodeTypeName()
: "Object");
}
const Type* constexpr_version =
field_.name_and_type.type->ConstexprVersion();
if (constexpr_version == nullptr) {
Error("Type '", field_.name_and_type.type->ToString(),
"' requires a constexpr representation")
.Position(field_.pos);
return "";
}
return constexpr_version->GetGeneratedTypeName();
return field_.name_and_type.type->GetConstexprGeneratedTypeName();
}
// Returns the field's size in bytes.
......@@ -288,13 +280,7 @@ void GenerateGetPropsChunkForField(const Field& field,
count_value =
"i::PlatformSmiTagging::SmiToInt(indexed_field_count.value)";
} else if (!index_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
const Type* constexpr_index = index_type->ConstexprVersion();
if (constexpr_index == nullptr) {
Error("Type '", index_type->ToString(),
"' requires a constexpr representation");
return;
}
index_type_name = constexpr_index->GetGeneratedTypeName();
index_type_name = index_type->GetConstexprGeneratedTypeName();
count_value = "indexed_field_count.value";
} else {
Error("Unsupported index type: ", index_type);
......
......@@ -43,6 +43,7 @@ class ParseResultHolderBase {
enum class ParseResultHolderBase::TypeId {
kStdString,
kBool,
kInt32,
kStdVectorOfString,
kExpressionPtr,
kIdentifierPtr,
......@@ -59,12 +60,16 @@ enum class ParseResultHolderBase::TypeId {
kNameAndExpression,
kAnnotation,
kVectorOfAnnotation,
kAnnotationParameter,
kOptionalAnnotationParameter,
kClassFieldExpression,
kStructFieldExpression,
kBitFieldDeclaration,
kStdVectorOfNameAndTypeExpression,
kStdVectorOfNameAndExpression,
kStdVectorOfClassFieldExpression,
kStdVectorOfStructFieldExpression,
kStdVectorOfBitFieldDeclaration,
kIncrementDecrementOperator,
kOptionalStdString,
kStdVectorOfStatementPtr,
......
......@@ -3075,6 +3075,44 @@ void ImplementationVisitor::GenerateClassFieldOffsets(
WriteFile(output_header_path, header.str());
}
void ImplementationVisitor::GenerateBitFields(
const std::string& output_directory) {
std::stringstream header;
std::string file_name = "bit-fields-tq.h";
{
IncludeGuardScope include_guard(header, file_name);
header << "#include \"src/base/bit-field.h\"\n\n";
NamespaceScope namespaces(header, {"v8", "internal"});
// TODO(v8:7793): Once we can define enums in Torque, we should be able to
// do something nicer than hard-coding these predeclarations. Until then,
// any enum used as a bitfield must be included in this list.
header << R"(
enum class FunctionSyntaxKind : uint8_t;
enum class BailoutReason : uint8_t;
enum FunctionKind : uint8_t;
)";
for (const auto& type : TypeOracle::GetBitFieldStructTypes()) {
header << "struct TorqueGenerated" << type->name() << "Fields {\n";
std::string type_name = type->GetConstexprGeneratedTypeName();
for (const auto& field : type->fields()) {
const char* suffix = field.num_bits == 1 ? "Bit" : "Bits";
std::string field_type_name =
field.name_and_type.type->GetConstexprGeneratedTypeName();
header << " using " << CamelifyString(field.name_and_type.name)
<< suffix << " = base::BitField<" << field_type_name << ", "
<< field.offset << ", " << field.num_bits << ", " << type_name
<< ">;\n";
}
header << "};\n\n";
}
}
const std::string output_header_path = output_directory + "/" + file_name;
WriteFile(output_header_path, header.str());
}
namespace {
class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
......@@ -3779,7 +3817,7 @@ void ImplementationVisitor::GenerateCSATypes(
// Generates headers for all structs in a topologically-sorted order, since
// TypeOracle keeps them in the order of their resolution
for (auto& type : *TypeOracle::GetAggregateTypes()) {
for (const auto& type : TypeOracle::GetAggregateTypes()) {
const StructType* struct_type = StructType::DynamicCast(type.get());
if (!struct_type) continue;
h_contents << "struct " << struct_type->GetGeneratedTypeNameImpl()
......
......@@ -347,6 +347,7 @@ class ImplementationVisitor {
void GenerateBuiltinDefinitionsAndInterfaceDescriptors(
const std::string& output_directory);
void GenerateClassFieldOffsets(const std::string& output_directory);
void GenerateBitFields(const std::string& output_directory);
void GeneratePrintDefinitions(const std::string& output_directory);
void GenerateClassDefinitions(const std::string& output_directory);
void GenerateInstanceTypes(const std::string& output_directory);
......
......@@ -82,6 +82,7 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
implementation_visitor.GenerateBuiltinDefinitionsAndInterfaceDescriptors(
output_directory);
implementation_visitor.GenerateClassFieldOffsets(output_directory);
implementation_visitor.GenerateBitFields(output_directory);
implementation_visitor.GeneratePrintDefinitions(output_directory);
implementation_visitor.GenerateClassDefinitions(output_directory);
implementation_visitor.GenerateClassVerifiers(output_directory);
......
This diff is collapsed.
......@@ -12,9 +12,15 @@ namespace torque {
DEFINE_CONTEXTUAL_VARIABLE(TypeOracle)
// static
const std::vector<std::unique_ptr<AggregateType>>*
const std::vector<std::unique_ptr<AggregateType>>&
TypeOracle::GetAggregateTypes() {
return &Get().aggregate_types_;
return Get().aggregate_types_;
}
// static
const std::vector<std::unique_ptr<BitFieldStructType>>&
TypeOracle::GetBitFieldStructTypes() {
return Get().bit_field_struct_types_;
}
// static
......
......@@ -43,6 +43,15 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return result;
}
static BitFieldStructType* GetBitFieldStructType(
const Type* parent, const BitFieldStructDeclaration* decl) {
auto ptr = std::unique_ptr<BitFieldStructType>(
new BitFieldStructType(CurrentNamespace(), parent, decl));
BitFieldStructType* result = ptr.get();
Get().bit_field_struct_types_.push_back(std::move(ptr));
return result;
}
static ClassType* GetClassType(const Type* parent, const std::string& name,
ClassFlags flags, const std::string& generates,
ClassDeclaration* decl,
......@@ -275,7 +284,9 @@ class TypeOracle : public ContextualClass<TypeOracle> {
return false;
}
static const std::vector<std::unique_ptr<AggregateType>>* GetAggregateTypes();
static const std::vector<std::unique_ptr<AggregateType>>& GetAggregateTypes();
static const std::vector<std::unique_ptr<BitFieldStructType>>&
GetBitFieldStructTypes();
static void FinalizeAggregateTypes();
......@@ -293,6 +304,7 @@ class TypeOracle : public ContextualClass<TypeOracle> {
Deduplicator<UnionType> union_types_;
std::vector<std::unique_ptr<Type>> nominal_types_;
std::vector<std::unique_ptr<AggregateType>> aggregate_types_;
std::vector<std::unique_ptr<BitFieldStructType>> bit_field_struct_types_;
std::vector<std::unique_ptr<Type>> top_types_;
std::vector<std::unique_ptr<Namespace>>
generic_type_instantiation_namespaces_;
......
......@@ -131,6 +131,70 @@ void DeclareMethods(AggregateType* container_type,
}
}
const BitFieldStructType* TypeVisitor::ComputeType(
BitFieldStructDeclaration* decl, MaybeSpecializationKey specialized_from) {
CurrentSourcePosition::Scope position_scope(decl->pos);
if (specialized_from.has_value()) {
ReportError("Bitfield struct specialization is not supported");
}
const Type* parent = TypeVisitor::ComputeType(decl->parent);
if (!IsAnyUnsignedInteger(parent)) {
ReportError(
"Bitfield struct must extend from an unsigned integer type, not ",
parent->ToString());
}
auto opt_size = SizeOf(parent);
if (!opt_size.has_value()) {
ReportError("Cannot determine size of bitfield struct ", decl->name->value,
" because of unsized parent type ", parent->ToString());
}
const size_t size = 8 * std::get<0>(*opt_size); // Convert bytes to bits.
BitFieldStructType* type = TypeOracle::GetBitFieldStructType(parent, decl);
// Iterate through all of the declared fields, checking their validity and
// registering them on the newly-constructed BitFieldStructType instance.
int offset = 0;
for (const auto& field : decl->fields) {
CurrentSourcePosition::Scope field_position_scope(
field.name_and_type.type->pos);
const Type* field_type = TypeVisitor::ComputeType(field.name_and_type.type);
if (!IsAllowedAsBitField(field_type)) {
ReportError("Type not allowed as bitfield: ",
field.name_and_type.name->value);
}
// Compute the maximum number of bits that could be used for a field of this
// type. Booleans are a special case, not included in SizeOf, because their
// runtime size is 32 bits but they should only occupy 1 bit as a bitfield.
size_t field_type_size = 0;
if (field_type == TypeOracle::GetBoolType()) {
field_type_size = 1;
} else {
auto opt_field_type_size = SizeOf(field_type);
if (!opt_field_type_size.has_value()) {
ReportError("Size unknown for type ", field_type->ToString());
}
field_type_size = 8 * std::get<0>(*opt_field_type_size);
}
if (field.num_bits < 1 ||
static_cast<size_t>(field.num_bits) > field_type_size) {
ReportError("Invalid number of bits for ",
field.name_and_type.name->value);
}
type->RegisterField({field.name_and_type.name->pos,
{field.name_and_type.name->value, field_type},
offset,
field.num_bits});
offset += field.num_bits;
if (static_cast<size_t>(offset) > size) {
ReportError("Too many total bits in ", decl->name->value);
}
}
return type;
}
const StructType* TypeVisitor::ComputeType(
StructDeclaration* decl, MaybeSpecializationKey specialized_from) {
StructType* struct_type = TypeOracle::GetStructType(decl, specialized_from);
......
......@@ -47,6 +47,8 @@ class TypeVisitor {
AbstractTypeDeclaration* decl, MaybeSpecializationKey specialized_from);
static const Type* ComputeType(TypeAliasDeclaration* decl,
MaybeSpecializationKey specialized_from);
static const BitFieldStructType* ComputeType(
BitFieldStructDeclaration* decl, MaybeSpecializationKey specialized_from);
static const StructType* ComputeType(StructDeclaration* decl,
MaybeSpecializationKey specialized_from);
static const ClassType* ComputeType(ClassDeclaration* decl,
......
......@@ -76,6 +76,15 @@ bool Type::IsSubtypeOf(const Type* supertype) const {
return false;
}
std::string Type::GetConstexprGeneratedTypeName() const {
const Type* constexpr_version = ConstexprVersion();
if (constexpr_version == nullptr) {
Error("Type '", ToString(), "' requires a constexpr representation");
return "";
}
return constexpr_version->GetGeneratedTypeName();
}
base::Optional<const ClassType*> Type::ClassSupertype() const {
for (const Type* t = this; t != nullptr; t = t->parent()) {
if (auto* class_type = ClassType::DynamicCast(t)) {
......@@ -245,6 +254,10 @@ const Type* SubtractType(const Type* a, const Type* b) {
return TypeOracle::GetUnionType(result);
}
std::string BitFieldStructType::ToExplicitString() const {
return "bitfield struct " + name();
}
void AggregateType::CheckForDuplicateFields() const {
// Check the aggregate hierarchy and currently defined class for duplicate
// field declarations.
......@@ -401,11 +414,7 @@ std::vector<Method*> AggregateType::Methods(const std::string& name) const {
return result;
}
std::string StructType::ToExplicitString() const {
std::stringstream result;
result << "struct " << name();
return result.str();
}
std::string StructType::ToExplicitString() const { return "struct " + name(); }
void StructType::Finalize() const {
if (is_finalized_) return;
......@@ -447,11 +456,7 @@ std::string ClassType::GetGeneratedTypeNameImpl() const {
: "TNode<" + GetGeneratedTNodeTypeName() + ">";
}
std::string ClassType::ToExplicitString() const {
std::stringstream result;
result << "class " << name();
return result.str();
}
std::string ClassType::ToExplicitString() const { return "class " + name(); }
bool ClassType::AllowInstantiation() const {
return (!IsExtern() || nspace()->IsDefaultNamespace()) && !IsAbstract();
......@@ -774,6 +779,28 @@ base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type) {
return std::make_tuple(size, size_string);
}
bool IsAnyUnsignedInteger(const Type* type) {
return type == TypeOracle::GetUint32Type() ||
type == TypeOracle::GetUint16Type() ||
type == TypeOracle::GetUint8Type() ||
type == TypeOracle::GetUIntPtrType();
}
bool IsAllowedAsBitField(const Type* type) {
if (type->IsBitFieldStructType()) {
// No nested bitfield structs for now. We could reconsider if there's a
// compelling use case.
return false;
}
// Any integer-ish type, including bools and enums which inherit from integer
// types, are allowed.
return type->IsSubtypeOf(TypeOracle::GetUint32Type()) ||
type->IsSubtypeOf(TypeOracle::GetUIntPtrType()) ||
type->IsSubtypeOf(TypeOracle::GetInt32Type()) ||
type->IsSubtypeOf(TypeOracle::GetIntPtrType()) ||
type->IsSubtypeOf(TypeOracle::GetBoolType());
}
} // namespace torque
} // namespace internal
} // namespace v8
......@@ -39,6 +39,7 @@ class TypeBase {
kAbstractType,
kBuiltinPointerType,
kUnionType,
kBitFieldStructType,
kStructType,
kClassType
};
......@@ -49,6 +50,9 @@ class TypeBase {
return kind() == Kind::kBuiltinPointerType;
}
bool IsUnionType() const { return kind() == Kind::kUnionType; }
bool IsBitFieldStructType() const {
return kind() == Kind::kBitFieldStructType;
}
bool IsStructType() const { return kind() == Kind::kStructType; }
bool IsClassType() const { return kind() == Kind::kClassType; }
bool IsAggregateType() const { return IsStructType() || IsClassType(); }
......@@ -125,6 +129,7 @@ class V8_EXPORT_PRIVATE Type : public TypeBase {
virtual bool IsTransient() const { return false; }
virtual const Type* NonConstexprVersion() const { return this; }
virtual const Type* ConstexprVersion() const { return nullptr; }
std::string GetConstexprGeneratedTypeName() const;
base::Optional<const ClassType*> ClassSupertype() const;
virtual std::vector<RuntimeType> GetRuntimeTypes() const { return {}; }
static const Type* CommonSupertype(const Type* a, const Type* b);
......@@ -445,6 +450,51 @@ class V8_EXPORT_PRIVATE UnionType final : public Type {
const Type* SubtractType(const Type* a, const Type* b);
struct BitField {
SourcePosition pos;
NameAndType name_and_type;
int offset;
int num_bits;
};
class V8_EXPORT_PRIVATE BitFieldStructType final : public Type {
public:
DECLARE_TYPE_BOILERPLATE(BitFieldStructType)
std::string ToExplicitString() const override;
std::string GetGeneratedTypeNameImpl() const override {
return parent()->GetGeneratedTypeName();
}
std::string GetGeneratedTNodeTypeNameImpl() const override {
return parent()->GetGeneratedTNodeTypeName();
}
std::vector<RuntimeType> GetRuntimeTypes() const override {
return {{parent()->GetGeneratedTNodeTypeName(), ""}};
}
const Type* ConstexprVersion() const override {
return parent()->ConstexprVersion();
}
void RegisterField(BitField field) { fields_.push_back(std::move(field)); }
const std::string& name() const { return decl_->name->value; }
const std::vector<BitField>& fields() const { return fields_; }
private:
friend class TypeOracle;
BitFieldStructType(Namespace* nspace, const Type* parent,
const BitFieldStructDeclaration* decl)
: Type(Kind::kBitFieldStructType, parent),
namespace_(nspace),
decl_(decl) {}
std::string SimpleNameImpl() const override { return name(); }
Namespace* namespace_;
const BitFieldStructDeclaration* decl_;
std::vector<BitField> fields_;
};
class AggregateType : public Type {
public:
DECLARE_TYPE_BOILERPLATE(AggregateType)
......@@ -729,6 +779,8 @@ TypeVector LowerParameterTypes(const ParameterTypes& parameter_types,
size_t vararg_count = 0);
base::Optional<std::tuple<size_t, std::string>> SizeOf(const Type* type);
bool IsAnyUnsignedInteger(const Type* type);
bool IsAllowedAsBitField(const Type* type);
} // namespace torque
} // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment