Index: llvm/test/Transforms/MemCpyOpt/memcpy.ll =================================================================== --- llvm/test/Transforms/MemCpyOpt/memcpy.ll +++ llvm/test/Transforms/MemCpyOpt/memcpy.ll @@ -391,3 +391,40 @@ declare void @f1(ptr nocapture sret(%struct.big)) declare void @f2(ptr) + +; TODO: remove memcpy, which is guaranteed to be invariant +; before and after the call because of its attributes. +declare void @fnr(ptr noalias readonly) +define noundef i32 @noalias_readonly_i8(ptr align 4 noalias readonly %val) { +; CHECK-LABEL: @noalias_readonly_i8( +; CHECK-NEXT: start: +; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false) +; CHECK-NEXT: [[TMP0:%.*]] = call noundef i32 @fnr(ptr noalias readonly align 4 [[VAL1]]) +; CHECK-NEXT: ret i32 [[TMP0]] +; +start: + %val1 = alloca i8, align 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %val1, ptr align 4 %val, i64 1, i1 false) + %0 = call noundef i32 @fnr(ptr align 4 noalias readonly %val1) + ret i32 %0 +} + + +%st = type { { ptr, i64 } } +; TODO: remove memcpy, which is guaranteed to be invariant +; before and after the call because of its attributes. +define noundef i32 @noalias_readonly_struct(ptr align 4 noalias readonly %val) { +; CHECK-LABEL: @noalias_readonly_struct( +; CHECK-NEXT: start: +; CHECK-NEXT: [[VAL1:%.*]] = alloca [[ST:%.*]], align 4 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL1]], ptr align 4 [[VAL:%.*]], i64 1, i1 false) +; CHECK-NEXT: [[TMP0:%.*]] = call noundef i32 @fnr(ptr noalias readonly align 4 [[VAL1]]) +; CHECK-NEXT: ret i32 [[TMP0]] +; +start: + %val1 = alloca %st, align 4 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %val1, ptr align 4 %val, i64 1, i1 false) + %0 = call noundef i32 @fnr(ptr align 4 noalias readonly %val1) + ret i32 %0 +}