[clang] [CIR] Upstream basic alloca and load support (PR #128792)
Bruno Cardoso Lopes via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 26 10:58:21 PST 2025
================
@@ -115,6 +115,149 @@ def ConstantOp : CIR_Op<"const",
let hasFolder = 1;
}
+//===----------------------------------------------------------------------===//
+// AllocaOp
+//===----------------------------------------------------------------------===//
+
+class AllocaTypesMatchWith<string summary, string lhsArg, string rhsArg,
+ string transform, string comparator = "std::equal_to<>()">
+ : PredOpTrait<summary, CPred<
+ comparator # "(" #
+ !subst("$_self", "$" # lhsArg # ".getType()", transform) #
+ ", $" # rhsArg # ")">> {
+ string lhs = lhsArg;
+ string rhs = rhsArg;
+ string transformer = transform;
+}
+
+def AllocaOp : CIR_Op<"alloca", [
+ AllocaTypesMatchWith<"'allocaType' matches pointee type of 'addr'",
+ "addr", "allocaType",
+ "cast<PointerType>($_self).getPointee()">,
+ DeclareOpInterfaceMethods<PromotableAllocationOpInterface>]> {
+ let summary = "Defines a scope-local variable";
+ let description = [{
+ The `cir.alloca` operation defines a scope-local variable.
+
+ The presence `init` attribute indicates that the local variable represented
+ by this alloca was originally initialized in C/C++ source code. In such
+ cases, the first use contains the initialization (a cir.store, a cir.call
+ to a ctor, etc).
+
+ The presence of the `const` attribute indicates that the local variable is
+ declared with C/C++ `const` keyword.
+
+ The `dynAllocSize` specifies the size to dynamically allocate on the stack
+ and ignores the allocation size based on the original type. This is useful
+ when handling VLAs and is omitted when declaring regular local variables.
+
+ The result type is a pointer to the input's type.
+
+ Example:
+
+ ```mlir
+ // int count = 3;
+ %0 = cir.alloca i32, !cir.ptr<i32>, ["count", init] {alignment = 4 : i64}
+
+ // int *ptr;
+ %1 = cir.alloca !cir.ptr<i32>, !cir.ptr<!cir.ptr<i32>>, ["ptr"] {alignment = 8 : i64}
+ ...
+ ```
+ }];
+
+ let arguments = (ins
+ Optional<PrimitiveInt>:$dynAllocSize,
+ TypeAttr:$allocaType,
+ StrAttr:$name,
+ UnitAttr:$init,
+ UnitAttr:$constant,
+ ConfinedAttr<OptionalAttr<I64Attr>, [IntMinValue<0>]>:$alignment,
+ OptionalAttr<ArrayAttr>:$annotations
+ );
+
+ let results = (outs Res<CIR_PointerType, "",
+ [MemAlloc<AutomaticAllocationScopeResource>]>:$addr);
+
+ let skipDefaultBuilders = 1;
+ let builders = [
+ OpBuilder<(ins "mlir::Type":$addr, "mlir::Type":$allocaType,
+ "llvm::StringRef":$name,
+ "mlir::IntegerAttr":$alignment)>,
+
+ OpBuilder<(ins "mlir::Type":$addr,
+ "mlir::Type":$allocaType,
+ "llvm::StringRef":$name,
+ "mlir::IntegerAttr":$alignment,
+ "mlir::Value":$dynAllocSize),
+ [{
+ if (dynAllocSize)
+ $_state.addOperands(dynAllocSize);
+ build($_builder, $_state, addr, allocaType, name, alignment);
+ }]>
+ ];
+
+ let extraClassDeclaration = [{
+ // Whether the alloca input type is a pointer.
+ bool isPointerType() { return ::mlir::isa<::cir::PointerType>(getAllocaType()); }
+
+ bool isDynamic() { return (bool)getDynAllocSize(); }
+ }];
+
+ let assemblyFormat = [{
+ $allocaType `,` qualified(type($addr)) `,`
+ ($dynAllocSize^ `:` type($dynAllocSize) `,`)?
+ `[` $name
+ (`,` `init` $init^)?
+ (`,` `const` $constant^)?
+ `]`
+ ($annotations^)? attr-dict
+ }];
+
+ let hasVerifier = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// LoadOp
+//===----------------------------------------------------------------------===//
+
+def LoadOp : CIR_Op<"load", [
+ TypesMatchWith<"type of 'result' matches pointee type of 'addr'",
+ "addr", "result",
+ "cast<PointerType>($_self).getPointee()">,
+ DeclareOpInterfaceMethods<PromotableMemOpInterface>]> {
+
+ let summary = "Load value from memory adddress";
+ let description = [{
+ `cir.load` reads a value (lvalue to rvalue conversion) given an address
+ backed up by a `cir.ptr` type. A unit attribute `deref` can be used to
+ mark the resulting value as used by another operation to dereference
+ a pointer. A unit attribute `volatile` can be used to indicate a volatile
+ loading. Load can be marked atomic by using `atomic(<mem_order>)`.
+
+ `align` can be used to specify an alignment that's different from the
+ default, which is computed from `result`'s type ABI data layout.
+
+ Example:
+
+ ```mlir
+
+ // Read from local variable, address in %0.
+ %1 = cir.load %0 : !cir.ptr<i32>, i32
+ ```
+ }];
+
+ let arguments = (ins Arg<CIR_PointerType, "the address to load from",
+ [MemRead]>:$addr
+ );
----------------
bcardosolopes wrote:
The closing paren probably belongs in the line above?
https://github.com/llvm/llvm-project/pull/128792
More information about the cfe-commits
mailing list