Derek Schuff d4207ba0f6 [WebAssembly] Stackify code emitted by eliminateFrameIndex and SP writeback
Summary:
MRI::eliminateFrameIndex can emit several instructions to do address
calculations; these can usually be stackified. Because instructions with
FI operands can have subsequent operands which may be expression trees,
find the top of the leftmost tree and insert the code before it, to keep
the LIFO property.

Also use stackified registers when writing back the SP value to memory
in the epilog; it's unnecessary because SP will not be used after the
epilog, and it results in better code.

Differential Revision: http://reviews.llvm.org/D18234

llvm-svn: 263725
2016-03-17 17:00:29 +00:00

108 lines
3.4 KiB
LLVM

; RUN: llc < %s -asm-verbose=false | FileCheck %s
; Test memcpy, memmove, and memset intrinsics.
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1)
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i32, i1)
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1)
; Test that return values are optimized.
; CHECK-LABEL: copy_yes:
; CHECK: i32.call $push0=, memcpy@FUNCTION, $0, $1, $2{{$}}
; CHECK-NEXT: return $pop0{{$}}
define i8* @copy_yes(i8* %dst, i8* %src, i32 %len) {
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dst, i8* %src, i32 %len, i32 1, i1 false)
ret i8* %dst
}
; CHECK-LABEL: copy_no:
; CHECK: i32.call $discard=, memcpy@FUNCTION, $0, $1, $2{{$}}
; CHECK-NEXT: return{{$}}
define void @copy_no(i8* %dst, i8* %src, i32 %len) {
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dst, i8* %src, i32 %len, i32 1, i1 false)
ret void
}
; CHECK-LABEL: move_yes:
; CHECK: i32.call $push0=, memmove@FUNCTION, $0, $1, $2{{$}}
; CHECK-NEXT: return $pop0{{$}}
define i8* @move_yes(i8* %dst, i8* %src, i32 %len) {
call void @llvm.memmove.p0i8.p0i8.i32(i8* %dst, i8* %src, i32 %len, i32 1, i1 false)
ret i8* %dst
}
; CHECK-LABEL: move_no:
; CHECK: i32.call $discard=, memmove@FUNCTION, $0, $1, $2{{$}}
; CHECK-NEXT: return{{$}}
define void @move_no(i8* %dst, i8* %src, i32 %len) {
call void @llvm.memmove.p0i8.p0i8.i32(i8* %dst, i8* %src, i32 %len, i32 1, i1 false)
ret void
}
; CHECK-LABEL: set_yes:
; CHECK: i32.call $push0=, memset@FUNCTION, $0, $1, $2{{$}}
; CHECK-NEXT: return $pop0{{$}}
define i8* @set_yes(i8* %dst, i8 %src, i32 %len) {
call void @llvm.memset.p0i8.i32(i8* %dst, i8 %src, i32 %len, i32 1, i1 false)
ret i8* %dst
}
; CHECK-LABEL: set_no:
; CHECK: i32.call $discard=, memset@FUNCTION, $0, $1, $2{{$}}
; CHECK-NEXT: return{{$}}
define void @set_no(i8* %dst, i8 %src, i32 %len) {
call void @llvm.memset.p0i8.i32(i8* %dst, i8 %src, i32 %len, i32 1, i1 false)
ret void
}
; CHECK-LABEL: frame_index:
; CHECK: i32.call $discard=, memset@FUNCTION, $pop12, $pop1, $pop0{{$}}
; CHECK: i32.call $discard=, memset@FUNCTION, $0, $pop3, $pop2{{$}}
; CHECK: return{{$}}
define void @frame_index() {
entry:
%a = alloca [2048 x i8], align 16
%b = alloca [2048 x i8], align 16
%0 = getelementptr inbounds [2048 x i8], [2048 x i8]* %a, i32 0, i32 0
%1 = getelementptr inbounds [2048 x i8], [2048 x i8]* %b, i32 0, i32 0
call void @llvm.memset.p0i8.i32(i8* %0, i8 256, i32 1024, i32 16, i1 false)
call void @llvm.memset.p0i8.i32(i8* %1, i8 256, i32 1024, i32 16, i1 false)
ret void
}
; If the result value of memset doesn't get stackified, it should be marked
; $discard.
; CHECK-LABEL: discard_result:
; CHECK: i32.call $discard=, memset@FUNCTION, $0, $1, $2
declare i8* @def()
define i8* @discard_result(i8* %arg, i8 %arg1, i32 %arg2, i32 %arg3, i32 %arg4) {
bb:
%tmp = icmp eq i32 %arg3, 0
br i1 %tmp, label %bb5, label %bb9
bb5:
%tmp6 = icmp eq i32 %arg4, 0
br i1 %tmp6, label %bb7, label %bb8
bb7:
call void @llvm.memset.p0i8.i32(i8* %arg, i8 %arg1, i32 %arg2, i32 1, i1 false)
br label %bb11
bb8:
br label %bb11
bb9:
%tmp10 = call i8* @def()
br label %bb11
bb11:
%tmp12 = phi i8* [ %arg, %bb7 ], [ %arg, %bb8 ], [ %tmp10, %bb9 ]
ret i8* %tmp12
}