blob: a6176142f1746334031cf1abe75871a0882b8091 [file] [log] [blame]
// RUN: mlir-opt %s --pass-pipeline="builtin.module(llvm.func(llvm-type-consistency))" --split-input-file | FileCheck %s
// CHECK-LABEL: llvm.func @same_address
llvm.func @same_address(%arg: i32) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
// CHECK: = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32)>
%7 = llvm.getelementptr %1[8] : (!llvm.ptr) -> !llvm.ptr, i8
llvm.store %arg, %7 : i32, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @same_address_keep_inbounds
llvm.func @same_address_keep_inbounds(%arg: i32) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
// CHECK: = llvm.getelementptr inbounds %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32)>
%7 = llvm.getelementptr inbounds %1[8] : (!llvm.ptr) -> !llvm.ptr, i8
llvm.store %arg, %7 : i32, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @index_in_final_padding
llvm.func @index_in_final_padding(%arg: i32) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i8)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i8)> : (i32) -> !llvm.ptr
// CHECK: = llvm.getelementptr %[[ALLOCA]][7] : (!llvm.ptr) -> !llvm.ptr, i8
%7 = llvm.getelementptr %1[7] : (!llvm.ptr) -> !llvm.ptr, i8
llvm.store %arg, %7 : i32, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @index_out_of_bounds
llvm.func @index_out_of_bounds(%arg: i32) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr
// CHECK: = llvm.getelementptr %[[ALLOCA]][9] : (!llvm.ptr) -> !llvm.ptr, i8
%7 = llvm.getelementptr %1[9] : (!llvm.ptr) -> !llvm.ptr, i8
llvm.store %arg, %7 : i32, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @index_in_padding
llvm.func @index_in_padding(%arg: i16) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, i32)> : (i32) -> !llvm.ptr
// CHECK: = llvm.getelementptr %[[ALLOCA]][2] : (!llvm.ptr) -> !llvm.ptr, i8
%7 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8
llvm.store %arg, %7 : i16, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @index_not_in_padding_because_packed
llvm.func @index_not_in_padding_because_packed(%arg: i16) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", packed (i16, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", packed (i16, i32)> : (i32) -> !llvm.ptr
// CHECK: = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i16, i32)>
%7 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8
llvm.store %arg, %7 : i16, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @no_crash_on_negative_gep_index
llvm.func @no_crash_on_negative_gep_index() {
%0 = llvm.mlir.constant(1.000000e+00 : f16) : f16
%1 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32)>
%2 = llvm.alloca %1 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
// CHECK: llvm.getelementptr %[[ALLOCA]][-1] : (!llvm.ptr) -> !llvm.ptr, f32
%3 = llvm.getelementptr %2[-1] : (!llvm.ptr) -> !llvm.ptr, f32
llvm.store %0, %3 : f16, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_ints
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_ints(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST32:.*]] = llvm.mlir.constant(32 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32)>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
llvm.store %arg, %1 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_ints_offset
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_ints_offset(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST32:.*]] = llvm.mlir.constant(32 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i64, i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i64, i32, i32)> : (i32) -> !llvm.ptr
%3 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32)>
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32)>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32)>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
llvm.store %arg, %3 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_floats
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_floats(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST32:.*]] = llvm.mlir.constant(32 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (f32, f32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (f32, f32)> : (i32) -> !llvm.ptr
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (f32, f32)>
// CHECK: %[[BIT_CAST:.*]] = llvm.bitcast %[[TRUNC]] : i32 to f32
// CHECK: llvm.store %[[BIT_CAST]], %[[GEP]]
llvm.store %arg, %1 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// Padding test purposefully not modified.
// CHECK-LABEL: llvm.func @coalesced_store_padding_inbetween
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_padding_inbetween(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, i32)> : (i32) -> !llvm.ptr
// CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.store %arg, %1 : i64, !llvm.ptr
llvm.return
}
// -----
// Padding test purposefully not modified.
// CHECK-LABEL: llvm.func @coalesced_store_padding_end
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_padding_end(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i16)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i16)> : (i32) -> !llvm.ptr
// CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.store %arg, %1 : i64, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_past_end
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_past_end(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32)> : (i32) -> !llvm.ptr
// CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.store %arg, %1 : i64, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_packed_struct
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_packed_struct(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST16:.*]] = llvm.mlir.constant(16 : i64) : i64
// CHECK-DAG: %[[CST48:.*]] = llvm.mlir.constant(48 : i64) : i64
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", packed (i16, i32, i16)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", packed (i16, i32, i16)> : (i32) -> !llvm.ptr
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
// CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST16]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i16, i32, i16)>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST48]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", packed (i16, i32, i16)>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
llvm.store %arg, %1 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @vector_write_split
// CHECK-SAME: %[[ARG:.*]]: vector<4xi32>
llvm.func @vector_write_split(%arg: vector<4xi32>) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i32) : i32
// CHECK-DAG: %[[CST1:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK-DAG: %[[CST2:.*]] = llvm.mlir.constant(2 : i32) : i32
// CHECK-DAG: %[[CST3:.*]] = llvm.mlir.constant(3 : i32) : i32
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32, i32)> : (i32) -> !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST0]] : i32] : vector<4xi32>
// CHECK: llvm.store %[[EXTRACT]], %[[ALLOCA]] : i32, !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST1]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST2]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST3]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
llvm.store %arg, %1 : vector<4xi32>, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @vector_write_split_offset
// CHECK-SAME: %[[ARG:.*]]: vector<4xi32>
llvm.func @vector_write_split_offset(%arg: vector<4xi32>) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i32) : i32
// CHECK-DAG: %[[CST1:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK-DAG: %[[CST2:.*]] = llvm.mlir.constant(2 : i32) : i32
// CHECK-DAG: %[[CST3:.*]] = llvm.mlir.constant(3 : i32) : i32
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i64, i32, i32, i32, i32)> : (i32) -> !llvm.ptr
%2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST0]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST1]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST2]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 3] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST3]] : i32] : vector<4xi32>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, i32, i32, i32, i32)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP]] : i32, !llvm.ptr
llvm.store %arg, %2 : vector<4xi32>, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// Small test that a split vector store will be further optimized (to than e.g.
// split integer loads to structs as shown here)
// CHECK-LABEL: llvm.func @vector_write_split_struct
// CHECK-SAME: %[[ARG:.*]]: vector<2xi64>
llvm.func @vector_write_split_struct(%arg: vector<2xi64>) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32, i32)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32, i32)> : (i32) -> !llvm.ptr
// CHECK-COUNT-4: llvm.store %{{.*}}, %{{.*}} : i32, !llvm.ptr
llvm.store %arg, %1 : vector<2xi64>, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @bitcast_insertion
// CHECK-SAME: %[[ARG:.*]]: i32
llvm.func @bitcast_insertion(%arg: i32) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x f32
%1 = llvm.alloca %0 x f32 : (i32) -> !llvm.ptr
// CHECK: %[[BIT_CAST:.*]] = llvm.bitcast %[[ARG]] : i32 to f32
// CHECK: llvm.store %[[BIT_CAST]], %[[ALLOCA]]
llvm.store %arg, %1 : i32, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @gep_split
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @gep_split(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.array<2 x struct<"foo", (i64)>>
%1 = llvm.alloca %0 x !llvm.array<2 x struct<"foo", (i64)>> : (i32) -> !llvm.ptr
%3 = llvm.getelementptr %1[0, 1, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
// CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64)>
// CHECK: llvm.store %[[ARG]], %[[GEP]]
llvm.store %arg, %3 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_ints_subaggregate
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_ints_subaggregate(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST32:.*]] = llvm.mlir.constant(32 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i64, struct<(i32, i32)>)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i64, struct<(i32, i32)>)> : (i32) -> !llvm.ptr
%3 = llvm.getelementptr %1[0, 1, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, struct<(i32, i32)>)>
// CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64, struct<(i32, i32)>)>
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: llvm.store %[[TRUNC]], %[[TOP_GEP]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, i32)>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
llvm.store %arg, %3 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @gep_result_ptr_type_dynamic
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @gep_result_ptr_type_dynamic(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.array<2 x struct<"foo", (i64)>>
%1 = llvm.alloca %0 x !llvm.array<2 x struct<"foo", (i64)>> : (i32) -> !llvm.ptr
%3 = llvm.getelementptr %1[0, %arg, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
// CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, %[[ARG]]] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.array<2 x struct<"foo", (i64)>>
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i64)>
// CHECK: llvm.store %[[ARG]], %[[GEP]]
llvm.store %arg, %3 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @overlapping_int_aggregate_store
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @overlapping_int_aggregate_store(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST16:.*]] = llvm.mlir.constant(16 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)> : (i32) -> !llvm.ptr
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
// CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST16]] : i64
// CHECK: [[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i48
// CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
// Normal integer splitting of [[TRUNC]] follows:
// CHECK: llvm.store %{{.*}}, %[[TOP_GEP]]
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
// CHECK: llvm.store %{{.*}}, %[[GEP]]
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
// CHECK: llvm.store %{{.*}}, %[[GEP]]
llvm.store %arg, %1 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @overlapping_vector_aggregate_store
// CHECK-SAME: %[[ARG:.*]]: vector<4xi16>
llvm.func @overlapping_vector_aggregate_store(%arg: vector<4 x i16>) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i32) : i32
// CHECK-DAG: %[[CST1:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK-DAG: %[[CST2:.*]] = llvm.mlir.constant(2 : i32) : i32
// CHECK-DAG: %[[CST3:.*]] = llvm.mlir.constant(3 : i32) : i32
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)> : (i32) -> !llvm.ptr
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST0]] : i32]
// CHECK: llvm.store %[[EXTRACT]], %[[ALLOCA]]
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST1]] : i32]
// CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP0]]
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST2]] : i32]
// CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
// CHECK: %[[GEP1:.*]] = llvm.getelementptr %[[GEP0]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP1]]
// CHECK: %[[EXTRACT:.*]] = llvm.extractelement %[[ARG]][%[[CST3]] : i32]
// CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16)>)>
// CHECK: %[[GEP1:.*]] = llvm.getelementptr %[[GEP0]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16)>
// CHECK: llvm.store %[[EXTRACT]], %[[GEP1]]
llvm.store %arg, %1 : vector<4 x i16>, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @partially_overlapping_aggregate_store
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @partially_overlapping_aggregate_store(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST16:.*]] = llvm.mlir.constant(16 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, struct<(i16, i16, i16, i16)>)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, struct<(i16, i16, i16, i16)>)> : (i32) -> !llvm.ptr
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i16
// CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST16]] : i64
// CHECK: [[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i48
// CHECK: %[[TOP_GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i16, struct<(i16, i16, i16, i16)>)>
// Normal integer splitting of [[TRUNC]] follows:
// CHECK: llvm.store %{{.*}}, %[[TOP_GEP]]
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16, i16)>
// CHECK: llvm.store %{{.*}}, %[[GEP]]
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[TOP_GEP]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i16, i16, i16, i16)>
// CHECK: llvm.store %{{.*}}, %[[GEP]]
// It is important that there are no more stores at this point.
// Specifically a store into the fourth field of %[[TOP_GEP]] would
// incorrectly change the semantics of the code.
// CHECK-NOT: llvm.store %{{.*}}, %{{.*}}
llvm.store %arg, %1 : i64, !llvm.ptr
llvm.return
}
// -----
// Here a split is undesirable since the store does a partial store into the field.
// CHECK-LABEL: llvm.func @undesirable_overlapping_aggregate_store
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @undesirable_overlapping_aggregate_store(%arg: i64) {
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)>
%1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)> : (i32) -> !llvm.ptr
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)>
%2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, i32, struct<(i64, i16, i16, i16)>)>
// CHECK: llvm.store %[[ARG]], %[[GEP]]
llvm.store %arg, %2 : i64, !llvm.ptr
llvm.return
}
// -----
// CHECK-LABEL: llvm.func @coalesced_store_ints_array
// CHECK-SAME: %[[ARG:.*]]: i64
llvm.func @coalesced_store_ints_array(%arg: i64) {
// CHECK-DAG: %[[CST0:.*]] = llvm.mlir.constant(0 : i64) : i64
// CHECK-DAG: %[[CST32:.*]] = llvm.mlir.constant(32 : i64) : i64
%0 = llvm.mlir.constant(1 : i32) : i32
// CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.array<2 x i32>
%1 = llvm.alloca %0 x !llvm.array<2 x i32> : (i32) -> !llvm.ptr
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST0]]
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: llvm.store %[[TRUNC]], %[[ALLOCA]]
// CHECK: %[[SHR:.*]] = llvm.lshr %[[ARG]], %[[CST32]] : i64
// CHECK: %[[TRUNC:.*]] = llvm.trunc %[[SHR]] : i64 to i32
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<2 x i32>
// CHECK: llvm.store %[[TRUNC]], %[[GEP]]
llvm.store %arg, %1 : i64, !llvm.ptr
// CHECK-NOT: llvm.store %[[ARG]], %[[ALLOCA]]
llvm.return
}