Skip to content

[LICM] LICM breaks initializes attribute #133038

@dtcxzyw

Description

@dtcxzyw

Reproducer: https://godbolt.org/z/evTP9P17j

; bin/opt -passes=licm reduced.ll -S
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-unknown-linux-gnu"

define void @_ZN25test7425_51072c957f3e023d3fn317hab8ab70cb1ea6b04E(ptr noalias writable align 2 dereferenceable(12) initializes((0, 12)) %0) {
  %2 = alloca [56 x i8], align 8
  %3 = getelementptr i8, ptr %0, i64 8
  %4 = getelementptr i8, ptr %0, i64 10
  br label %5

5:                                                ; preds = %10, %1
  %6 = getelementptr i8, ptr %2, i64 16
  %7 = getelementptr i8, ptr %2, i64 16
  store i16 0, ptr %3, align 2
  store i16 0, ptr %4, align 2
  %8 = load <4 x i32>, ptr %6, align 8
  store <4 x i32> %8, ptr %7, align 8
  br label %9

9:                                                ; preds = %5
  switch i8 1, label %11 [
    i8 1, label %11
    i8 0, label %10
  ]

10:                                               ; preds = %9
  store <4 x i16> zeroinitializer, ptr %0, align 2
  br label %5

11:                                               ; preds = %9, %9
  ret void
}

define void @_ZN25test7425_51072c957f3e023d4main17hb2c14928af806df2E() {
  %1 = alloca [64 x i8], align 8
  call void @_ZN25test7425_51072c957f3e023d3fn317hab8ab70cb1ea6b04E(ptr %1)
  ret void
}

After LICM, the first memory access to %0 is load <4 x i16>, ptr %0, align 1, which breaks the initializes attribute:

Initialization of memory means the first memory access is a non-volatile, non-atomic write.
The initializes attribute does not imply writeonly since initializes allows reading from the pointer after writing.

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-unknown-linux-gnu"

define void @_ZN25test7425_51072c957f3e023d3fn317hab8ab70cb1ea6b04E(ptr noalias writable align 2 dereferenceable(12) initializes((0, 12)) %0) {
  %2 = alloca [56 x i8], align 8
  %3 = getelementptr i8, ptr %0, i64 8
  %4 = getelementptr i8, ptr %0, i64 10
  %5 = getelementptr i8, ptr %2, i64 16
  %6 = getelementptr i8, ptr %2, i64 16
  %.promoted = load <4 x i32>, ptr %5, align 8
  %.promoted1 = load <4 x i16>, ptr %0, align 1
  br label %7

7:                                                ; preds = %11, %1
  %8 = phi <4 x i16> [ zeroinitializer, %11 ], [ %.promoted1, %1 ]
  %9 = phi <4 x i32> [ %9, %11 ], [ %.promoted, %1 ]
  br label %10

10:                                               ; preds = %7
  switch i8 1, label %12 [
    i8 1, label %12
    i8 0, label %11
  ]

11:                                               ; preds = %10
  br label %7

12:                                               ; preds = %10, %10
  %.lcssa2 = phi <4 x i16> [ %8, %10 ], [ %8, %10 ]
  %.lcssa = phi <4 x i32> [ %9, %10 ], [ %9, %10 ]
  store i16 0, ptr %3, align 2
  store i16 0, ptr %4, align 2
  store <4 x i32> %.lcssa, ptr %5, align 8
  store <4 x i16> %.lcssa2, ptr %0, align 1
  ret void
}

Should we clarify the LangRef wording on initializes to allow loads before the initialization is complete, if they are not externally observable?

This case is generated by rustlantis + llubi.
Original rust mir program: https://gist.github.com/dtcxzyw/fcf0905a562f8734428e0b216198e0c0

cc @haopliu @nikic

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions