441 lines
14 KiB
C++
441 lines
14 KiB
C++
//===- BuiltinDialectBytecode.cpp - Builtin Bytecode Implementation -------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "BuiltinDialectBytecode.h"
|
|
#include "mlir/Bytecode/BytecodeImplementation.h"
|
|
#include "mlir/IR/BuiltinDialect.h"
|
|
#include "mlir/IR/BuiltinTypes.h"
|
|
#include "mlir/IR/Diagnostics.h"
|
|
#include "llvm/ADT/TypeSwitch.h"
|
|
|
|
using namespace mlir;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Encoding
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
namespace builtin_encoding {
|
|
/// This enum contains marker codes used to indicate which attribute is
|
|
/// currently being decoded, and how it should be decoded. The order of these
|
|
/// codes should generally be unchanged, as any changes will inevitably break
|
|
/// compatibility with older bytecode.
|
|
enum AttributeCode {
|
|
/// ArrayAttr {
|
|
/// elements: Attribute[]
|
|
/// }
|
|
///
|
|
kArrayAttr = 0,
|
|
|
|
/// DictionaryAttr {
|
|
/// attrs: <StringAttr, Attribute>[]
|
|
/// }
|
|
kDictionaryAttr = 1,
|
|
|
|
/// StringAttr {
|
|
/// value: string
|
|
/// }
|
|
kStringAttr = 2,
|
|
|
|
/// StringAttrWithType {
|
|
/// value: string,
|
|
/// type: Type
|
|
/// }
|
|
/// A variant of StringAttr with a type.
|
|
kStringAttrWithType = 3,
|
|
|
|
/// FlatSymbolRefAttr {
|
|
/// rootReference: StringAttr
|
|
/// }
|
|
/// A variant of SymbolRefAttr with no leaf references.
|
|
kFlatSymbolRefAttr = 4,
|
|
|
|
/// SymbolRefAttr {
|
|
/// rootReference: StringAttr,
|
|
/// leafReferences: FlatSymbolRefAttr[]
|
|
/// }
|
|
kSymbolRefAttr = 5,
|
|
|
|
/// TypeAttr {
|
|
/// value: Type
|
|
/// }
|
|
kTypeAttr = 6,
|
|
|
|
/// UnitAttr {
|
|
/// }
|
|
kUnitAttr = 7,
|
|
|
|
/// IntegerAttr {
|
|
/// type: Type
|
|
/// value: APInt,
|
|
/// }
|
|
kIntegerAttr = 8,
|
|
|
|
/// FloatAttr {
|
|
/// type: FloatType
|
|
/// value: APFloat
|
|
/// }
|
|
kFloatAttr = 9,
|
|
};
|
|
|
|
/// This enum contains marker codes used to indicate which type is currently
|
|
/// being decoded, and how it should be decoded. The order of these codes should
|
|
/// generally be unchanged, as any changes will inevitably break compatibility
|
|
/// with older bytecode.
|
|
enum TypeCode {
|
|
/// IntegerType {
|
|
/// widthAndSignedness: varint // (width << 2) | (signedness)
|
|
/// }
|
|
///
|
|
kIntegerType = 0,
|
|
|
|
/// IndexType {
|
|
/// }
|
|
///
|
|
kIndexType = 1,
|
|
|
|
/// FunctionType {
|
|
/// inputs: Type[],
|
|
/// results: Type[]
|
|
/// }
|
|
///
|
|
kFunctionType = 2,
|
|
};
|
|
|
|
} // namespace builtin_encoding
|
|
} // namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// BuiltinDialectBytecodeInterface
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
/// This class implements the bytecode interface for the builtin dialect.
|
|
struct BuiltinDialectBytecodeInterface : public BytecodeDialectInterface {
|
|
BuiltinDialectBytecodeInterface(Dialect *dialect)
|
|
: BytecodeDialectInterface(dialect) {}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Attributes
|
|
|
|
Attribute readAttribute(DialectBytecodeReader &reader) const override;
|
|
ArrayAttr readArrayAttr(DialectBytecodeReader &reader) const;
|
|
DictionaryAttr readDictionaryAttr(DialectBytecodeReader &reader) const;
|
|
FloatAttr readFloatAttr(DialectBytecodeReader &reader) const;
|
|
IntegerAttr readIntegerAttr(DialectBytecodeReader &reader) const;
|
|
StringAttr readStringAttr(DialectBytecodeReader &reader, bool hasType) const;
|
|
SymbolRefAttr readSymbolRefAttr(DialectBytecodeReader &reader,
|
|
bool hasNestedRefs) const;
|
|
TypeAttr readTypeAttr(DialectBytecodeReader &reader) const;
|
|
|
|
LogicalResult writeAttribute(Attribute attr,
|
|
DialectBytecodeWriter &writer) const override;
|
|
void write(ArrayAttr attr, DialectBytecodeWriter &writer) const;
|
|
void write(DictionaryAttr attr, DialectBytecodeWriter &writer) const;
|
|
void write(IntegerAttr attr, DialectBytecodeWriter &writer) const;
|
|
void write(FloatAttr attr, DialectBytecodeWriter &writer) const;
|
|
void write(StringAttr attr, DialectBytecodeWriter &writer) const;
|
|
void write(SymbolRefAttr attr, DialectBytecodeWriter &writer) const;
|
|
void write(TypeAttr attr, DialectBytecodeWriter &writer) const;
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Types
|
|
|
|
Type readType(DialectBytecodeReader &reader) const override;
|
|
IntegerType readIntegerType(DialectBytecodeReader &reader) const;
|
|
FunctionType readFunctionType(DialectBytecodeReader &reader) const;
|
|
|
|
LogicalResult writeType(Type type,
|
|
DialectBytecodeWriter &writer) const override;
|
|
void write(IntegerType type, DialectBytecodeWriter &writer) const;
|
|
void write(FunctionType type, DialectBytecodeWriter &writer) const;
|
|
};
|
|
} // namespace
|
|
|
|
void builtin_dialect_detail::addBytecodeInterface(BuiltinDialect *dialect) {
|
|
dialect->addInterfaces<BuiltinDialectBytecodeInterface>();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Attributes: Reader
|
|
|
|
Attribute BuiltinDialectBytecodeInterface::readAttribute(
|
|
DialectBytecodeReader &reader) const {
|
|
uint64_t code;
|
|
if (failed(reader.readVarInt(code)))
|
|
return Attribute();
|
|
switch (code) {
|
|
case builtin_encoding::kArrayAttr:
|
|
return readArrayAttr(reader);
|
|
case builtin_encoding::kDictionaryAttr:
|
|
return readDictionaryAttr(reader);
|
|
case builtin_encoding::kStringAttr:
|
|
return readStringAttr(reader, /*hasType=*/false);
|
|
case builtin_encoding::kStringAttrWithType:
|
|
return readStringAttr(reader, /*hasType=*/true);
|
|
case builtin_encoding::kFlatSymbolRefAttr:
|
|
return readSymbolRefAttr(reader, /*hasNestedRefs=*/false);
|
|
case builtin_encoding::kSymbolRefAttr:
|
|
return readSymbolRefAttr(reader, /*hasNestedRefs=*/true);
|
|
case builtin_encoding::kTypeAttr:
|
|
return readTypeAttr(reader);
|
|
case builtin_encoding::kUnitAttr:
|
|
return UnitAttr::get(getContext());
|
|
case builtin_encoding::kIntegerAttr:
|
|
return readIntegerAttr(reader);
|
|
case builtin_encoding::kFloatAttr:
|
|
return readFloatAttr(reader);
|
|
default:
|
|
reader.emitError() << "unknown builtin attribute code: " << code;
|
|
return Attribute();
|
|
}
|
|
}
|
|
|
|
ArrayAttr BuiltinDialectBytecodeInterface::readArrayAttr(
|
|
DialectBytecodeReader &reader) const {
|
|
SmallVector<Attribute> elements;
|
|
if (failed(reader.readAttributes(elements)))
|
|
return ArrayAttr();
|
|
return ArrayAttr::get(getContext(), elements);
|
|
}
|
|
|
|
DictionaryAttr BuiltinDialectBytecodeInterface::readDictionaryAttr(
|
|
DialectBytecodeReader &reader) const {
|
|
auto readNamedAttr = [&]() -> FailureOr<NamedAttribute> {
|
|
StringAttr name;
|
|
Attribute value;
|
|
if (failed(reader.readAttribute(name)) ||
|
|
failed(reader.readAttribute(value)))
|
|
return failure();
|
|
return NamedAttribute(name, value);
|
|
};
|
|
SmallVector<NamedAttribute> attrs;
|
|
if (failed(reader.readList(attrs, readNamedAttr)))
|
|
return DictionaryAttr();
|
|
return DictionaryAttr::get(getContext(), attrs);
|
|
}
|
|
|
|
FloatAttr BuiltinDialectBytecodeInterface::readFloatAttr(
|
|
DialectBytecodeReader &reader) const {
|
|
FloatType type;
|
|
if (failed(reader.readType(type)))
|
|
return FloatAttr();
|
|
FailureOr<APFloat> value =
|
|
reader.readAPFloatWithKnownSemantics(type.getFloatSemantics());
|
|
if (failed(value))
|
|
return FloatAttr();
|
|
return FloatAttr::get(type, *value);
|
|
}
|
|
|
|
IntegerAttr BuiltinDialectBytecodeInterface::readIntegerAttr(
|
|
DialectBytecodeReader &reader) const {
|
|
Type type;
|
|
if (failed(reader.readType(type)))
|
|
return IntegerAttr();
|
|
|
|
// Extract the value storage width from the type.
|
|
unsigned bitWidth;
|
|
if (auto intType = type.dyn_cast<IntegerType>()) {
|
|
bitWidth = intType.getWidth();
|
|
} else if (type.isa<IndexType>()) {
|
|
bitWidth = IndexType::kInternalStorageBitWidth;
|
|
} else {
|
|
reader.emitError()
|
|
<< "expected integer or index type for IntegerAttr, but got: " << type;
|
|
return IntegerAttr();
|
|
}
|
|
|
|
FailureOr<APInt> value = reader.readAPIntWithKnownWidth(bitWidth);
|
|
if (failed(value))
|
|
return IntegerAttr();
|
|
return IntegerAttr::get(type, *value);
|
|
}
|
|
|
|
StringAttr
|
|
BuiltinDialectBytecodeInterface::readStringAttr(DialectBytecodeReader &reader,
|
|
bool hasType) const {
|
|
StringRef string;
|
|
if (failed(reader.readString(string)))
|
|
return StringAttr();
|
|
|
|
// Read the type if present.
|
|
Type type;
|
|
if (!hasType)
|
|
type = NoneType::get(getContext());
|
|
else if (failed(reader.readType(type)))
|
|
return StringAttr();
|
|
return StringAttr::get(string, type);
|
|
}
|
|
|
|
SymbolRefAttr BuiltinDialectBytecodeInterface::readSymbolRefAttr(
|
|
DialectBytecodeReader &reader, bool hasNestedRefs) const {
|
|
StringAttr rootReference;
|
|
if (failed(reader.readAttribute(rootReference)))
|
|
return SymbolRefAttr();
|
|
SmallVector<FlatSymbolRefAttr> nestedReferences;
|
|
if (hasNestedRefs && failed(reader.readAttributes(nestedReferences)))
|
|
return SymbolRefAttr();
|
|
return SymbolRefAttr::get(rootReference, nestedReferences);
|
|
}
|
|
|
|
TypeAttr BuiltinDialectBytecodeInterface::readTypeAttr(
|
|
DialectBytecodeReader &reader) const {
|
|
Type type;
|
|
if (failed(reader.readType(type)))
|
|
return TypeAttr();
|
|
return TypeAttr::get(type);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Attributes: Writer
|
|
|
|
LogicalResult BuiltinDialectBytecodeInterface::writeAttribute(
|
|
Attribute attr, DialectBytecodeWriter &writer) const {
|
|
return TypeSwitch<Attribute, LogicalResult>(attr)
|
|
.Case<ArrayAttr, DictionaryAttr, FloatAttr, IntegerAttr, StringAttr,
|
|
SymbolRefAttr, TypeAttr>([&](auto attr) {
|
|
write(attr, writer);
|
|
return success();
|
|
})
|
|
.Case([&](UnitAttr) {
|
|
writer.writeVarInt(builtin_encoding::kUnitAttr);
|
|
return success();
|
|
})
|
|
.Default([&](Attribute) { return failure(); });
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
ArrayAttr attr, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kArrayAttr);
|
|
writer.writeAttributes(attr.getValue());
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
DictionaryAttr attr, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kDictionaryAttr);
|
|
writer.writeList(attr.getValue(), [&](NamedAttribute attr) {
|
|
writer.writeAttribute(attr.getName());
|
|
writer.writeAttribute(attr.getValue());
|
|
});
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
FloatAttr attr, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kFloatAttr);
|
|
writer.writeType(attr.getType());
|
|
writer.writeAPFloatWithKnownSemantics(attr.getValue());
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
IntegerAttr attr, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kIntegerAttr);
|
|
writer.writeType(attr.getType());
|
|
writer.writeAPIntWithKnownWidth(attr.getValue());
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
StringAttr attr, DialectBytecodeWriter &writer) const {
|
|
// We only encode the type if it isn't NoneType, which is significantly less
|
|
// common.
|
|
Type type = attr.getType();
|
|
if (!type.isa<NoneType>()) {
|
|
writer.writeVarInt(builtin_encoding::kStringAttrWithType);
|
|
writer.writeOwnedString(attr.getValue());
|
|
writer.writeType(type);
|
|
return;
|
|
}
|
|
writer.writeVarInt(builtin_encoding::kStringAttr);
|
|
writer.writeOwnedString(attr.getValue());
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
SymbolRefAttr attr, DialectBytecodeWriter &writer) const {
|
|
ArrayRef<FlatSymbolRefAttr> nestedRefs = attr.getNestedReferences();
|
|
writer.writeVarInt(nestedRefs.empty() ? builtin_encoding::kFlatSymbolRefAttr
|
|
: builtin_encoding::kSymbolRefAttr);
|
|
|
|
writer.writeAttribute(attr.getRootReference());
|
|
if (!nestedRefs.empty())
|
|
writer.writeAttributes(nestedRefs);
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
TypeAttr attr, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kTypeAttr);
|
|
writer.writeType(attr.getValue());
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Types: Reader
|
|
|
|
Type BuiltinDialectBytecodeInterface::readType(
|
|
DialectBytecodeReader &reader) const {
|
|
uint64_t code;
|
|
if (failed(reader.readVarInt(code)))
|
|
return Type();
|
|
switch (code) {
|
|
case builtin_encoding::kIntegerType:
|
|
return readIntegerType(reader);
|
|
case builtin_encoding::kIndexType:
|
|
return IndexType::get(getContext());
|
|
|
|
case builtin_encoding::kFunctionType:
|
|
return readFunctionType(reader);
|
|
default:
|
|
reader.emitError() << "unknown builtin type code: " << code;
|
|
return Type();
|
|
}
|
|
}
|
|
|
|
IntegerType BuiltinDialectBytecodeInterface::readIntegerType(
|
|
DialectBytecodeReader &reader) const {
|
|
uint64_t encoding;
|
|
if (failed(reader.readVarInt(encoding)))
|
|
return IntegerType();
|
|
return IntegerType::get(
|
|
getContext(), encoding >> 2,
|
|
static_cast<IntegerType::SignednessSemantics>(encoding & 0x3));
|
|
}
|
|
|
|
FunctionType BuiltinDialectBytecodeInterface::readFunctionType(
|
|
DialectBytecodeReader &reader) const {
|
|
SmallVector<Type> inputs, results;
|
|
if (failed(reader.readTypes(inputs)) || failed(reader.readTypes(results)))
|
|
return FunctionType();
|
|
return FunctionType::get(getContext(), inputs, results);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Types: Writer
|
|
|
|
LogicalResult BuiltinDialectBytecodeInterface::writeType(
|
|
Type type, DialectBytecodeWriter &writer) const {
|
|
return TypeSwitch<Type, LogicalResult>(type)
|
|
.Case<IntegerType, FunctionType>([&](auto type) {
|
|
write(type, writer);
|
|
return success();
|
|
})
|
|
.Case([&](IndexType) {
|
|
return writer.writeVarInt(builtin_encoding::kIndexType), success();
|
|
})
|
|
.Default([&](Type) { return failure(); });
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
IntegerType type, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kIntegerType);
|
|
writer.writeVarInt((type.getWidth() << 2) | type.getSignedness());
|
|
}
|
|
|
|
void BuiltinDialectBytecodeInterface::write(
|
|
FunctionType type, DialectBytecodeWriter &writer) const {
|
|
writer.writeVarInt(builtin_encoding::kFunctionType);
|
|
writer.writeTypes(type.getInputs());
|
|
writer.writeTypes(type.getResults());
|
|
}
|