Index: llvm/test/Transforms/MemCpyOpt/memcpy.ll =================================================================== --- llvm/test/Transforms/MemCpyOpt/memcpy.ll +++ llvm/test/Transforms/MemCpyOpt/memcpy.ll @@ -391,3 +391,143 @@ declare void @f1(ptr nocapture sret(%struct.big)) declare void @f2(ptr) + +declare void @f(ptr) +declare void @f_full_readonly(ptr nocapture noalias readonly) +declare void @f_full_readnone(ptr nocapture noalias readnone) +declare void @f_full_memory_none(ptr nocapture noalias) memory(none) + +; TODO: remove memcpy, which is guaranteed to be invariant +; before and after the call because of its attributes. +define void @immut_param1(ptr align 4 noalias %val) { +; CHECK-LABEL: @immut_param1( +; 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: call void @f(ptr noalias nocapture readonly align 4 [[VAL1]]) +; CHECK-NEXT: ret void +; +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) + call void @f(ptr align 4 nocapture noalias readonly %val1) + ret void +} + +; TODO: remove memcpy +define void @immut_param2_readonly(ptr align 4 noalias %val) { +; CHECK-LABEL: @immut_param2_readonly( +; 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: call void @f_full_readonly(ptr align 4 [[VAL1]]) +; CHECK-NEXT: ret void +; +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) + call void @f_full_readonly(ptr align 4 %val1) + ret void +} + +; TODO: remove memcpy +define void @immut_param2_readnone(ptr align 4 noalias %val) { +; CHECK-LABEL: @immut_param2_readnone( +; CHECK-NEXT: start: +; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4 +; CHECK-NEXT: call void @f_full_readnone(ptr align 4 [[VAL1]]) +; CHECK-NEXT: ret void +; +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) + call void @f_full_readnone(ptr align 4 %val1) + ret void +} + +; TODO: remove memcpy +define void @immut_param3_memory_none(ptr align 4 noalias %val) { +; CHECK-LABEL: @immut_param3_memory_none( +; CHECK-NEXT: start: +; CHECK-NEXT: [[VAL1:%.*]] = alloca i8, align 4 +; CHECK-NEXT: call void @f_full_memory_none(ptr align 4 [[VAL1]]) +; CHECK-NEXT: ret void +; +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) + call void @f_full_memory_none(ptr align 4 %val1) + ret void +} + +; TODO: remove memcpy because neither alignment attribute, +; nor Datalayout S specifications is given. +define void @immut_param4_no_align(ptr align 4 noalias %val) { +; CHECK-LABEL: @immut_param4_no_align( +; 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: call void @f_full_readonly(ptr [[VAL1]]) +; CHECK-NEXT: ret void +; +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) + call void @f_full_readonly(ptr %val1) + ret void +} + +; can't remove memcpy, because if the %val directly passed to @f, +; alignment of ptr to f's argument will be different. +define void @immut_invalid_align(i1 %c, ptr noalias %val) { +; CHECK-LABEL: @immut_invalid_align( +; CHECK-NEXT: [[VAL1:%.*]] = alloca [4 x i8], align 4 +; CHECK-NEXT: [[VAL2:%.*]] = alloca [16 x i8], align 16 +; CHECK-NEXT: [[VAL3:%.*]] = select i1 [[C:%.*]], ptr [[VAL1]], ptr [[VAL2]] +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL3]], ptr align 4 [[VAL:%.*]], i64 4, i1 false) +; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL3]]) +; CHECK-NEXT: ret void +; + %val1 = alloca [4 x i8], align 4 + %val2 = alloca [16 x i8], align 16 + %val3 = select i1 %c, ptr %val1, ptr %val2 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %val3, ptr align 4 %val, i64 4, i1 false) + call void @f(ptr nocapture noalias readonly %val3) + ret void +} + +; TODO: remove memcpy, +define void @immut_valid_align(i1 %c, ptr noalias align 4 %val) { +; CHECK-LABEL: @immut_valid_align( +; CHECK-NEXT: [[VAL1:%.*]] = alloca [4 x i8], align 4 +; CHECK-NEXT: [[VAL2:%.*]] = alloca [16 x i8], align 4 +; CHECK-NEXT: [[VAL3:%.*]] = select i1 [[C:%.*]], ptr [[VAL1]], ptr [[VAL2]] +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL3]], ptr align 4 [[VAL:%.*]], i64 4, i1 false) +; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL3]]) +; CHECK-NEXT: ret void +; + %val1 = alloca [4 x i8], align 4 + %val2 = alloca [16 x i8], align 4 + %val3 = select i1 %c, ptr %val1, ptr %val2 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %val3, ptr align 4 %val, i64 4, i1 false) + call void @f(ptr nocapture noalias readonly %val3) + ret void +} + +; TODO: remove memcpy, copied size is less than or equal to the alloca size +define void @immut_valid_small_align(i1 %c, ptr noalias align 4 %val) { +; CHECK-LABEL: @immut_valid_small_align( +; CHECK-NEXT: [[VAL1:%.*]] = alloca [4 x i8], align 4 +; CHECK-NEXT: [[VAL2:%.*]] = alloca [16 x i8], align 4 +; CHECK-NEXT: [[VAL3:%.*]] = select i1 [[C:%.*]], ptr [[VAL1]], ptr [[VAL2]] +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[VAL3]], ptr align 4 [[VAL:%.*]], i64 1, i1 false) +; CHECK-NEXT: call void @f(ptr noalias nocapture readonly [[VAL3]]) +; CHECK-NEXT: ret void +; + %val1 = alloca [4 x i8], align 4 + %val2 = alloca [16 x i8], align 4 + %val3 = select i1 %c, ptr %val1, ptr %val2 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %val3, ptr align 4 %val, i64 1, i1 false) + call void @f(ptr nocapture noalias readonly %val3) + ret void +}