Skip to content

[MLIR] mlir-translate emits global struct init on address of #117389

@Jezurko

Description

@Jezurko

I have tested this on llvm 18 and 19.
For each function where addressof is generated for a global variable of struct type, mlir-translate also generates the body of the init region of the struct.

Take this program:

struct MyStruct {
	char f0[20];
	int f1;
	int* f2;
};

int x, y;
struct MyStruct global = {"abcdefg", 20, &x};

int foo(struct MyStruct *S) {
    return &global == S;
}

int main() {
    int x = foo(&global);
    struct MyStruct *P = &global;
    return 0;
}

emitting LLVM IR with clang produces following code:

; ModuleID = 'experiment.c'
source_filename = "experiment.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-solus-linux"

%struct.MyStruct = type { [20 x i8], i32, ptr }

@x = dso_local global i32 0, align 4
@global = dso_local global %struct.MyStruct { [20 x i8] c"abcdefg\00\00\00\00\00\00\00\00\00\00\00\00\00", i32 20, ptr @x }, align 8
@y = dso_local global i32 0, align 4

; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local i32 @foo(ptr noundef %0) #0 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  %3 = load ptr, ptr %2, align 8
  %4 = icmp eq ptr @global, %3
  %5 = zext i1 %4 to i32
  ret i32 %5
}

; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca ptr, align 8
  store i32 0, ptr %1, align 4
  %4 = call i32 @foo(ptr noundef @global)
  store i32 %4, ptr %2, align 4
  store ptr @global, ptr %3, align 8
  ret i32 0
}

attributes #0 = { noinline nounwind optnone sspstrong uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"clang version 18.1.8"}

Which is okay.
Loading this into mlir using mlir-translate -import-llvm produces following code:

module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>} {
  llvm.mlir.global external @x(0 : i32) {addr_space = 0 : i32, alignment = 4 : i64, dso_local} : i32
  llvm.mlir.global external @global() {addr_space = 0 : i32, alignment = 8 : i64, dso_local} : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> {
    %0 = llvm.mlir.constant(0 : i32) : i32
    %1 = llvm.mlir.addressof @x : !llvm.ptr
    %2 = llvm.mlir.constant(20 : i32) : i32
    %3 = llvm.mlir.constant("abcdefg\00\00\00\00\00\00\00\00\00\00\00\00\00") : !llvm.array<20 x i8>
    %4 = llvm.mlir.undef : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)>
    %5 = llvm.insertvalue %3, %4[0] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %6 = llvm.insertvalue %2, %5[1] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %7 = llvm.insertvalue %1, %6[2] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    llvm.return %7 : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)>
  }
  llvm.mlir.global external @y(0 : i32) {addr_space = 0 : i32, alignment = 4 : i64, dso_local} : i32
  llvm.func @foo(%arg0: !llvm.ptr {llvm.noundef}) -> i32 attributes {frame_pointer = #llvm.framePointerKind<all>, passthrough = ["noinline", "nounwind", "optnone", "sspstrong", ["uwtable", "2"], ["min-legal-vector-width", "0"], ["no-trapping-math", "true"], ["stack-protector-buffer-size", "8"], ["target-cpu", "x86-64"], ["tune-cpu", "generic"]], target_cpu = "x86-64", target_features = #llvm.target_features<["+cmov", "+cx8", "+fxsr", "+mmx", "+sse", "+sse2", "+x87"]>} {
    %0 = llvm.mlir.constant(1 : i32) : i32
    %1 = llvm.mlir.constant(0 : i32) : i32
    %2 = llvm.mlir.addressof @x : !llvm.ptr
    %3 = llvm.mlir.constant(20 : i32) : i32
    %4 = llvm.mlir.constant("abcdefg\00\00\00\00\00\00\00\00\00\00\00\00\00") : !llvm.array<20 x i8>
    %5 = llvm.mlir.undef : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)>
    %6 = llvm.insertvalue %4, %5[0] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %7 = llvm.insertvalue %3, %6[1] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %8 = llvm.insertvalue %2, %7[2] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %9 = llvm.mlir.addressof @global : !llvm.ptr
    %10 = llvm.alloca %0 x !llvm.ptr {alignment = 8 : i64} : (i32) -> !llvm.ptr
    llvm.store %arg0, %10 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
    %11 = llvm.load %10 {alignment = 8 : i64} : !llvm.ptr -> !llvm.ptr
    %12 = llvm.icmp "eq" %9, %11 : !llvm.ptr
    %13 = llvm.zext %12 : i1 to i32
    llvm.return %13 : i32
  }
  llvm.func @main() -> i32 attributes {frame_pointer = #llvm.framePointerKind<all>, passthrough = ["noinline", "nounwind", "optnone", "sspstrong", ["uwtable", "2"], ["min-legal-vector-width", "0"], ["no-trapping-math", "true"], ["stack-protector-buffer-size", "8"], ["target-cpu", "x86-64"], ["tune-cpu", "generic"]], target_cpu = "x86-64", target_features = #llvm.target_features<["+cmov", "+cx8", "+fxsr", "+mmx", "+sse", "+sse2", "+x87"]>} {
    %0 = llvm.mlir.constant(1 : i32) : i32
    %1 = llvm.mlir.constant(0 : i32) : i32
    %2 = llvm.mlir.addressof @x : !llvm.ptr
    %3 = llvm.mlir.constant(20 : i32) : i32
    %4 = llvm.mlir.constant("abcdefg\00\00\00\00\00\00\00\00\00\00\00\00\00") : !llvm.array<20 x i8>
    %5 = llvm.mlir.undef : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)>
    %6 = llvm.insertvalue %4, %5[0] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %7 = llvm.insertvalue %3, %6[1] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %8 = llvm.insertvalue %2, %7[2] : !llvm.struct<"struct.MyStruct", (array<20 x i8>, i32, ptr)> 
    %9 = llvm.mlir.addressof @global : !llvm.ptr
    %10 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
    %11 = llvm.alloca %0 x i32 {alignment = 4 : i64} : (i32) -> !llvm.ptr
    %12 = llvm.alloca %0 x !llvm.ptr {alignment = 8 : i64} : (i32) -> !llvm.ptr
    llvm.store %1, %10 {alignment = 4 : i64} : i32, !llvm.ptr
    %13 = llvm.call @foo(%9) : (!llvm.ptr) -> i32
    llvm.store %13, %11 {alignment = 4 : i64} : i32, !llvm.ptr
    llvm.store %9, %12 {alignment = 8 : i64} : !llvm.ptr, !llvm.ptr
    llvm.return %1 : i32
  }
}

Both foo and main have the contents of the init region, even though it serves no purpose there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions