Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d659eaf
changelog
tim-hoffman Jun 18, 2026
d256d32
add test case
tim-hoffman Jun 18, 2026
f6e898e
split pods within arrays to multiple arrays
tim-hoffman Jun 18, 2026
cdf8853
Merge branch 'main' into th/make_pod_to_scalar_split_arrays
tim-hoffman Jun 18, 2026
6793d6e
fix compile error from merge
tim-hoffman Jun 18, 2026
477c532
fix shadowing warnings
tim-hoffman Jun 18, 2026
3d01279
reverse pipeline ordering based on this update
tim-hoffman Jun 18, 2026
e9a3bb2
clarify documentation
tim-hoffman Jun 22, 2026
6fb0125
fix: Convert subarray ops for POD arrays
tim-hoffman Jun 22, 2026
87a5fcd
Merge branch 'main' into th/make_pod_to_scalar_split_arrays
tim-hoffman Jun 22, 2026
fd339e7
update test to ensure distinct types are preserved
tim-hoffman Jun 22, 2026
bc05e5f
fix: avoid invalid member ref and fully handle array of pod
tim-hoffman Jun 22, 2026
3166d45
fix: Avoid assuming one backing array for `array.len`
tim-hoffman Jun 23, 2026
2d0db69
fix: Populate result split sizes before cloning attrs
tim-hoffman Jun 23, 2026
233a887
Merge branch 'main' into th/make_pod_to_scalar_split_arrays
tim-hoffman Jun 23, 2026
e516171
fix: split equality constraints over POD arrays
tim-hoffman Jun 23, 2026
c5d0d62
fix: Avoid creating arrays whose elements are arrays
tim-hoffman Jun 23, 2026
34bd6e0
fix dangling ref
tim-hoffman Jun 23, 2026
4563267
additional regression test
tim-hoffman Jun 23, 2026
fae7959
clang-tidy cleanup
tim-hoffman Jun 23, 2026
26c1cc5
fix: Flatten array-valued leaves for initialized array.new
tim-hoffman Jun 24, 2026
69cfd98
fix: Convert pod.read array fields before splitting array reads
tim-hoffman Jun 24, 2026
3449ad6
fix: Preserve affine operands for leaf-array dimensions
tim-hoffman Jul 1, 2026
82c77cd
Merge branch 'main' into th/make_pod_to_scalar_split_arrays
tim-hoffman Jul 1, 2026
04c59af
fix: Preserve original rank for array.len
tim-hoffman Jul 1, 2026
ca87a4e
fix: Support dynamic nested POD arrays
tim-hoffman Jul 1, 2026
e8bceaa
fix: Handle uninitialized deferred POD-array reads
tim-hoffman Jul 2, 2026
0b804d4
fix: Apply uninitialized fallback to static POD arrays
tim-hoffman Jul 2, 2026
3d0e443
fix: Avoid aborting on dynamic nested POD operands
tim-hoffman Jul 2, 2026
9956341
fix: Split pod.read-backed array returns
tim-hoffman Jul 2, 2026
ce0ce8f
fix: Rewrite quantifiers over POD arrays
tim-hoffman Jul 2, 2026
ac379dd
clang-tidy
tim-hoffman Jul 2, 2026
3b352b3
fix: Honor writes before resolving virtual POD reads
tim-hoffman Jul 2, 2026
8ea12b1
fix: Split unifiable casts for POD arrays
tim-hoffman Jul 2, 2026
ddc518b
fix: Split POD-array call operands from POD reads
tim-hoffman Jul 2, 2026
1401bf2
fix: Preserve member read offsets when splitting POD arrays
tim-hoffman Jul 2, 2026
4021ad1
Merge branch 'main' into th/make_pod_to_scalar_split_arrays
tim-hoffman Jul 2, 2026
74d0b45
fix: Preserve the source shape for affine empty-POD arrays
tim-hoffman Jul 2, 2026
bd186a3
fix: Use a writable affine-aware array for static POD-array leaves
tim-hoffman Jul 2, 2026
21f2e6d
Merge branch 'main' into th/make_pod_to_scalar_split_arrays
tim-hoffman Jul 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
changed:
- Update `llzk-pod-to-scalar` to split pods within arrays by creating multiple arrays.
10 changes: 9 additions & 1 deletion include/llzk/Dialect/POD/Transforms/TransformationPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ include "llzk/Pass/PassBase.td"
def PodToScalarPass : LLZKPass<"llzk-pod-to-scalar"> {
let summary = "Replace PODs with scalar values";
let description = [{
Replace `pod.type` values with the proper number of scalar values
Scalarize `pod.type` values by splitting POD-typed struct members into
multiple scalar members, splitting POD-typed array elements into parallel
arrays, then rewriting affected member accesses plus function signatures,
calls, and returns, and finally running POD-specific SROA + mem2reg cleanup
so the remaining POD storage is promoted to SSA values.

If it is necessary to scalarize both PODs and arrays, run this pass before
running the `-llzk-array-to-scalar` pass because that pass will not scalarize
array types that are within a POD type.
}];
}

Expand Down
8 changes: 8 additions & 0 deletions include/llzk/Util/TypeHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ namespace llzk {

bool isDynamic(mlir::IntegerAttr intAttr);

/// Flatten any array-valued element type into the dimensions of `outerArrTy`.
///
/// This is used when an LLZK array logically resolves to a higher-rank array even though array
/// element types cannot themselves be arrays. The returned type keeps `outerArrTy`'s leading
/// dimensions, appends any nested dimensions from `elementType`, and uses the innermost non-array
/// element type as the final element type.
array::ArrayType flattenArrayElementType(array::ArrayType outerArrTy, mlir::Type elementType);

/// Compute the cardinality (i.e. number of scalar constraints) for an EmitEqualityOp type since the
/// op can be used to constrain two same-size arrays.
uint64_t computeEmitEqCardinality(mlir::Type type);
Expand Down
3,440 changes: 3,027 additions & 413 deletions lib/Dialect/POD/Transforms/PodToScalarPass.cpp

Large diffs are not rendered by default.

14 changes: 1 addition & 13 deletions lib/Dialect/Polymorphic/Transforms/FlatteningPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -969,18 +969,6 @@ LogicalResult run(ModuleOp modOp, ConversionTracker &tracker) {

namespace Step1B_InstantiateFunctions {

/// Flatten nested array instantiations by appending any dimensions contributed by the converted
/// element type onto the outer array. This allows wildcard element types to resolve to
/// higher-rank arrays even though LLZK array element types cannot themselves be arrays.
static ArrayType flattenInstantiatedArrayType(ArrayType inputTy, Type convertedElemTy) {
SmallVector<Attribute> mergedDims(inputTy.getDimensionSizes());
while (ArrayType nestedArrTy = llvm::dyn_cast<ArrayType>(convertedElemTy)) {
llvm::append_range(mergedDims, nestedArrTy.getDimensionSizes());
convertedElemTy = nestedArrTy.getElementType();
}
return ArrayType::get(convertedElemTy, mergedDims);
}

/// TypeConverter for function instantiation that replaces TypeVarType and symbolic
/// ArrayType/StructType parameters with their concrete values determined by unification.
class FuncInstTypeConverter : public TypeConverter {
Expand Down Expand Up @@ -1020,7 +1008,7 @@ class FuncInstTypeConverter : public TypeConverter {
if (!changed && newElemTy == inputTy.getElementType()) {
return inputTy;
}
return flattenInstantiatedArrayType(
return flattenArrayElementType(
inputTy.cloneWith(inputTy.getElementType(), updated), newElemTy
);
});
Expand Down
10 changes: 5 additions & 5 deletions lib/Transforms/LLZKTransformationPassPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ void buildFullStructInliningPipelineImpl(
}
pm.addPass(polymorphic::createFlatteningPass(flattening));

// Run array-to-scalar first because it can split arrays within a pod
// but pod-to-scalar cannot split pods within an array.
if (arrayToScalar) {
pm.addPass(array::createArrayToScalarPass());
}
// Run pod-to-scalar first because it is able to split `pod.type` used as array element type
// (into parallel arrays) so it should be able to fully remove all `pod.type` usages.
if (podToScalar) {
pm.addPass(pod::createPodToScalarPass());
}
if (arrayToScalar) {
pm.addPass(array::createArrayToScalarPass());
}
// Canonicalize to remove known-condition `scf.if` regions so struct inlining
// can link "@compute" calls to struct members.
pm.addPass(mlir::createCanonicalizerPass());
Expand Down
9 changes: 9 additions & 0 deletions lib/Util/TypeHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,15 @@ bool hasAffineMapAttr(Type type) {

bool isDynamic(IntegerAttr intAttr) { return ShapedType::isDynamic(fromAPInt(intAttr.getValue())); }

ArrayType flattenArrayElementType(ArrayType outerArrTy, Type elementType) {
SmallVector<Attribute> mergedDims(outerArrTy.getDimensionSizes());
while (ArrayType nestedArrTy = llvm::dyn_cast<ArrayType>(elementType)) {
llvm::append_range(mergedDims, nestedArrTy.getDimensionSizes());
elementType = nestedArrTy.getElementType();
}
return ArrayType::get(elementType, mergedDims);
}

uint64_t computeEmitEqCardinality(Type type) {
struct Impl : LLZKTypeSwitch<Impl, uint64_t> {
uint64_t caseBool(IntegerType) { return 1; }
Expand Down
30 changes: 30 additions & 0 deletions test/Transforms/PodToScalar/array_extract_insert.llzk
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// RUN: llzk-opt -split-input-file -llzk-pod-to-scalar %s | FileCheck --enable-var-scope %s

!Pair = !pod.type<[@lhs: index, @rhs: !felt.type]>
!PairRow = !array.type<2 x !Pair>
!PairMatrix = !array.type<2,2 x !Pair>
module attributes {llzk.lang} {
function.def @extract_then_insert(%src: !PairMatrix) -> !PairMatrix {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%row = array.extract %src[%c0] : !PairMatrix
%dst = array.new : !PairMatrix
array.insert %dst[%c1] = %row : !PairMatrix, !PairRow
function.return %dst : !PairMatrix
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @extract_then_insert
// CHECK-SAME: (%[[VAL_0:[0-9a-zA-Z_\.]+]]: !array.type<2,2 x index>, %[[VAL_1:[0-9a-zA-Z_\.]+]]: !array.type<2,2 x !felt.type>)
// CHECK-SAME: -> (!array.type<2,2 x index>, !array.type<2,2 x !felt.type>) {
// CHECK-NEXT: %[[VAL_2:[0-9a-zA-Z_\.]+]] = arith.constant 0 : index
// CHECK-NEXT: %[[VAL_3:[0-9a-zA-Z_\.]+]] = arith.constant 1 : index
// CHECK-NEXT: %[[VAL_4:[0-9a-zA-Z_\.]+]] = array.extract %[[VAL_0]]{{\[}}%[[VAL_2]]] : <2,2 x index>
// CHECK-NEXT: %[[VAL_5:[0-9a-zA-Z_\.]+]] = array.extract %[[VAL_1]]{{\[}}%[[VAL_2]]] : <2,2 x !felt.type>
// CHECK-NEXT: %[[VAL_6:[0-9a-zA-Z_\.]+]] = array.new : <2,2 x index>
// CHECK-NEXT: %[[VAL_7:[0-9a-zA-Z_\.]+]] = array.new : <2,2 x !felt.type>
// CHECK-NEXT: array.insert %[[VAL_6]]{{\[}}%[[VAL_3]]] = %[[VAL_4]] : <2,2 x index>, <2 x index>
// CHECK-NEXT: array.insert %[[VAL_7]]{{\[}}%[[VAL_3]]] = %[[VAL_5]] : <2,2 x !felt.type>, <2 x !felt.type>
// CHECK-NEXT: function.return %[[VAL_6]], %[[VAL_7]] : !array.type<2,2 x index>, !array.type<2,2 x !felt.type>
// CHECK-NEXT: }
// CHECK-NEXT: }
78 changes: 78 additions & 0 deletions test/Transforms/PodToScalar/array_leaf_in_pod_array.llzk
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// RUN: llzk-opt -split-input-file -llzk-pod-to-scalar %s | FileCheck --enable-var-scope %s

!Elem = !pod.type<[@vals: !array.type<3 x index>, @tag: index]>
!ElemArray = !array.type<2 x !Elem>
module attributes {llzk.lang} {
function.def @pass_through(%arg: !ElemArray) -> !ElemArray {
function.return %arg : !ElemArray
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @pass_through(
// CHECK-SAME: %[[VAL_0:[0-9a-zA-Z_\.]+]]: !array.type<2,3 x index>,
// CHECK-SAME: %[[VAL_1:[0-9a-zA-Z_\.]+]]: !array.type<2 x index>
// CHECK-SAME: ) -> (!array.type<2,3 x index>, !array.type<2 x index>) {
// CHECK-NEXT: function.return %[[VAL_0]], %[[VAL_1]] : !array.type<2,3 x index>, !array.type<2 x index>
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

!Elem = !pod.type<[@vals: !array.type<3 x index>]>
!ElemArray = !array.type<2 x !Elem>
module attributes {llzk.lang} {
function.def @pack(
%a0: index, %a1: index, %a2: index, %b0: index, %b1: index, %b2: index
) -> !ElemArray {
%vals0 = array.new %a0, %a1, %a2 : !array.type<3 x index>
%vals1 = array.new %b0, %b1, %b2 : !array.type<3 x index>
%lhs = pod.new : !Elem
pod.write %lhs[@vals] = %vals0 : !Elem, !array.type<3 x index>
%rhs = pod.new : !Elem
pod.write %rhs[@vals] = %vals1 : !Elem, !array.type<3 x index>
%arr = array.new %lhs, %rhs : !ElemArray
function.return %arr : !ElemArray
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @pack(
// CHECK-SAME: %[[VAL_0:[0-9a-zA-Z_\.]+]]: index, %[[VAL_1:[0-9a-zA-Z_\.]+]]: index,
// CHECK-SAME: %[[VAL_2:[0-9a-zA-Z_\.]+]]: index, %[[VAL_3:[0-9a-zA-Z_\.]+]]: index,
// CHECK-SAME: %[[VAL_4:[0-9a-zA-Z_\.]+]]: index, %[[VAL_5:[0-9a-zA-Z_\.]+]]: index
// CHECK-SAME: ) -> !array.type<2,3 x index> {
// CHECK-NEXT: %[[VAL_6:[0-9a-zA-Z_\.]+]] = array.new %[[VAL_0]], %[[VAL_1]], %[[VAL_2]] : <3 x index>
// CHECK-NEXT: %[[VAL_7:[0-9a-zA-Z_\.]+]] = array.new %[[VAL_3]], %[[VAL_4]], %[[VAL_5]] : <3 x index>
// CHECK-NEXT: %[[VAL_8:[0-9a-zA-Z_\.]+]] = array.new : <2,3 x index>
// CHECK-NEXT: %[[VAL_9:[0-9a-zA-Z_\.]+]] = arith.constant 0 : index
// CHECK-NEXT: array.insert %[[VAL_8]]{{\[}}%[[VAL_9]]] = %[[VAL_6]] : <2,3 x index>, <3 x index>
// CHECK-NEXT: %[[VAL_10:[0-9a-zA-Z_\.]+]] = arith.constant 1 : index
// CHECK-NEXT: array.insert %[[VAL_8]]{{\[}}%[[VAL_10]]] = %[[VAL_7]] : <2,3 x index>, <3 x index>
// CHECK-NEXT: function.return %[[VAL_8]] : !array.type<2,3 x index>
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

!Elem = !pod.type<[@vals: !array.type<3 x index>, @tag: index]>
!ElemArray = !array.type<2 x !Elem>
module attributes {llzk.lang} {
function.def @update_first(%arr: !ElemArray, %newVals: !array.type<3 x index>) -> !ElemArray {
%c0 = arith.constant 0 : index
%elem = array.read %arr[%c0] : !ElemArray, !Elem
pod.write %elem[@vals] = %newVals : !Elem, !array.type<3 x index>
array.write %arr[%c0] = %elem : !ElemArray, !Elem
function.return %arr : !ElemArray
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @update_first(
// CHECK-SAME: %[[VAL_0:[0-9a-zA-Z_\.]+]]: !array.type<2,3 x index>,
// CHECK-SAME: %[[VAL_1:[0-9a-zA-Z_\.]+]]: !array.type<2 x index>,
// CHECK-SAME: %[[VAL_2:[0-9a-zA-Z_\.]+]]: !array.type<3 x index>
// CHECK-SAME: ) -> (!array.type<2,3 x index>, !array.type<2 x index>) {
// CHECK-NEXT: %[[VAL_3:[0-9a-zA-Z_\.]+]] = arith.constant 0 : index
// CHECK-NEXT: %[[VAL_4:[0-9a-zA-Z_\.]+]] = array.extract %[[VAL_0]]{{\[}}%[[VAL_3]]] : <2,3 x index>
// CHECK-NEXT: %[[VAL_5:[0-9a-zA-Z_\.]+]] = array.read %[[VAL_1]]{{\[}}%[[VAL_3]]] : <2 x index>, index
// CHECK-NEXT: array.insert %[[VAL_0]]{{\[}}%[[VAL_3]]] = %[[VAL_2]] : <2,3 x index>, <3 x index>
// CHECK-NEXT: array.write %[[VAL_1]]{{\[}}%[[VAL_3]]] = %[[VAL_5]] : <2 x index>, index
// CHECK-NEXT: function.return %[[VAL_0]], %[[VAL_1]] : !array.type<2,3 x index>, !array.type<2 x index>
// CHECK-NEXT: }
// CHECK-NEXT: }
129 changes: 129 additions & 0 deletions test/Transforms/PodToScalar/array_length.llzk
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// RUN: llzk-opt -split-input-file -llzk-pod-to-scalar %s | FileCheck --enable-var-scope %s

!Pair = !pod.type<[@x: index, @y: !felt.type]>
module attributes {llzk.lang} {
function.def @len_multi_leaf(%arr: !array.type<2 x !Pair>, %dim: index) -> index {
%len = array.len %arr, %dim : !array.type<2 x !Pair>
function.return %len : index
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_multi_leaf(%[[ARR_X:[0-9a-zA-Z_\.]+]]: !array.type<2 x index>, %[[ARR_Y:[0-9a-zA-Z_\.]+]]: !array.type<2 x !felt.type>, %[[DIM:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[LEN:[0-9a-zA-Z_\.]+]] = array.len %[[ARR_X]], %[[DIM]] : <2 x index>
// CHECK-NEXT: function.return %[[LEN]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

// Tests: preserve the `array.len` semantics so a dynamic dimension selection
// cannot observe dimensions that did not exist before pod flattening.
!Elem = !pod.type<[@vals: !array.type<3 x index>]>
module attributes {llzk.lang} {
function.def @len_leaf_array_dynamic_dim(%arr: !array.type<2 x !Elem>, %dim: index) -> index {
%len = array.len %arr, %dim : !array.type<2 x !Elem>
function.return %len : index
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_leaf_array_dynamic_dim(%[[ARR:[0-9a-zA-Z_\.]+]]: !array.type<2,3 x index>, %[[DIM:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[SHAPE:[0-9a-zA-Z_\.]+]] = array.new : <2 x index>
// CHECK-NEXT: %[[LEN:[0-9a-zA-Z_\.]+]] = array.len %[[SHAPE]], %[[DIM]] : <2 x index>
// CHECK-NEXT: function.return %[[LEN]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

module attributes {llzk.lang} {
function.def @len_empty_leaf_static_create(%dim: index) -> index {
%arr = array.new : !array.type<4 x !pod.type<[]>>
%len = array.len %arr, %dim : !array.type<4 x !pod.type<[]>>
function.return %len : index
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_empty_leaf_static_create(%[[DIM:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[ARR:[0-9a-zA-Z_\.]+]] = array.new : <4 x index>
// CHECK-NEXT: %[[LEN:[0-9a-zA-Z_\.]+]] = array.len %[[ARR]], %[[DIM]] : <4 x index>
// CHECK-NEXT: function.return %[[LEN]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

#map = affine_map<()[s0] -> (s0)>
module attributes {llzk.lang} {
function.def @len_empty_leaf_array(%n: index, %dim: index) -> index {
%arr = array.new{()[%n]} : !array.type<#map x !pod.type<[]>>
%len = array.len %arr, %dim : !array.type<#map x !pod.type<[]>>
function.return %len : index
}
}
// CHECK: #[[$MAP:[0-9a-zA-Z_\.]+]] = affine_map<()[s0] -> (s0)>
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_empty_leaf_array(%[[N:[0-9a-zA-Z_\.]+]]: index, %[[DIM:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[ARR:[0-9a-zA-Z_\.]+]] = array.new{()[%[[N]]]} : <#[[$MAP]] x index>
// CHECK-NEXT: %[[LEN:[0-9a-zA-Z_\.]+]] = array.len %[[ARR]], %[[DIM]] : <#[[$MAP]] x index>
// CHECK-NEXT: function.return %[[LEN]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

module attributes {llzk.lang} {
function.def @len_empty_leaf_static_arg(%arr: !array.type<4 x !pod.type<[]>>, %dim: index) -> index {
%len = array.len %arr, %dim : !array.type<4 x !pod.type<[]>>
function.return %len : index
}
}
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_empty_leaf_static_arg(%[[ARR:[0-9a-zA-Z_\.]+]]: !array.type<4 x index>, %[[DIM:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[LEN:[0-9a-zA-Z_\.]+]] = array.len %[[ARR]], %[[DIM]] : <4 x index>
// CHECK-NEXT: function.return %[[LEN]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

#map_arg = affine_map<()[s0] -> (s0)>
module attributes {llzk.lang} {
function.def @len_empty_leaf_affine_arg(
%arr: !array.type<#map_arg x !pod.type<[]>>, %dim: index
) -> index {
%len = array.len %arr, %dim : !array.type<#map_arg x !pod.type<[]>>
function.return %len : index
}
}
// CHECK: #[[$MAP:[0-9a-zA-Z_\.]+]] = affine_map<()[s0] -> (s0)>
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_empty_leaf_affine_arg(%[[ARR:[0-9a-zA-Z_\.]+]]: !array.type<#[[$MAP]] x index>, %[[DIM:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[LEN:[0-9a-zA-Z_\.]+]] = array.len %[[ARR]], %[[DIM]] : <#[[$MAP]] x index>
// CHECK-NEXT: function.return %[[LEN]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
// -----

#map_call = affine_map<()[s0] -> (s0)>
module attributes {llzk.lang} {
function.def @len_empty_leaf_affine_sink(
%arr: !array.type<#map_call x !pod.type<[]>>, %dim: index
) -> index {
%len = array.len %arr, %dim : !array.type<#map_call x !pod.type<[]>>
function.return %len : index
}

function.def @len_empty_leaf_affine_call(
%arr: !array.type<#map_call x !pod.type<[]>>, %dim: index
) -> index {
%len = function.call @len_empty_leaf_affine_sink(%arr, %dim)
: (!array.type<#map_call x !pod.type<[]>>, index) -> index
function.return %len : index
}
}
// CHECK: #[[$MAP:[0-9a-zA-Z_\.]+]] = affine_map<()[s0] -> (s0)>
// CHECK-LABEL: module attributes {llzk.lang} {
// CHECK-NEXT: function.def @len_empty_leaf_affine_sink(%[[ARR0:[0-9a-zA-Z_\.]+]]: !array.type<#[[$MAP]] x index>, %[[DIM0:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[LEN0:[0-9a-zA-Z_\.]+]] = array.len %[[ARR0]], %[[DIM0]] : <#[[$MAP]] x index>
// CHECK-NEXT: function.return %[[LEN0]] : index
// CHECK-NEXT: }
// CHECK-NEXT: function.def @len_empty_leaf_affine_call(%[[ARR1:[0-9a-zA-Z_\.]+]]: !array.type<#[[$MAP]] x index>, %[[DIM1:[0-9a-zA-Z_\.]+]]: index) -> index {
// CHECK-NEXT: %[[LEN1:[0-9a-zA-Z_\.]+]] = function.call @len_empty_leaf_affine_sink(%[[ARR1]], %[[DIM1]]) : (!array.type<#[[$MAP]] x index>, index) -> index
// CHECK-NEXT: function.return %[[LEN1]] : index
// CHECK-NEXT: }
// CHECK-NEXT: }
Loading