diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td --- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td +++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td @@ -503,6 +503,16 @@ // Externally visible constant variable. memref.global constant @c : memref<2xi32> = dense<1, 4> ``` + + A global variable may specify an alignment (a power of 2 positive + integer). This value is passed during lowering to the `llvm.mlir.global` + operation. + + Example: + + ```mlir + // Require alignment on 64 byte barrier + memref.global "private" @x : memref<2xf32> = dense<0.0,2.0> {alignment = 64} }]; let arguments = (ins @@ -510,7 +520,8 @@ OptionalAttr:$sym_visibility, TypeAttr:$type, OptionalAttr:$initial_value, - UnitAttr:$constant + UnitAttr:$constant, + OptionalAttr:$alignment ); let assemblyFormat = [{ diff --git a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp --- a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp +++ b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp @@ -2300,9 +2300,11 @@ initialValue = elementsAttr.getValue({}); } + uint64_t alignment = global.alignment().getValueOr(0); + rewriter.replaceOpWithNewOp( global, arrayTy, global.constant(), linkage, global.sym_name(), - initialValue, /*alignment=*/0, type.getMemorySpaceAsInt()); + initialValue, alignment, type.getMemorySpaceAsInt()); return success(); } }; diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp --- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp +++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp @@ -1114,6 +1114,13 @@ } } + if (Optional alignAttr = op.alignment()) { + uint64_t value = alignAttr.getValue(); + if (!llvm::isPowerOf2_64(value)) + return op->emitError() + << "alignment attribute value " << value << " is not a power of 2"; + } + // TODO: verify visibility for declarations. return success(); } diff --git a/mlir/lib/Dialect/StandardOps/Transforms/TensorConstantBufferize.cpp b/mlir/lib/Dialect/StandardOps/Transforms/TensorConstantBufferize.cpp --- a/mlir/lib/Dialect/StandardOps/Transforms/TensorConstantBufferize.cpp +++ b/mlir/lib/Dialect/StandardOps/Transforms/TensorConstantBufferize.cpp @@ -48,7 +48,8 @@ /*sym_visibility=*/globalBuilder.getStringAttr("private"), /*type=*/typeConverter.convertType(type), /*initial_value=*/constantOp.getValue().cast(), - /*constant=*/true); + /*constant=*/true, + /*alignment=*/IntegerAttr()); symbolTable.insert(global); // The symbol table inserts at the end of the module, but globals are a bit // nicer if they are at the beginning. diff --git a/mlir/test/Conversion/StandardToLLVM/standard-to-llvm.mlir b/mlir/test/Conversion/StandardToLLVM/standard-to-llvm.mlir --- a/mlir/test/Conversion/StandardToLLVM/standard-to-llvm.mlir +++ b/mlir/test/Conversion/StandardToLLVM/standard-to-llvm.mlir @@ -240,6 +240,11 @@ return } +// Test global variable alignment translation +// CHECK: llvm.mlir.global private @gv4(dense<[0.000000e+00, 1.000000e+00, 2.000000e+00, 3.000000e+00]> : tensor<4xf32>) {alignment = 64 : i64} : !llvm.array<4 x f32> +memref.global "private" @gv4 : memref<4xf32> = dense<[0.0, 1.0, 2.0, 3.0]> { alignment = 64 } + + // This should not trigger an assertion by creating an LLVM::CallOp with a // nullptr result type. diff --git a/mlir/test/Dialect/MemRef/invalid.mlir b/mlir/test/Dialect/MemRef/invalid.mlir --- a/mlir/test/Dialect/MemRef/invalid.mlir +++ b/mlir/test/Dialect/MemRef/invalid.mlir @@ -168,6 +168,11 @@ // ----- +// expected-error @+1 {{alignment attribute value 63 is not a power of 2}} +memref.global "private" @foo : memref<4xf32> = dense<[0.0, 1.0, 2.0, 3.0]> { alignment = 63 } + +// ----- + // expected-error @+1 {{expected valid '@'-identifier for symbol name}} memref.global "private" "public" @foo : memref<2x2xf32> = "foo"