1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mcpu=mvp -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -tail-dup-placement=0 | FileCheck %s 3 4; Test memcpy, memmove, and memset intrinsics. 5 6target triple = "wasm32-unknown-unknown" 7 8declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1) 9declare void @llvm.memmove.p0.p0.i32(ptr nocapture, ptr nocapture readonly, i32, i1) 10declare void @llvm.memset.p0.i32(ptr nocapture, i8, i32, i1) 11 12; Test that return values are optimized. 13 14define ptr @copy_yes(ptr %dst, ptr %src, i32 %len) { 15; CHECK-LABEL: copy_yes: 16; CHECK: .functype copy_yes (i32, i32, i32) -> (i32) 17; CHECK-NEXT: # %bb.0: 18; CHECK-NEXT: call $push0=, memcpy, $0, $1, $2 19; CHECK-NEXT: return $pop0 20 call void @llvm.memcpy.p0.p0.i32(ptr %dst, ptr %src, i32 %len, i1 false) 21 ret ptr %dst 22} 23define void @copy_no(ptr %dst, ptr %src, i32 %len) { 24; CHECK-LABEL: copy_no: 25; CHECK: .functype copy_no (i32, i32, i32) -> () 26; CHECK-NEXT: # %bb.0: 27; CHECK-NEXT: call $drop=, memcpy, $0, $1, $2 28; CHECK-NEXT: return 29 call void @llvm.memcpy.p0.p0.i32(ptr %dst, ptr %src, i32 %len, i1 false) 30 ret void 31} 32 33define ptr @move_yes(ptr %dst, ptr %src, i32 %len) { 34; CHECK-LABEL: move_yes: 35; CHECK: .functype move_yes (i32, i32, i32) -> (i32) 36; CHECK-NEXT: # %bb.0: 37; CHECK-NEXT: call $push0=, memmove, $0, $1, $2 38; CHECK-NEXT: return $pop0 39 call void @llvm.memmove.p0.p0.i32(ptr %dst, ptr %src, i32 %len, i1 false) 40 ret ptr %dst 41} 42 43define void @move_no(ptr %dst, ptr %src, i32 %len) { 44; CHECK-LABEL: move_no: 45; CHECK: .functype move_no (i32, i32, i32) -> () 46; CHECK-NEXT: # %bb.0: 47; CHECK-NEXT: call $drop=, memmove, $0, $1, $2 48; CHECK-NEXT: return 49 call void @llvm.memmove.p0.p0.i32(ptr %dst, ptr %src, i32 %len, i1 false) 50 ret void 51} 52 53define ptr @set_yes(ptr %dst, i8 %src, i32 %len) { 54; CHECK-LABEL: set_yes: 55; CHECK: .functype set_yes (i32, i32, i32) -> (i32) 56; CHECK-NEXT: # %bb.0: 57; CHECK-NEXT: call $push0=, memset, $0, $1, $2 58; CHECK-NEXT: return $pop0 59 call void @llvm.memset.p0.i32(ptr %dst, i8 %src, i32 %len, i1 false) 60 ret ptr %dst 61} 62 63define void @set_no(ptr %dst, i8 %src, i32 %len) { 64; CHECK-LABEL: set_no: 65; CHECK: .functype set_no (i32, i32, i32) -> () 66; CHECK-NEXT: # %bb.0: 67; CHECK-NEXT: call $drop=, memset, $0, $1, $2 68; CHECK-NEXT: return 69 call void @llvm.memset.p0.i32(ptr %dst, i8 %src, i32 %len, i1 false) 70 ret void 71} 72 73define void @frame_index() { 74; CHECK-LABEL: frame_index: 75; CHECK: .functype frame_index () -> () 76; CHECK-NEXT: # %bb.0: # %entry 77; CHECK-NEXT: global.get $push3=, __stack_pointer 78; CHECK-NEXT: i32.const $push4=, 4096 79; CHECK-NEXT: i32.sub $push12=, $pop3, $pop4 80; CHECK-NEXT: local.tee $push11=, $0=, $pop12 81; CHECK-NEXT: global.set __stack_pointer, $pop11 82; CHECK-NEXT: i32.const $push7=, 2048 83; CHECK-NEXT: i32.add $push8=, $0, $pop7 84; CHECK-NEXT: i32.const $push1=, 0 85; CHECK-NEXT: i32.const $push0=, 1024 86; CHECK-NEXT: call $drop=, memset, $pop8, $pop1, $pop0 87; CHECK-NEXT: i32.const $push10=, 0 88; CHECK-NEXT: i32.const $push9=, 1024 89; CHECK-NEXT: call $push2=, memset, $0, $pop10, $pop9 90; CHECK-NEXT: i32.const $push5=, 4096 91; CHECK-NEXT: i32.add $push6=, $pop2, $pop5 92; CHECK-NEXT: global.set __stack_pointer, $pop6 93; CHECK-NEXT: return 94entry: 95 %a = alloca [2048 x i8], align 16 96 %b = alloca [2048 x i8], align 16 97 call void @llvm.memset.p0.i32(ptr align 16 %a, i8 256, i32 1024, i1 false) 98 call void @llvm.memset.p0.i32(ptr align 16 %b, i8 256, i32 1024, i1 false) 99 ret void 100} 101 102; If the result value of memset doesn't get stackified, it should be marked 103; $drop. Note that we use a call to prevent tail dup so that we can test 104; this specific functionality. 105 106declare ptr @def() 107declare void @block_tail_dup() 108define ptr @drop_result(ptr %arg, i8 %arg1, i32 %arg2, i32 %arg3, i32 %arg4) { 109; CHECK-LABEL: drop_result: 110; CHECK: .functype drop_result (i32, i32, i32, i32, i32) -> (i32) 111; CHECK-NEXT: # %bb.0: # %bb 112; CHECK-NEXT: block 113; CHECK-NEXT: block 114; CHECK-NEXT: br_if 0, $3 # 0: down to label1 115; CHECK-NEXT: # %bb.1: # %bb5 116; CHECK-NEXT: br_if 1, $4 # 1: down to label0 117; CHECK-NEXT: # %bb.2: # %bb7 118; CHECK-NEXT: call $drop=, memset, $0, $1, $2 119; CHECK-NEXT: call block_tail_dup 120; CHECK-NEXT: return $0 121; CHECK-NEXT: .LBB7_3: # %bb9 122; CHECK-NEXT: end_block # label1: 123; CHECK-NEXT: call $0=, def 124; CHECK-NEXT: .LBB7_4: # %bb11 125; CHECK-NEXT: end_block # label0: 126; CHECK-NEXT: call block_tail_dup 127; CHECK-NEXT: return $0 128bb: 129 %tmp = icmp eq i32 %arg3, 0 130 br i1 %tmp, label %bb5, label %bb9 131 132bb5: 133 %tmp6 = icmp eq i32 %arg4, 0 134 br i1 %tmp6, label %bb7, label %bb8 135 136bb7: 137 call void @llvm.memset.p0.i32(ptr %arg, i8 %arg1, i32 %arg2, i1 false) 138 br label %bb11 139 140bb8: 141 br label %bb11 142 143bb9: 144 %tmp10 = call ptr @def() 145 br label %bb11 146 147bb11: 148 %tmp12 = phi ptr [ %arg, %bb7 ], [ %arg, %bb8 ], [ %tmp10, %bb9 ] 149 call void @block_tail_dup() 150 ret ptr %tmp12 151} 152 153; This is the same as drop_result, except we let tail dup happen, so the 154; result of the memset *is* stackified. 155 156define ptr @tail_dup_to_reuse_result(ptr %arg, i8 %arg1, i32 %arg2, i32 %arg3, i32 %arg4) { 157; CHECK-LABEL: tail_dup_to_reuse_result: 158; CHECK: .functype tail_dup_to_reuse_result (i32, i32, i32, i32, i32) -> (i32) 159; CHECK-NEXT: # %bb.0: # %bb 160; CHECK-NEXT: block 161; CHECK-NEXT: block 162; CHECK-NEXT: br_if 0, $3 # 0: down to label3 163; CHECK-NEXT: # %bb.1: # %bb5 164; CHECK-NEXT: br_if 1, $4 # 1: down to label2 165; CHECK-NEXT: # %bb.2: # %bb7 166; CHECK-NEXT: call $push0=, memset, $0, $1, $2 167; CHECK-NEXT: return $pop0 168; CHECK-NEXT: .LBB8_3: # %bb9 169; CHECK-NEXT: end_block # label3: 170; CHECK-NEXT: call $0=, def 171; CHECK-NEXT: .LBB8_4: # %bb11 172; CHECK-NEXT: end_block # label2: 173; CHECK-NEXT: return $0 174bb: 175 %tmp = icmp eq i32 %arg3, 0 176 br i1 %tmp, label %bb5, label %bb9 177 178bb5: 179 %tmp6 = icmp eq i32 %arg4, 0 180 br i1 %tmp6, label %bb7, label %bb8 181 182bb7: 183 call void @llvm.memset.p0.i32(ptr %arg, i8 %arg1, i32 %arg2, i1 false) 184 br label %bb11 185 186bb8: 187 br label %bb11 188 189bb9: 190 %tmp10 = call ptr @def() 191 br label %bb11 192 193bb11: 194 %tmp12 = phi ptr [ %arg, %bb7 ], [ %arg, %bb8 ], [ %tmp10, %bb9 ] 195 ret ptr %tmp12 196} 197