blob: 9ab9a7642237a3433db2a19a9cce201117f18a6b [file] [log] [blame]
// Tests creating a bundle from multiple modules using nested module format.
// Named modules are wrapped in nested module containers.
// External declarations are preserved (not resolved in bundle mode).
// RUN: iree-link --bundle \
// RUN: --link-module=%S/iree-link-module-a.mlir \
// RUN: --link-module=%S/iree-link-module-b.mlir \
// RUN: -o - | FileCheck %s
// CHECK: module {
// CHECK: module @module_a {
// CHECK: util.func private @module_b.process
// CHECK: util.func public @compute
// CHECK: flow.executable private @compute_dispatch_0
// CHECK: }
// CHECK: module @module_b {
// CHECK: util.func public @helper
// CHECK: util.func public @process
// CHECK: }
// CHECK: }
// -----
// Tests that bytecode output works correctly (auto-detected from .mlirbc
// extension).
// RUN: iree-link --bundle \
// RUN: --link-module=%S/iree-link-module-a.mlir \
// RUN: --link-module=%S/iree-link-module-b.mlir \
// RUN: -o %t.mlirbc
// RUN: iree-opt %t.mlirbc | FileCheck %s --check-prefix=BYTECODE
// BYTECODE: module {
// BYTECODE: module @module_a {
// BYTECODE: util.func public @compute
// BYTECODE: }
// BYTECODE: module @module_b {
// BYTECODE: util.func public @helper
// BYTECODE: util.func public @process
// BYTECODE: }
// BYTECODE: }
// -----
// Tests that private function shadowing works correctly in bundles.
// Both anonymous modules have conflicting private @scale_factor() functions.
// mergeModuleInto renames the second module's symbols to avoid conflicts.
// RUN: iree-link --bundle \
// RUN: --link-module=%S/iree-link-module-c.mlir \
// RUN: --link-module=%S/iree-link-anonymous.mlir \
// RUN: -o - | FileCheck %s --check-prefix=SHADOW
// SHADOW: module {
// SHADOW-DAG: util.func private @scale_factor() -> i32
// SHADOW-DAG: util.func public @subtract
// SHADOW-DAG: util.func public @double
// SHADOW-DAG: util.func private @scale_factor_0() -> i32
// SHADOW-DAG: util.func public @test_anonymous
// SHADOW: }
// -----
// Tests creating a bundle with a mix of named and anonymous modules.
// Named modules (a, b) are wrapped in nested modules.
// Anonymous module (c) operations are placed at the top level.
// RUN: iree-link --bundle \
// RUN: --link-module=%S/iree-link-module-a.mlir \
// RUN: --link-module=%S/iree-link-module-b.mlir \
// RUN: --link-module=%S/iree-link-module-c.mlir \
// RUN: -o - | FileCheck %s --check-prefix=ANONYMOUS
// ANONYMOUS: module {
// ANONYMOUS: module @module_a {
// ANONYMOUS: util.func private @module_b.process
// ANONYMOUS: util.func public @compute
// ANONYMOUS: }
// ANONYMOUS: module @module_b {
// ANONYMOUS: util.func public @helper
// ANONYMOUS: util.func public @process
// ANONYMOUS: }
// ANONYMOUS: util.func private @scale_factor
// ANONYMOUS: util.func public @subtract
// ANONYMOUS: util.func public @double
// ANONYMOUS: }
// -----
// Tests creating an empty bundle with no input modules.
// Should produce an empty module.
// RUN: iree-link --bundle -o - | FileCheck %s --check-prefix=EMPTY
// EMPTY: module {
// EMPTY: }
// -----
// Tests that globals with initializers are correctly handled during bundling.
// Two anonymous modules have conflicting @state globals with same initial value
// but different initializers. Both should be preserved with one renamed.
// RUN: iree-link --bundle \
// RUN: --link-module=%S/iree-link-globals-a.mlir \
// RUN: --link-module=%S/iree-link-globals-b.mlir \
// RUN: -o - | FileCheck %s --check-prefix=GLOBALS
// First global, initializer, and function (keeps original names).
// GLOBALS: util.global private mutable @state = dense<0.000000e+00> : tensor<f32>
// GLOBALS-NEXT: util.initializer {
// GLOBALS-NEXT: %[[C1:.+]] = arith.constant dense<1.000000e+00> : tensor<f32>
// GLOBALS-NEXT: util.global.store %[[C1]], @state : tensor<f32>
// GLOBALS-NEXT: util.return
// GLOBALS-NEXT: }
// GLOBALS-NEXT: util.func private @get_state() -> tensor<f32> {
// GLOBALS-NEXT: %[[LOAD1:.+]] = util.global.load @state : tensor<f32>
// GLOBALS-NEXT: util.return %[[LOAD1]] : tensor<f32>
// GLOBALS-NEXT: }
// Second global, initializer, and function (renamed to @state_0/@get_state_0).
// GLOBALS-NEXT: util.global private mutable @state_0 = dense<0.000000e+00> : tensor<f32>
// GLOBALS-NEXT: util.initializer {
// GLOBALS-NEXT: %[[C2:.+]] = arith.constant dense<2.000000e+00> : tensor<f32>
// GLOBALS-NEXT: util.global.store %[[C2]], @state_0 : tensor<f32>
// GLOBALS-NEXT: util.return
// GLOBALS-NEXT: }
// GLOBALS-NEXT: util.func private @get_state_0() -> tensor<f32> {
// GLOBALS-NEXT: %[[LOAD2:.+]] = util.global.load @state_0 : tensor<f32>
// GLOBALS-NEXT: util.return %[[LOAD2]] : tensor<f32>
// GLOBALS-NEXT: }
// -----
// Tests three-way global conflict with different initial values.
// All three globals should be preserved with unique names.
// RUN: iree-link --bundle \
// RUN: --link-module=%S/iree-link-globals-a.mlir \
// RUN: --link-module=%S/iree-link-globals-b.mlir \
// RUN: --link-module=%S/iree-link-globals-c.mlir \
// RUN: -o - | FileCheck %s --check-prefix=THREEWAY
// First module: global, initializer, and function (keeps original names).
// THREEWAY: util.global private mutable @state = dense<0.000000e+00> : tensor<f32>
// THREEWAY-NEXT: util.initializer {
// THREEWAY-NEXT: %[[C1:.+]] = arith.constant dense<1.000000e+00> : tensor<f32>
// THREEWAY-NEXT: util.global.store %[[C1]], @state : tensor<f32>
// THREEWAY-NEXT: util.return
// THREEWAY-NEXT: }
// THREEWAY-NEXT: util.func private @get_state() -> tensor<f32> {
// THREEWAY-NEXT: %[[LOAD1:.+]] = util.global.load @state : tensor<f32>
// THREEWAY-NEXT: util.return %[[LOAD1]] : tensor<f32>
// THREEWAY-NEXT: }
// Second module: global, initializer, and function (renamed to _0 suffix).
// THREEWAY-NEXT: util.global private mutable @state_0 = dense<0.000000e+00> : tensor<f32>
// THREEWAY-NEXT: util.initializer {
// THREEWAY-NEXT: %[[C2:.+]] = arith.constant dense<2.000000e+00> : tensor<f32>
// THREEWAY-NEXT: util.global.store %[[C2]], @state_0 : tensor<f32>
// THREEWAY-NEXT: util.return
// THREEWAY-NEXT: }
// THREEWAY-NEXT: util.func private @get_state_0() -> tensor<f32> {
// THREEWAY-NEXT: %[[LOAD2:.+]] = util.global.load @state_0 : tensor<f32>
// THREEWAY-NEXT: util.return %[[LOAD2]] : tensor<f32>
// THREEWAY-NEXT: }
// Third module: global, initializer, and function (renamed to _1 suffix).
// THREEWAY-NEXT: util.global private mutable @state_1 = dense<5.000000e+00> : tensor<f32>
// THREEWAY-NEXT: util.initializer {
// THREEWAY-NEXT: %[[C3:.+]] = arith.constant dense<3.000000e+00> : tensor<f32>
// THREEWAY-NEXT: util.global.store %[[C3]], @state_1 : tensor<f32>
// THREEWAY-NEXT: util.return
// THREEWAY-NEXT: }
// THREEWAY-NEXT: util.func private @get_state_1() -> tensor<f32> {
// THREEWAY-NEXT: %[[LOAD3:.+]] = util.global.load @state_1 : tensor<f32>
// THREEWAY-NEXT: util.return %[[LOAD3]] : tensor<f32>
// THREEWAY-NEXT: }