clang 24.0.0git
CIRDialectBytecode.cpp
Go to the documentation of this file.
1//===- CIRDialectBytecode.cpp - CIR Bytecode Implementation ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "mlir/Bytecode/BytecodeImplementation.h"
11#include "mlir/IR/Diagnostics.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/TypeSwitch.h"
18
19#include <limits>
20#include <type_traits>
21
22using namespace mlir;
23using namespace cir;
24
25namespace {
26
27// Both namespaces declare a BoolAttr, named unqualified below. This must live
28// in the inner namespace: at global scope it merges with the using-directives
29// and stays ambiguous.
30using cir::BoolAttr;
31
32//===--------------------------------------------------------------------===//
33// Helpers referenced by the generated readers
34//===--------------------------------------------------------------------===//
35
36// The payload width is implied by the type (mirroring BuiltinDialectBytecode)
37// and recovered here. A mismatched type fails rather than asserts: it came
38// from the same untrusted file, so it is a corrupt-input case.
39
40static LogicalResult readAPIntWithKnownWidth(DialectBytecodeReader &reader,
41 Type type, FailureOr<APInt> &val) {
42 auto intType = mlir::dyn_cast<cir::IntTypeInterface>(type);
43 if (!intType)
44 return reader.emitError()
45 << "expected a CIR integer type for cir.int, but got: " << type;
46 val = reader.readAPIntWithKnownWidth(intType.getWidth());
47 return success(succeeded(val));
48}
49
50static LogicalResult
51readAPFloatWithKnownSemantics(DialectBytecodeReader &reader, Type type,
52 FailureOr<APFloat> &val) {
53 auto fpType = mlir::dyn_cast<cir::FPTypeInterface>(type);
54 if (!fpType)
55 return reader.emitError()
56 << "expected a CIR floating-point type for cir.fp, but got: "
57 << type;
58 val = reader.readAPFloatWithKnownSemantics(fpType.getFloatSemantics());
59 return success(succeeded(val));
60}
61
62// std::optional<T> parameters carry presence as a varint of its own ahead of
63// the value, so the full width survives.
64template <typename EntryTy>
65static LogicalResult readOptionalInt(DialectBytecodeReader &reader,
66 std::optional<EntryTy> &storage) {
67 static_assert(std::is_unsigned_v<EntryTy>,
68 "EntryTy must be unsigned: only unsigned varints are "
69 "supported here, so a negative value cannot be represented");
70 uint64_t present = 0;
71 if (failed(reader.readVarInt(present)))
72 return failure();
73 if (present == 0) {
74 storage = std::nullopt;
75 return success();
76 }
77 if (present != 1)
78 return reader.emitError() << "optional integer presence flag " << present
79 << " is neither 0 nor 1";
80 uint64_t value = 0;
81 if (failed(reader.readVarInt(value)))
82 return failure();
83 // Out-of-range values fail rather than truncating into a plausible index.
84 if (value > static_cast<uint64_t>(std::numeric_limits<EntryTy>::max()))
85 return reader.emitError() << "optional integer value " << value
86 << " does not fit in destination type";
87 storage = static_cast<EntryTy>(value);
88 return success();
89}
90
91template <typename EntryTy>
92static void writeOptionalInt(DialectBytecodeWriter &writer,
93 std::optional<EntryTy> storage) {
94 static_assert(std::is_unsigned_v<EntryTy>,
95 "EntryTy must be unsigned: only unsigned varints are "
96 "supported here, so a negative value cannot be represented");
97 writer.writeVarInt(storage.has_value() ? 1 : 0);
98 if (storage)
99 writer.writeVarInt(*storage);
100}
101
102// std::optional<Attr> form (cir.method's symbol). A null attribute is not a
103// valid state and normalizes to std::nullopt on the wire.
104
105template <typename AttrTy>
106static LogicalResult readStdOptionalAttribute(DialectBytecodeReader &reader,
107 std::optional<AttrTy> &storage) {
108 AttrTy attr;
109 if (failed(reader.readOptionalAttribute(attr)))
110 return failure();
111 if (attr)
112 storage = attr;
113 else
114 storage = std::nullopt;
115 return success();
116}
117
118template <typename AttrTy>
119static void writeStdOptionalAttribute(DialectBytecodeWriter &writer,
120 std::optional<AttrTy> storage) {
121 assert(!storage || *storage);
122 writer.writeOptionalAttribute(storage.value_or(AttrTy()));
123}
124
125// A scoped enum validated through its symbolizer; out-of-range values fail
126// instead of casting undefined values into the enum.
127template <typename EnumTy>
128static LogicalResult readEnum(DialectBytecodeReader &reader, EnumTy &result,
129 std::optional<EnumTy> (*symbolize)(uint32_t),
130 llvm::StringRef enumName) {
131 uint64_t value = 0;
132 if (failed(reader.readVarInt(value)))
133 return failure();
134 if (value > static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()))
135 return reader.emitError()
136 << enumName << " value " << value << " out of range";
137 std::optional<EnumTy> kind = symbolize(static_cast<uint32_t>(value));
138 if (!kind)
139 return reader.emitError() << "invalid " << enumName << " value " << value;
140 result = *kind;
141 return success();
142}
143
144// A varint narrowed to a fixed-width integer; out-of-range values fail
145// instead of truncating.
146template <typename IntTy>
147static LogicalResult readCheckedInt(DialectBytecodeReader &reader,
148 IntTy &result) {
149 static_assert(std::is_integral_v<IntTy> && !std::is_same_v<IntTy, bool>);
150 if constexpr (std::is_signed_v<IntTy>) {
151 int64_t value = 0;
152 if (failed(reader.readSignedVarInt(value)))
153 return failure();
154 if (value > static_cast<int64_t>(std::numeric_limits<IntTy>::max()) ||
155 value < static_cast<int64_t>(std::numeric_limits<IntTy>::min()))
156 return reader.emitError() << "integer value " << value
157 << " does not fit in destination type";
158 result = static_cast<IntTy>(value);
159 } else {
160 uint64_t value = 0;
161 if (failed(reader.readVarInt(value)))
162 return failure();
163 if (value > static_cast<uint64_t>(std::numeric_limits<IntTy>::max()))
164 return reader.emitError() << "integer value " << value
165 << " does not fit in destination type";
166 result = static_cast<IntTy>(value);
167 }
168 return success();
169}
170
171//===--------------------------------------------------------------------===//
172// Tablegen generated bytecode functions
173//===--------------------------------------------------------------------===//
174
175#include "clang/CIR/Dialect/IR/CIRDialectBytecode.cpp.inc"
176
177//===--------------------------------------------------------------------===//
178// CIRDialectBytecodeInterface
179//===--------------------------------------------------------------------===//
180
181/// Bytecode interface for the CIR dialect.
182struct CIRDialectBytecodeInterface : public BytecodeDialectInterface {
183 CIRDialectBytecodeInterface(Dialect *dialect)
184 : BytecodeDialectInterface(dialect) {}
185
186 Attribute readAttribute(DialectBytecodeReader &reader) const override {
187 return ::readAttribute(getContext(), reader);
188 }
189
190 LogicalResult writeAttribute(Attribute attr,
191 DialectBytecodeWriter &writer) const override {
192 return ::writeAttribute(attr, writer);
193 }
194
195 Type readType(DialectBytecodeReader &reader) const override {
196 return ::readType(getContext(), reader);
197 }
198
199 LogicalResult writeType(Type type,
200 DialectBytecodeWriter &writer) const override {
201 return ::writeType(type, writer);
202 }
203};
204} // namespace
205
206void cir::detail::addBytecodeInterface(CIRDialect *dialect) {
207 dialect->addInterfaces<CIRDialectBytecodeInterface>();
208}
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
void addBytecodeInterface(CIRDialect *dialect)
Add the interfaces necessary for encoding the CIR dialect components in bytecode.
const internal::VariadicAllOfMatcher< Attr > attr
int32_t uint32_t