Files
clang-p2996/llvm/test/CodeGen/WebAssembly/reg-stackify.ll
Dan Gohman b6fd39a3a7 [WebAssembly] Rematerialize constants rather than hold them live in registers.
Teach the register stackifier to rematerialize constants that have multiple
uses instead of leaving them in registers. In the WebAssembly encoding, it's
the same code size to materialize most constants as it is to read a value
from a register.

llvm-svn: 258142
2016-01-19 16:59:23 +00:00

132 lines
3.6 KiB
LLVM

; RUN: llc < %s -asm-verbose=false -verify-machineinstrs | FileCheck %s
; Test the register stackifier pass.
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
target triple = "wasm32-unknown-unknown"
; No because of pointer aliasing.
; CHECK-LABEL: no0:
; CHECK: return $1{{$}}
define i32 @no0(i32* %p, i32* %q) {
%t = load i32, i32* %q
store i32 0, i32* %p
ret i32 %t
}
; No because of side effects.
; CHECK-LABEL: no1:
; CHECK: return $1{{$}}
define i32 @no1(i32* %p, i32* dereferenceable(4) %q) {
%t = load volatile i32, i32* %q, !invariant.load !0
store volatile i32 0, i32* %p
ret i32 %t
}
; Yes because of invariant load and no side effects.
; CHECK-LABEL: yes0:
; CHECK: return $pop0{{$}}
define i32 @yes0(i32* %p, i32* dereferenceable(4) %q) {
%t = load i32, i32* %q, !invariant.load !0
store i32 0, i32* %p
ret i32 %t
}
; Yes because of no intervening side effects.
; CHECK-LABEL: yes1:
; CHECK: return $pop0{{$}}
define i32 @yes1(i32* %q) {
%t = load volatile i32, i32* %q
ret i32 %t
}
; Don't schedule stack uses into the stack. To reduce register pressure, the
; scheduler might be tempted to move the definition of $2 down. However, this
; would risk getting incorrect liveness if the instructions are later
; rearranged to make the stack contiguous.
; CHECK-LABEL: stack_uses:
; CHECK-NEXT: .param i32, i32, i32, i32{{$}}
; CHECK-NEXT: .result i32{{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: i32.const $push13=, 1{{$}}
; CHECK-NEXT: i32.lt_s $push0=, $0, $pop13{{$}}
; CHECK-NEXT: i32.const $push1=, 2{{$}}
; CHECK-NEXT: i32.lt_s $push2=, $1, $pop1{{$}}
; CHECK-NEXT: i32.xor $push5=, $pop0, $pop2{{$}}
; CHECK-NEXT: i32.const $push12=, 1{{$}}
; CHECK-NEXT: i32.lt_s $push3=, $2, $pop12{{$}}
; CHECK-NEXT: i32.const $push11=, 2{{$}}
; CHECK-NEXT: i32.lt_s $push4=, $3, $pop11{{$}}
; CHECK-NEXT: i32.xor $push6=, $pop3, $pop4{{$}}
; CHECK-NEXT: i32.xor $push7=, $pop5, $pop6{{$}}
; CHECK-NEXT: i32.const $push10=, 1{{$}}
; CHECK-NEXT: i32.ne $push8=, $pop7, $pop10{{$}}
; CHECK-NEXT: br_if $pop8, 0{{$}}
; CHECK-NEXT: i32.const $push9=, 0{{$}}
; CHECK-NEXT: return $pop9{{$}}
; CHECK-NEXT: .LBB4_2:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: i32.const $push14=, 1{{$}}
; CHECK-NEXT: return $pop14{{$}}
define i32 @stack_uses(i32 %x, i32 %y, i32 %z, i32 %w) {
entry:
%c = icmp sle i32 %x, 0
%d = icmp sle i32 %y, 1
%e = icmp sle i32 %z, 0
%f = icmp sle i32 %w, 1
%g = xor i1 %c, %d
%h = xor i1 %e, %f
%i = xor i1 %g, %h
br i1 %i, label %true, label %false
true:
ret i32 0
false:
ret i32 1
}
; Test an interesting case where the load has multiple uses and cannot
; be trivially stackified.
; CHECK-LABEL: multiple_uses:
; CHECK-NEXT: .param i32, i32, i32{{$}}
; CHECK-NEXT: .local i32{{$}}
; CHECK-NEXT: i32.load $3=, 0($2){{$}}
; CHECK-NEXT: block{{$}}
; CHECK-NEXT: i32.ge_u $push0=, $3, $1{{$}}
; CHECK-NEXT: br_if $pop0, 0{{$}}
; CHECK-NEXT: i32.lt_u $push1=, $3, $0{{$}}
; CHECK-NEXT: br_if $pop1, 0{{$}}
; CHECK-NEXT: i32.store $discard=, 0($2), $3{{$}}
; CHECK-NEXT: .LBB5_3:
; CHECK-NEXT: end_block{{$}}
; CHECK-NEXT: return{{$}}
define void @multiple_uses(i32* %arg0, i32* %arg1, i32* %arg2) nounwind {
bb:
br label %loop
loop:
%tmp7 = load i32, i32* %arg2
%tmp8 = inttoptr i32 %tmp7 to i32*
%tmp9 = icmp uge i32* %tmp8, %arg1
%tmp10 = icmp ult i32* %tmp8, %arg0
%tmp11 = or i1 %tmp9, %tmp10
br i1 %tmp11, label %back, label %then
then:
store i32 %tmp7, i32* %arg2
br label %back
back:
br i1 undef, label %return, label %loop
return:
ret void
}
!0 = !{}