@@ -115,6 +115,149 @@ def ConstantOp : CIR_Op<"const",
115115 let hasFolder = 1;
116116}
117117
118+ //===----------------------------------------------------------------------===//
119+ // AllocaOp
120+ //===----------------------------------------------------------------------===//
121+
122+ class AllocaTypesMatchWith<string summary, string lhsArg, string rhsArg,
123+ string transform, string comparator = "std::equal_to<>()">
124+ : PredOpTrait<summary, CPred<
125+ comparator # "(" #
126+ !subst("$_self", "$" # lhsArg # ".getType()", transform) #
127+ ", $" # rhsArg # ")">> {
128+ string lhs = lhsArg;
129+ string rhs = rhsArg;
130+ string transformer = transform;
131+ }
132+
133+ def AllocaOp : CIR_Op<"alloca", [
134+ AllocaTypesMatchWith<"'allocaType' matches pointee type of 'addr'",
135+ "addr", "allocaType",
136+ "cast<PointerType>($_self).getPointee()">,
137+ DeclareOpInterfaceMethods<PromotableAllocationOpInterface>]> {
138+ let summary = "Defines a scope-local variable";
139+ let description = [{
140+ The `cir.alloca` operation defines a scope-local variable.
141+
142+ The presence `init` attribute indicates that the local variable represented
143+ by this alloca was originally initialized in C/C++ source code. In such
144+ cases, the first use contains the initialization (a cir.store, a cir.call
145+ to a ctor, etc).
146+
147+ The presence of the `const` attribute indicates that the local variable is
148+ declared with C/C++ `const` keyword.
149+
150+ The `dynAllocSize` specifies the size to dynamically allocate on the stack
151+ and ignores the allocation size based on the original type. This is useful
152+ when handling VLAs and is omitted when declaring regular local variables.
153+
154+ The result type is a pointer to the input's type.
155+
156+ Example:
157+
158+ ```mlir
159+ // int count = 3;
160+ %0 = cir.alloca i32, !cir.ptr<i32>, ["count", init] {alignment = 4 : i64}
161+
162+ // int *ptr;
163+ %1 = cir.alloca !cir.ptr<i32>, !cir.ptr<!cir.ptr<i32>>, ["ptr"] {alignment = 8 : i64}
164+ ...
165+ ```
166+ }];
167+
168+ let arguments = (ins
169+ Optional<PrimitiveInt>:$dynAllocSize,
170+ TypeAttr:$allocaType,
171+ StrAttr:$name,
172+ UnitAttr:$init,
173+ UnitAttr:$constant,
174+ ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$alignment,
175+ OptionalAttr<ArrayAttr>:$annotations
176+ );
177+
178+ let results = (outs Res<CIR_PointerType, "",
179+ [MemAlloc<AutomaticAllocationScopeResource>]>:$addr);
180+
181+ let skipDefaultBuilders = 1;
182+ let builders = [
183+ OpBuilder<(ins "mlir::Type":$addr, "mlir::Type":$allocaType,
184+ "llvm::StringRef":$name,
185+ "mlir::IntegerAttr":$alignment)>,
186+
187+ OpBuilder<(ins "mlir::Type":$addr,
188+ "mlir::Type":$allocaType,
189+ "llvm::StringRef":$name,
190+ "mlir::IntegerAttr":$alignment,
191+ "mlir::Value":$dynAllocSize),
192+ [{
193+ if (dynAllocSize)
194+ $_state.addOperands(dynAllocSize);
195+ build($_builder, $_state, addr, allocaType, name, alignment);
196+ }]>
197+ ];
198+
199+ let extraClassDeclaration = [{
200+ // Whether the alloca input type is a pointer.
201+ bool isPointerType() { return ::mlir::isa<::cir::PointerType>(getAllocaType()); }
202+
203+ bool isDynamic() { return (bool)getDynAllocSize(); }
204+ }];
205+
206+ let assemblyFormat = [{
207+ $allocaType `,` qualified(type($addr)) `,`
208+ ($dynAllocSize^ `:` type($dynAllocSize) `,`)?
209+ `[` $name
210+ (`,` `init` $init^)?
211+ (`,` `const` $constant^)?
212+ `]`
213+ ($annotations^)? attr-dict
214+ }];
215+
216+ let hasVerifier = 0;
217+ }
218+
219+ //===----------------------------------------------------------------------===//
220+ // LoadOp
221+ //===----------------------------------------------------------------------===//
222+
223+ def LoadOp : CIR_Op<"load", [
224+ TypesMatchWith<"type of 'result' matches pointee type of 'addr'",
225+ "addr", "result",
226+ "cast<PointerType>($_self).getPointee()">,
227+ DeclareOpInterfaceMethods<PromotableMemOpInterface>]> {
228+
229+ let summary = "Load value from memory adddress";
230+ let description = [{
231+ `cir.load` reads a value (lvalue to rvalue conversion) given an address
232+ backed up by a `cir.ptr` type. A unit attribute `deref` can be used to
233+ mark the resulting value as used by another operation to dereference
234+ a pointer. A unit attribute `volatile` can be used to indicate a volatile
235+ loading. Load can be marked atomic by using `atomic(<mem_order>)`.
236+
237+ `align` can be used to specify an alignment that's different from the
238+ default, which is computed from `result`'s type ABI data layout.
239+
240+ Example:
241+
242+ ```mlir
243+
244+ // Read from local variable, address in %0.
245+ %1 = cir.load %0 : !cir.ptr<i32>, i32
246+ ```
247+ }];
248+
249+ let arguments = (ins Arg<CIR_PointerType, "the address to load from",
250+ [MemRead]>:$addr
251+ );
252+ let results = (outs CIR_AnyType:$result);
253+
254+ let assemblyFormat = [{
255+ $addr `:` qualified(type($addr)) `,` type($result) attr-dict
256+ }];
257+
258+ // FIXME: add verifier.
259+ }
260+
118261//===----------------------------------------------------------------------===//
119262// ReturnOp
120263//===----------------------------------------------------------------------===//
0 commit comments