mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	For now just handles simple comparisons of an ANDed value with zero. The CC value provides enough information to do any comparison for a 2-bit mask, and some nonzero comparisons with more populated masks, but that's all future work. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189469 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			800 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			LLVM
		
	
	
	
	
	
			
		
		
	
	
			800 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			LLVM
		
	
	
	
	
	
| ; Test that compares are ommitted if CC already has the right value
 | |
| ; (z10 version).
 | |
| ;
 | |
| ; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
 | |
| 
 | |
| declare void @foo()
 | |
| 
 | |
| ; Addition provides enough for equality comparisons with zero.  First teest
 | |
| ; the EQ case.
 | |
| define i32 @f1(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f1:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: je .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   %cmp = icmp eq i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and again with NE.
 | |
| define i32 @f2(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f2:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: jne .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; SLT requires a comparison.
 | |
| define i32 @f3(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f3:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: cijl %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   %cmp = icmp slt i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...SLE too.
 | |
| define i32 @f4(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f4:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: cijle %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   %cmp = icmp sle i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...SGT too.
 | |
| define i32 @f5(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f5:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: cijh %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   %cmp = icmp sgt i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...SGE too.
 | |
| define i32 @f6(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f6:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: cijhe %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   %cmp = icmp sge i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Subtraction also provides enough for equality comparisons with zero.
 | |
| define i32 @f7(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f7:
 | |
| ; CHECK: s %r2, 0(%r4)
 | |
| ; CHECK-NEXT: jne .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %cur = load i32 *%dest
 | |
|   %res = sub i32 %a, %cur
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...but not for ordered comparisons.
 | |
| define i32 @f8(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f8:
 | |
| ; CHECK: s %r2, 0(%r4)
 | |
| ; CHECK-NEXT: cijl %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %cur = load i32 *%dest
 | |
|   %res = sub i32 %a, %cur
 | |
|   %cmp = icmp slt i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Logic register-register instructions also provide enough for equality
 | |
| ; comparisons with zero.
 | |
| define i32 @f9(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f9:
 | |
| ; CHECK: nr %r2, %r3
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = and i32 %a, %b
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...but not for ordered comparisons.
 | |
| define i32 @f10(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f10:
 | |
| ; CHECK: nr %r2, %r3
 | |
| ; CHECK-NEXT: cijl %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = and i32 %a, %b
 | |
|   %cmp = icmp slt i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Logic register-immediate instructions also provide enough for equality
 | |
| ; comparisons with zero if the immediate covers the whole register.
 | |
| define i32 @f11(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f11:
 | |
| ; CHECK: nilf %r2, 100000001
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = and i32 %a, 100000001
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Partial logic register-immediate instructions do not provide simple
 | |
| ; zero results.
 | |
| define i32 @f12(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f12:
 | |
| ; CHECK: nill %r2, 65436
 | |
| ; CHECK-NEXT: cijlh %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = and i32 %a, -100
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; SRA provides the same CC result as a comparison with zero.
 | |
| define i32 @f13(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f13:
 | |
| ; CHECK: sra %r2, 0(%r3)
 | |
| ; CHECK-NEXT: je .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = ashr i32 %a, %b
 | |
|   %cmp = icmp eq i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and again with NE.
 | |
| define i32 @f14(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f14:
 | |
| ; CHECK: sra %r2, 0(%r3)
 | |
| ; CHECK-NEXT: jlh .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = ashr i32 %a, %b
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and SLT.
 | |
| define i32 @f15(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f15:
 | |
| ; CHECK: sra %r2, 0(%r3)
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = ashr i32 %a, %b
 | |
|   %cmp = icmp slt i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and SLE.
 | |
| define i32 @f16(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f16:
 | |
| ; CHECK: sra %r2, 0(%r3)
 | |
| ; CHECK-NEXT: jle .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = ashr i32 %a, %b
 | |
|   %cmp = icmp sle i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and SGT.
 | |
| define i32 @f17(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f17:
 | |
| ; CHECK: sra %r2, 0(%r3)
 | |
| ; CHECK-NEXT: jh .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = ashr i32 %a, %b
 | |
|   %cmp = icmp sgt i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and SGE.
 | |
| define i32 @f18(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f18:
 | |
| ; CHECK: sra %r2, 0(%r3)
 | |
| ; CHECK-NEXT: jhe .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = ashr i32 %a, %b
 | |
|   %cmp = icmp sge i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; RISBG provides the same result as a comparison against zero.
 | |
| ; Test the EQ case.
 | |
| define i64 @f19(i64 %a, i64 %b, i64 *%dest) {
 | |
| ; CHECK-LABEL: f19:
 | |
| ; CHECK: risbg %r2, %r3, 0, 190, 0
 | |
| ; CHECK-NEXT: je .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = and i64 %b, -2
 | |
|   %cmp = icmp eq i64 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %b, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %res
 | |
| }
 | |
| 
 | |
| ; ...and the SLT case.
 | |
| define i64 @f20(i64 %a, i64 %b, i64 *%dest) {
 | |
| ; CHECK-LABEL: f20:
 | |
| ; CHECK: risbg %r2, %r3, 0, 190, 0
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = and i64 %b, -2
 | |
|   %cmp = icmp slt i64 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %b, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %res
 | |
| }
 | |
| 
 | |
| ; Test a case where the register we're testing is set by a non-CC-clobbering
 | |
| ; instruction.
 | |
| define i32 @f21(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f21:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r2
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: cije %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i32 %a, 1000000
 | |
|   %res = call i32 asm "blah $0", "=r,0" (i32 %add)
 | |
|   %cmp = icmp eq i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; ...and again with a CC-clobbering instruction.
 | |
| define i32 @f22(i32 %a, i32 %b, i32 *%dest) {
 | |
| ; CHECK-LABEL: f22:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r2
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: cije %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i32 %a, 1000000
 | |
|   %res = call i32 asm "blah $0", "=r,0,~{cc}" (i32 %add)
 | |
|   %cmp = icmp eq i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Check that stores do not interfere.
 | |
| define i32 @f23(i32 %a, i32 %b, i32 *%dest1, i32 *%dest2) {
 | |
| ; CHECK-LABEL: f23:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: st %r2, 0(%r4)
 | |
| ; CHECK-NEXT: jne .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %res = add i32 %a, 1000000
 | |
|   store i32 %res, i32 *%dest1
 | |
|   %cmp = icmp ne i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %b, i32 *%dest2
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Check that calls do interfere.
 | |
| define void @f24(i32 *%ptr) {
 | |
| ; CHECK-LABEL: f24:
 | |
| ; CHECK: afi [[REG:%r[0-9]+]], 1000000
 | |
| ; CHECK-NEXT: brasl %r14, foo@PLT
 | |
| ; CHECK-NEXT: cijlh [[REG]], 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %val = load i32 *%ptr
 | |
|   %xor = xor i32 %val, 1
 | |
|   %add = add i32 %xor, 1000000
 | |
|   call void @foo()
 | |
|   %cmp = icmp ne i32 %add, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %add, i32 *%ptr
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; Check that inline asms don't interfere if they don't clobber CC.
 | |
| define void @f25(i32 %a, i32 *%ptr) {
 | |
| ; CHECK-LABEL: f25:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jne .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i32 %a, 1000000
 | |
|   call void asm sideeffect "blah", "r"(i32 %add)
 | |
|   %cmp = icmp ne i32 %add, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %add, i32 *%ptr
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; ...but do interfere if they do clobber CC.
 | |
| define void @f26(i32 %a, i32 *%ptr) {
 | |
| ; CHECK-LABEL: f26:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: cijlh %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i32 %a, 1000000
 | |
|   call void asm sideeffect "blah", "r,~{cc}"(i32 %add)
 | |
|   %cmp = icmp ne i32 %add, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %add, i32 *%ptr
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; Test a case where CC is set based on a different register from the
 | |
| ; compare input.
 | |
| define i32 @f27(i32 %a, i32 %b, i32 *%dest1, i32 *%dest2) {
 | |
| ; CHECK-LABEL: f27:
 | |
| ; CHECK: afi %r2, 1000000
 | |
| ; CHECK-NEXT: sr %r3, %r2
 | |
| ; CHECK-NEXT: st %r3, 0(%r4)
 | |
| ; CHECK-NEXT: cije %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i32 %a, 1000000
 | |
|   %sub = sub i32 %b, %add
 | |
|   store i32 %sub, i32 *%dest1
 | |
|   %cmp = icmp eq i32 %add, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %sub, i32 *%dest2
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %add
 | |
| }
 | |
| 
 | |
| ; Make sure that we don't confuse a base register for a destination.
 | |
| define void @f28(i64 %a, i64 *%dest) {
 | |
| ; CHECK-LABEL: f28:
 | |
| ; CHECK: xi 0(%r2), 15
 | |
| ; CHECK: cgije %r2, 0, .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %ptr = inttoptr i64 %a to i8 *
 | |
|   %val = load i8 *%ptr
 | |
|   %xor = xor i8 %val, 15
 | |
|   store i8 %xor, i8 *%ptr
 | |
|   %cmp = icmp eq i64 %a, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %a, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; Test that L gets converted to LT where useful.
 | |
| define i32 @f29(i64 %base, i64 %index, i32 *%dest) {
 | |
| ; CHECK-LABEL: f29:
 | |
| ; CHECK: lt %r2, 0({{%r2,%r3|%r3,%r2}})
 | |
| ; CHECK-NEXT: jle .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i64 %base, %index
 | |
|   %ptr = inttoptr i64 %add to i32 *
 | |
|   %res = load i32 *%ptr
 | |
|   %cmp = icmp sle i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %res, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Test that LY gets converted to LT where useful.
 | |
| define i32 @f30(i64 %base, i64 %index, i32 *%dest) {
 | |
| ; CHECK-LABEL: f30:
 | |
| ; CHECK: lt %r2, 100000({{%r2,%r3|%r3,%r2}})
 | |
| ; CHECK-NEXT: jle .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add1 = add i64 %base, %index
 | |
|   %add2 = add i64 %add1, 100000
 | |
|   %ptr = inttoptr i64 %add2 to i32 *
 | |
|   %res = load i32 *%ptr
 | |
|   %cmp = icmp sle i32 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %res, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %res
 | |
| }
 | |
| 
 | |
| ; Test that LG gets converted to LTG where useful.
 | |
| define i64 @f31(i64 %base, i64 %index, i64 *%dest) {
 | |
| ; CHECK-LABEL: f31:
 | |
| ; CHECK: ltg %r2, 0({{%r2,%r3|%r3,%r2}})
 | |
| ; CHECK-NEXT: jhe .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i64 %base, %index
 | |
|   %ptr = inttoptr i64 %add to i64 *
 | |
|   %res = load i64 *%ptr
 | |
|   %cmp = icmp sge i64 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %res, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %res
 | |
| }
 | |
| 
 | |
| ; Test that LGF gets converted to LTGF where useful.
 | |
| define i64 @f32(i64 %base, i64 %index, i64 *%dest) {
 | |
| ; CHECK-LABEL: f32:
 | |
| ; CHECK: ltgf %r2, 0({{%r2,%r3|%r3,%r2}})
 | |
| ; CHECK-NEXT: jh .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %add = add i64 %base, %index
 | |
|   %ptr = inttoptr i64 %add to i32 *
 | |
|   %val = load i32 *%ptr
 | |
|   %res = sext i32 %val to i64
 | |
|   %cmp = icmp sgt i64 %res, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %res, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %res
 | |
| }
 | |
| 
 | |
| ; Test that LR gets converted to LTR where useful.
 | |
| define i32 @f33(i32 %dummy, i32 %val, i32 *%dest) {
 | |
| ; CHECK-LABEL: f33:
 | |
| ; CHECK: ltr %r2, %r3
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r2
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   call void asm sideeffect "blah $0", "{r2}"(i32 %val)
 | |
|   %cmp = icmp slt i32 %val, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %val, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %val
 | |
| }
 | |
| 
 | |
| ; Test that LGR gets converted to LTGR where useful.
 | |
| define i64 @f34(i64 %dummy, i64 %val, i64 *%dest) {
 | |
| ; CHECK-LABEL: f34:
 | |
| ; CHECK: ltgr %r2, %r3
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r2
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jh .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   call void asm sideeffect "blah $0", "{r2}"(i64 %val)
 | |
|   %cmp = icmp sgt i64 %val, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %val, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %val
 | |
| }
 | |
| 
 | |
| ; Test that LGFR gets converted to LTGFR where useful.
 | |
| define i64 @f35(i64 %dummy, i32 %val, i64 *%dest) {
 | |
| ; CHECK-LABEL: f35:
 | |
| ; CHECK: ltgfr %r2, %r3
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r2
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jh .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %ext = sext i32 %val to i64
 | |
|   call void asm sideeffect "blah $0", "{r2}"(i64 %ext)
 | |
|   %cmp = icmp sgt i64 %ext, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %ext, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %ext
 | |
| }
 | |
| 
 | |
| ; Test a case where it is the source rather than destination of LR that
 | |
| ; we need.
 | |
| define i32 @f36(i32 %val, i32 %dummy, i32 *%dest) {
 | |
| ; CHECK-LABEL: f36:
 | |
| ; CHECK: ltr %r3, %r2
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r3
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   call void asm sideeffect "blah $0", "{r3}"(i32 %val)
 | |
|   %cmp = icmp slt i32 %val, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %val, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %val
 | |
| }
 | |
| 
 | |
| ; Test a case where it is the source rather than destination of LGR that
 | |
| ; we need.
 | |
| define i64 @f37(i64 %val, i64 %dummy, i64 *%dest) {
 | |
| ; CHECK-LABEL: f37:
 | |
| ; CHECK: ltgr %r3, %r2
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r3
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   call void asm sideeffect "blah $0", "{r3}"(i64 %val)
 | |
|   %cmp = icmp slt i64 %val, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i64 %val, i64 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i64 %val
 | |
| }
 | |
| 
 | |
| ; Test a case where it is the source rather than destination of LGFR that
 | |
| ; we need.
 | |
| define i32 @f38(i32 %val, i64 %dummy, i32 *%dest) {
 | |
| ; CHECK-LABEL: f38:
 | |
| ; CHECK: ltgfr %r3, %r2
 | |
| ; CHECK-NEXT: #APP
 | |
| ; CHECK-NEXT: blah %r3
 | |
| ; CHECK-NEXT: #NO_APP
 | |
| ; CHECK-NEXT: jl .L{{.*}}
 | |
| ; CHECK: br %r14
 | |
| entry:
 | |
|   %ext = sext i32 %val to i64
 | |
|   call void asm sideeffect "blah $0", "{r3}"(i64 %ext)
 | |
|   %cmp = icmp slt i32 %val, 0
 | |
|   br i1 %cmp, label %exit, label %store
 | |
| 
 | |
| store:
 | |
|   store i32 %val, i32 *%dest
 | |
|   br label %exit
 | |
| 
 | |
| exit:
 | |
|   ret i32 %val
 | |
| }
 |