brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · 7dc579a Raw
240 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 42; RUN: opt < %s -passes=memcpyopt -S -verify-memoryssa | FileCheck %s3 4%buf = type [9 x i8]5 6; We can forward `memcpy` because the copy location are the same,7define void @forward_offset(ptr %src, ptr %dest) {8; CHECK-LABEL: define void @forward_offset(9; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {10; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 111; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)12; CHECK-NEXT:    [[SRC_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 113; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 114; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 6, i1 false)15; CHECK-NEXT:    ret void16;17  %cpy_tmp = alloca %buf, align 118  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)19  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 120  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)21  ret void22}23 24; We need to update the align value of the source of `memcpy` when forwarding.25define void @forward_offset_align(ptr %src, ptr %dest) {26; CHECK-LABEL: define void @forward_offset_align(27; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {28; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 129; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 4 [[SRC]], i64 9, i1 false)30; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 331; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 332; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 5, i1 false)33; CHECK-NEXT:    ret void34;35  %cpy_tmp = alloca %buf, align 136  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 4 %src, i64 9, i1 false)37  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 338  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 5, i1 false)39  ret void40}41 42; We can change the align value to 2 when forwarding.43define void @forward_offset_align_2(ptr %src, ptr %dest) {44; CHECK-LABEL: define void @forward_offset_align_2(45; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {46; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 147; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 4 [[SRC]], i64 9, i1 false)48; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 249; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 250; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 2 [[TMP1]], i64 6, i1 false)51; CHECK-NEXT:    ret void52;53  %cpy_tmp = alloca %buf, align 154  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 4 %src, i64 9, i1 false)55  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 256  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)57  ret void58}59 60; If the copy destination can be used as the copy source, we don't need to create a GEP instruction.61define void @forward_offset_without_gep(ptr %src) {62; CHECK-LABEL: define void @forward_offset_without_gep(63; CHECK-SAME: ptr [[SRC:%.*]]) {64; CHECK-NEXT:    [[TMP:%.*]] = alloca [9 x i8], align 165; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[TMP]], ptr align 1 [[SRC]], i64 7, i1 false)66; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 167; CHECK-NEXT:    [[DEST:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 168; CHECK-NEXT:    ret void69;70  %cpy_tmp = alloca %buf, align 171  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)72  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 173  %dest = getelementptr inbounds i8, ptr %src, i64 174  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)75  ret void76}77 78; We need to create a GEP instruction when forwarding.79define void @forward_offset_with_gep(ptr %src) {80; CHECK-LABEL: define void @forward_offset_with_gep(81; CHECK-SAME: ptr [[SRC:%.*]]) {82; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 183; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)84; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 185; CHECK-NEXT:    [[DEST:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 286; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 187; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 6, i1 false)88; CHECK-NEXT:    ret void89;90  %cpy_tmp = alloca %buf, align 191  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)92  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 193  %dest = getelementptr inbounds i8, ptr %src, i64 294  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)95  ret void96}97 98; Make sure we pass the right parameters when calling `memcpy`.99define void @forward_offset_memcpy(ptr %src, ptr %dest) {100; CHECK-LABEL: define void @forward_offset_memcpy(101; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {102; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 1103; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)104; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1105; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 1106; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 6, i1 false)107; CHECK-NEXT:    call void @use(ptr [[DEST]])108; CHECK-NEXT:    ret void109;110  %cpy_tmp = alloca %buf, align 1111  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)112  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 1113  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)114  call void @use(ptr %dest)115  ret void116}117 118; Make sure we pass the right parameters when calling `memcpy.inline`.119define void @forward_offset_memcpy_inline(ptr %src, ptr %dest) {120; CHECK-LABEL: define void @forward_offset_memcpy_inline(121; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {122; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 1123; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)124; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1125; CHECK-NEXT:    call void @llvm.memcpy.inline.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 6, i1 false)126; CHECK-NEXT:    call void @use(ptr [[DEST]])127; CHECK-NEXT:    ret void128;129  %cpy_tmp = alloca %buf, align 1130  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)131  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 1132  call void @llvm.memcpy.inline.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)133  call void @use(ptr %dest)134  ret void135}136 137; We can forward `memcpy` by shrinking it to the size of the `memcpy` it depends on.138define void @forward_oversize_offset(ptr %src, ptr %dest) {139; CHECK-LABEL: define void @forward_oversize_offset(140; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {141; CHECK-NEXT:    [[CPY_TMP:%.*]] = alloca [9 x i8], align 1142; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[CPY_TMP]], ptr align 1 [[SRC]], i64 6, i1 false)143; CHECK-NEXT:    [[CPY_TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[CPY_TMP]], i64 1144; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 1145; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 5, i1 false)146; CHECK-NEXT:    ret void147;148  %cpy_tmp = alloca %buf, align 1149  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 6, i1 false)150  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 1151  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)152  ret void153}154 155; We can forward `memcpy` because the write operation does not corrupt the location to be copied.156define void @forward_offset_and_store(ptr %src, ptr %dest) {157; CHECK-LABEL: define void @forward_offset_and_store(158; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {159; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 1160; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)161; CHECK-NEXT:    store i8 1, ptr [[SRC]], align 1162; CHECK-NEXT:    [[DEP_SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 6163; CHECK-NEXT:    store i8 1, ptr [[DEP_SRC_END]], align 1164; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1165; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 1166; CHECK-NEXT:    call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 5, i1 false)167; CHECK-NEXT:    ret void168;169  %cpy_tmp = alloca %buf, align 1170  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)171  store i8 1, ptr %src, align 1172  %src_end = getelementptr inbounds i8, ptr %src, i64 6173  store i8 1, ptr %src_end, align 1174  %cpy_tmp_offset  = getelementptr inbounds i8, ptr %cpy_tmp, i64 1175  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 5, i1 false)176  ret void177}178 179; We cannot forward `memcpy` because the write operation alters the location to be copied.180; Also, make sure we have removed the GEP instruction that was created temporarily.181define void @do_not_forward_offset_and_store(ptr %src, ptr %dest) {182; CHECK-LABEL: define void @do_not_forward_offset_and_store(183; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {184; CHECK-NEXT:    [[DEP_DEST:%.*]] = alloca [9 x i8], align 1185; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)186; CHECK-NEXT:    [[DEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 1187; CHECK-NEXT:    store i8 1, ptr [[DEP]], align 1188; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1189; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP_OFFSET]], i64 5, i1 false)190; CHECK-NEXT:    ret void191;192  %cpy_tmp = alloca %buf, align 1193  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)194  %src_offset = getelementptr inbounds i8, ptr %src, i64 1195  store i8 1, ptr %src_offset, align 1196  %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 1197  call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 5, i1 false)198  ret void199}200 201; Make sure we don't crash when the copy source is a constant.202@buf = external global [32 x i8]203 204define void @pr98675(ptr noalias %p1, ptr noalias %p2) {205; CHECK-LABEL: define void @pr98675(206; CHECK-SAME: ptr noalias [[P1:%.*]], ptr noalias [[P2:%.*]]) {207; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[P1]], ptr @buf, i64 26, i1 false)208; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P1]], i64 10209; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[P2]], ptr getelementptr inbounds (i8, ptr @buf, i64 10), i64 1, i1 false)210; CHECK-NEXT:    ret void211;212  call void @llvm.memcpy.p0.p0.i64(ptr %p1, ptr @buf, i64 26, i1 false)213  %gep = getelementptr i8, ptr %p1, i64 10214  call void @llvm.memmove.p0.p0.i64(ptr %p2, ptr %gep, i64 1, i1 false)215  ret void216}217 218define void @over_offset_cpy(ptr %src) {219; CHECK-LABEL: define void @over_offset_cpy(220; CHECK-SAME: ptr [[SRC:%.*]]) {221; CHECK-NEXT:    [[TMP:%.*]] = alloca [2 x i8], align 1222; CHECK-NEXT:    [[DST:%.*]] = alloca i8, align 1223; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP]], ptr align 8 [[SRC]], i64 1, i1 false)224; CHECK-NEXT:    [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 1225; CHECK-NEXT:    ret void226;227  %tmp = alloca [2 x i8]228  %dst = alloca i8229  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %tmp, ptr align 8 %src, i64 1, i1 false)230  %tmp_offset = getelementptr inbounds i8, ptr %tmp, i64 1231  call void @llvm.memcpy.p0.p0.i64(ptr align 8 %dst, ptr align 8 %tmp_offset, i64 1, i1 false)232 233  ret void234}235 236declare void @use(ptr)237 238declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)239declare void @llvm.memcpy.inline.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)240