llvm/mlir/test/Target/LLVMIR/attribute-tbaa.mlir

// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s

#tbaa_root_0 = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
#tbaa_type_desc_1 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
#tbaa_type_desc_2 = #llvm.tbaa_type_desc<id = "long long", members = {<#tbaa_type_desc_1, 0>}>
#tbaa_type_desc_3 = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 8>}>
#tbaa_tag_4 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_3, offset = 8>
#tbaa_type_desc_5 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_1, 0>}>
#tbaa_type_desc_6 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_5, 0>, <#tbaa_type_desc_5, 4>}>
#tbaa_tag_7 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_6, offset = 0, constant = true>

llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.getelementptr inbounds %arg1[%0, 1] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg2_t", (i64, i64)>
  // CHECK: load i64, ptr %{{.*}},{{.*}}!tbaa ![[LTAG:[0-9]*]]
  %3 = llvm.load %2 {tbaa = [#tbaa_tag_4]} : !llvm.ptr -> i64
  %4 = llvm.trunc %3 : i64 to i32
  %5 = llvm.getelementptr inbounds %arg0[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
  // CHECK: store i32 %{{.*}}, ptr %{{.*}},{{.*}}!tbaa ![[STAG:[0-9]*]]
  llvm.store %4, %5 {tbaa = [#tbaa_tag_7]} : i32, !llvm.ptr
  llvm.return
}

// CHECK-DAG: ![[LTAG]] = !{![[AGG2T:[0-9]*]], ![[I64T:[0-9]*]], i64 8}
// CHECK-DAG: ![[AGG2T]] = !{!"agg2_t", ![[I64T]], i64 0, ![[I64T]], i64 8}
// CHECK-DAG: ![[I64T]] = !{!"long long", ![[CHART:[0-9]*]], i64 0}
// CHECK-DAG: ![[CHART]] = !{!"omnipotent char", ![[ROOT:[0-9]*]], i64 0}
// CHECK-DAG: ![[ROOT]] = !{!"Simple C/C++ TBAA"}
// CHECK-DAG: ![[STAG]] = !{![[AGG1T:[0-9]*]], ![[I32T:[0-9]*]], i64 0, i64 1}
// CHECK-DAG: ![[AGG1T]] = !{!"agg1_t", ![[I32T]], i64 0, ![[I32T]], i64 4}
// CHECK-DAG: ![[I32T]] = !{!"int", ![[CHART]], i64 0}

// -----

// Verify that the MDNode's created for the access tags are not uniqued
// before they are finalized. In the process of creating the MDNodes for
// the tag operations we used to produce incomplete MDNodes like:
//   #tbaa_tag_4 => !{!null, !null, i64 0}
//   #tbaa_tag_7 => !{!null, !null, i64 0}
// This caused the two tags to map to the same incomplete MDNode due to
// uniquing. To prevent this, we have to use temporary MDNodes
// instead of !null's.

#tbaa_root_0 = #llvm.tbaa_root<id = "Simple C/C++ TBAA">
#tbaa_type_desc_1 = #llvm.tbaa_type_desc<id = "omnipotent char", members = {<#tbaa_root_0, 0>}>
#tbaa_type_desc_2 = #llvm.tbaa_type_desc<id = "float", members = {<#tbaa_type_desc_1, 0>}>
#tbaa_type_desc_3 = #llvm.tbaa_type_desc<id = "agg2_t", members = {<#tbaa_type_desc_2, 0>, <#tbaa_type_desc_2, 4>}>
#tbaa_tag_4 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_2, base_type = #tbaa_type_desc_3, offset = 0>
#tbaa_type_desc_5 = #llvm.tbaa_type_desc<id = "int", members = {<#tbaa_type_desc_1, 0>}>
#tbaa_type_desc_6 = #llvm.tbaa_type_desc<id = "agg1_t", members = {<#tbaa_type_desc_5, 0>, <#tbaa_type_desc_5, 4>}>
#tbaa_tag_7 = #llvm.tbaa_tag<access_type = #tbaa_type_desc_5, base_type = #tbaa_type_desc_6, offset = 0>


llvm.func @foo(%arg0: !llvm.ptr)
llvm.func @tbaa2(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
  %0 = llvm.mlir.constant(0 : i32) : i32
  %1 = llvm.mlir.constant(1 : i32) : i32
  %2 = llvm.getelementptr inbounds %arg1[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg2_t", (f32, f32)>
  // CHECK: load float, ptr %{{.*}},{{.*}}!tbaa ![[LTAG:[0-9]*]]
  %3 = llvm.load %2 {tbaa = [#tbaa_tag_4]} : !llvm.ptr -> f32
  %4 = llvm.fptosi %3 : f32 to i32
  %5 = llvm.getelementptr inbounds %arg0[%0, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.agg1_t", (i32, i32)>
  // CHECK: store i32 %{{.*}}, ptr %{{.*}},{{.*}}!tbaa ![[STAG:[0-9]*]]
  llvm.store %4, %5 {tbaa = [#tbaa_tag_7]} : i32, !llvm.ptr
  // CHECK: atomicrmw add ptr %{{.*}}, i32 %{{.*}} !tbaa ![[STAG]]
  %6 = llvm.atomicrmw add %5, %4 monotonic {tbaa = [#tbaa_tag_7]} : !llvm.ptr, i32
  // CHECK: cmpxchg ptr %{{.*}}, i32 %{{.*}}, i32 %{{.*}} !tbaa ![[STAG]]
  %7 = llvm.cmpxchg %5, %6, %4 acq_rel monotonic {tbaa = [#tbaa_tag_7]} : !llvm.ptr, i32
  %9 = llvm.mlir.constant(42 : i8) : i8
  // CHECK: llvm.memcpy{{.*}} !tbaa ![[STAG]]
  "llvm.intr.memcpy"(%arg1, %arg1, %0) <{isVolatile = false}> {tbaa = [#tbaa_tag_7]} : (!llvm.ptr, !llvm.ptr, i32) -> ()
  // CHECK: llvm.memset{{.*}} !tbaa ![[STAG]]
  "llvm.intr.memset"(%arg1, %9, %0) <{isVolatile = false}> {tbaa = [#tbaa_tag_7]} : (!llvm.ptr, i8, i32) -> ()
  // CHECK: call void @foo({{.*}} !tbaa ![[STAG]]
  llvm.call @foo(%arg1) {tbaa = [#tbaa_tag_7]} : (!llvm.ptr) -> ()
  llvm.return
}


// CHECK-DAG: ![[LTAG]] = !{![[AGG2T:[0-9]*]], ![[F32T:[0-9]*]], i64 0}
// CHECK-DAG: ![[AGG2T]] = !{!"agg2_t", ![[F32T]], i64 0, ![[F32T]], i64 4}
// CHECK-DAG: ![[I64T]] = !{!"float", ![[CHART:[0-9]*]], i64 0}
// CHECK-DAG: ![[CHART]] = !{!"omnipotent char", ![[ROOT:[0-9]*]], i64 0}
// CHECK-DAG: ![[ROOT]] = !{!"Simple C/C++ TBAA"}
// CHECK-DAG: ![[STAG]] = !{![[AGG1T:[0-9]*]], ![[I32T:[0-9]*]], i64 0}
// CHECK-DAG: ![[AGG1T]] = !{!"agg1_t", ![[I32T]], i64 0, ![[I32T]], i64 4}
// CHECK-DAG: ![[I32T]] = !{!"int", ![[CHART]], i64 0}