-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[CIR] Upstream basic alloca and load support #128792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
| ); | ||
|
||
| let results = (outs CIR_AnyType:$result); | ||
|
|
||
| let assemblyFormat = [{ | ||
| $addr `:` qualified(type($addr)) `,` type($result) attr-dict | ||
| }]; | ||
|
|
||
| // FIXME: add verifier. | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // ReturnOp | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This class provides a simple wrapper for a pair of a pointer and an | ||
| // alignment. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_CLANG_LIB_CIR_ADDRESS_H | ||
|
||
| #define LLVM_CLANG_LIB_CIR_ADDRESS_H | ||
|
|
||
| #include "mlir/IR/Value.h" | ||
| #include "clang/AST/CharUnits.h" | ||
| #include "clang/CIR/Dialect/IR/CIRTypes.h" | ||
| #include "llvm/ADT/PointerIntPair.h" | ||
|
|
||
| namespace clang::CIRGen { | ||
|
|
||
| class Address { | ||
|
|
||
| // The boolean flag indicates whether the pointer is known to be non-null. | ||
| llvm::PointerIntPair<mlir::Value, 1, bool> pointerAndKnownNonNull; | ||
|
|
||
| /// The expected CIR type of the pointer. Carrying accurate element type | ||
| /// information in Address makes it more convenient to work with Address | ||
| /// values and allows frontend assertions to catch simple mistakes. | ||
| mlir::Type elementType; | ||
|
|
||
| clang::CharUnits alignment; | ||
|
|
||
| protected: | ||
| Address(std::nullptr_t) : elementType(nullptr) {} | ||
|
|
||
| public: | ||
| Address(mlir::Value pointer, mlir::Type elementType, | ||
| clang::CharUnits alignment) | ||
| : pointerAndKnownNonNull(pointer, false), elementType(elementType), | ||
| alignment(alignment) { | ||
| assert(mlir::isa<cir::PointerType>(pointer.getType()) && | ||
| "Expected cir.ptr type"); | ||
|
|
||
| assert(pointer && "Pointer cannot be null"); | ||
| assert(elementType && "Element type cannot be null"); | ||
| assert(!alignment.isZero() && "Alignment cannot be zero"); | ||
|
|
||
| assert(mlir::cast<cir::PointerType>(pointer.getType()).getPointee() == | ||
| elementType); | ||
| } | ||
|
|
||
| static Address invalid() { return Address(nullptr); } | ||
| bool isValid() const { | ||
| return pointerAndKnownNonNull.getPointer() != nullptr; | ||
| } | ||
|
|
||
| mlir::Value getPointer() const { | ||
| assert(isValid()); | ||
| return pointerAndKnownNonNull.getPointer(); | ||
| } | ||
|
|
||
| mlir::Type getElementType() const { | ||
| assert(isValid()); | ||
| assert(mlir::cast<cir::PointerType>( | ||
| pointerAndKnownNonNull.getPointer().getType()) | ||
| .getPointee() == elementType); | ||
| return elementType; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace clang::CIRGen | ||
|
|
||
| #endif // LLVM_CLANG_LIB_CIR_ADDRESS_H | ||
Uh oh!
There was an error while loading. Please reload this page.