311 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			LLVM
		
	
	
	
| ; RUN: llc -mtriple=thumbv7em -mattr=+fp-armv8 %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DEFAULT
 | |
| ; RUN: llc -mtriple=thumbv8m.main -mattr=+fp-armv8,+dsp %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DEFAULT
 | |
| ; RUN: llc -mtriple=thumbv8m.main -mattr=+fp-armv8,+dsp -lsr-backedge-indexing=false %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLED
 | |
| ; RUN: llc -mtriple=thumbv8 %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLED
 | |
| ; RUN: llc -mtriple=thumbv8m.main -mattr=+fp-armv8,+dsp -lsr-complexity-limit=2147483647 %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-COMPLEX
 | |
| 
 | |
| ; CHECK-LABEL: test_qadd_2
 | |
| ; CHECK: @ %loop
 | |
| 
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: str{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]!
 | |
| ; CHECK-DEAFULT: ldr{{.*}}, #8]!
 | |
| ; CHECK-DEFAULT: str{{.*}}, #8]!
 | |
| 
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]!
 | |
| ; CHECK-COMPLEX: str{{.*}}, #8]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #4]
 | |
| 
 | |
| ; DISABLED-NOT: ldr{{.*}}]!
 | |
| ; DISABLED-NOT: str{{.*}}]!
 | |
| 
 | |
| define void @test_qadd_2(i32* %a.array, i32* %b.array, i32* %out.array, i32 %N) {
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
 | |
|   %idx.1 = phi i32 [ 0, %entry ], [ %idx.next, %loop ]
 | |
|   %gep.a.1 = getelementptr inbounds i32, i32* %a.array, i32 %idx.1
 | |
|   %a.1 = load i32, i32* %gep.a.1
 | |
|   %gep.b.1 = getelementptr inbounds i32, i32* %b.array, i32 %idx.1
 | |
|   %b.1 = load i32, i32* %gep.b.1
 | |
|   %qadd.1 = call i32 @llvm.arm.qadd(i32 %a.1, i32 %b.1)
 | |
|   %addr.1 = getelementptr inbounds i32, i32* %out.array, i32 %idx.1
 | |
|   store i32 %qadd.1, i32* %addr.1
 | |
|   %idx.2 = or i32 %idx.1, 1
 | |
|   %gep.a.2 = getelementptr inbounds i32, i32* %a.array, i32 %idx.2
 | |
|   %a.2 = load i32, i32* %gep.a.2
 | |
|   %gep.b.2 = getelementptr inbounds i32, i32* %b.array, i32 %idx.2
 | |
|   %b.2 = load i32, i32* %gep.b.2
 | |
|   %qadd.2 = call i32 @llvm.arm.qadd(i32 %a.2, i32 %b.2)
 | |
|   %addr.2 = getelementptr inbounds i32, i32* %out.array, i32 %idx.2
 | |
|   store i32 %qadd.2, i32* %addr.2
 | |
|   %i.next = add nsw nuw i32 %i, -2
 | |
|   %idx.next = add nsw nuw i32 %idx.1, 2
 | |
|   %cmp = icmp ult i32 %i.next, %N
 | |
|   br i1 %cmp, label %loop, label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; CHECK-LABEL: test_qadd_2_backwards
 | |
| ; TODO: Indexes should be generated.
 | |
| 
 | |
| ; CHECK: @ %loop
 | |
| 
 | |
| ; CHECK-DEFAULT: ldr{{.*}},
 | |
| ; CHECK-DEFAULT: ldr{{.*}},
 | |
| ; CHECK-DEFAULT: str{{.*}},
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #-4]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #-4]
 | |
| ; CHECK-DEFAULT: sub{{.*}}, #8
 | |
| ; CHECK-DEFAULT: str{{.*}}, #-4]
 | |
| ; CHECK-DEFAULT: sub{{.*}}, #8
 | |
| 
 | |
| ; CHECK-COMPLEX: ldr{{.*}} lsl #2]
 | |
| ; CHECK-COMPLEX: ldr{{.*}} lsl #2]
 | |
| ; CHECK-COMPLEX: str{{.*}} lsl #2]
 | |
| ; CHECK-COMPLEX: ldr{{.*}} lsl #2]
 | |
| ; CHECK-COMPLEX: ldr{{.*}} lsl #2]
 | |
| ; CHECK-COMPLEX: str{{.*}} lsl #2]
 | |
| 
 | |
| ; DISABLED-NOT: ldr{{.*}}]!
 | |
| ; DISABLED-NOT: str{{.*}}]!
 | |
| 
 | |
| define void @test_qadd_2_backwards(i32* %a.array, i32* %b.array, i32* %out.array, i32 %N) {
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
 | |
|   %idx.1 = phi i32 [ %N, %entry ], [ %idx.next, %loop ]
 | |
|   %gep.a.1 = getelementptr inbounds i32, i32* %a.array, i32 %idx.1
 | |
|   %a.1 = load i32, i32* %gep.a.1
 | |
|   %gep.b.1 = getelementptr inbounds i32, i32* %b.array, i32 %idx.1
 | |
|   %b.1 = load i32, i32* %gep.b.1
 | |
|   %qadd.1 = call i32 @llvm.arm.qadd(i32 %a.1, i32 %b.1)
 | |
|   %addr.1 = getelementptr inbounds i32, i32* %out.array, i32 %idx.1
 | |
|   store i32 %qadd.1, i32* %addr.1
 | |
|   %idx.2 = sub nsw nuw i32 %idx.1, 1
 | |
|   %gep.a.2 = getelementptr inbounds i32, i32* %a.array, i32 %idx.2
 | |
|   %a.2 = load i32, i32* %gep.a.2
 | |
|   %gep.b.2 = getelementptr inbounds i32, i32* %b.array, i32 %idx.2
 | |
|   %b.2 = load i32, i32* %gep.b.2
 | |
|   %qadd.2 = call i32 @llvm.arm.qadd(i32 %a.2, i32 %b.2)
 | |
|   %addr.2 = getelementptr inbounds i32, i32* %out.array, i32 %idx.2
 | |
|   store i32 %qadd.2, i32* %addr.2
 | |
|   %i.next = add nsw nuw i32 %i, -2
 | |
|   %idx.next = sub nsw nuw i32 %idx.1, 2
 | |
|   %cmp = icmp ult i32 %i.next, %N
 | |
|   br i1 %cmp, label %loop, label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; CHECK-LABEL: test_qadd_3
 | |
| ; CHECK: @ %loop
 | |
| 
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: str{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #12]!
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #12]!
 | |
| ; CHECK-DEFAULT: str{{.*}}, #12]!
 | |
| 
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #12]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #12]!
 | |
| ; CHECK-COMPLEX: str{{.*}}, #12]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #8]
 | |
| 
 | |
| ; DISABLED-NOT: ldr{{.*}}]!
 | |
| ; DISABLED-NOT: str{{.*}}]!
 | |
| 
 | |
| define void @test_qadd_3(i32* %a.array, i32* %b.array, i32* %out.array, i32 %N) {
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
 | |
|   %idx.1 = phi i32 [ 0, %entry ], [ %idx.next, %loop ]
 | |
|   %gep.a.1 = getelementptr inbounds i32, i32* %a.array, i32 %idx.1
 | |
|   %a.1 = load i32, i32* %gep.a.1
 | |
|   %gep.b.1 = getelementptr inbounds i32, i32* %b.array, i32 %idx.1
 | |
|   %b.1 = load i32, i32* %gep.b.1
 | |
|   %qadd.1 = call i32 @llvm.arm.qadd(i32 %a.1, i32 %b.1)
 | |
|   %addr.1 = getelementptr inbounds i32, i32* %out.array, i32 %idx.1
 | |
|   store i32 %qadd.1, i32* %addr.1
 | |
|   %idx.2 = add nuw nsw i32 %idx.1, 1
 | |
|   %gep.a.2 = getelementptr inbounds i32, i32* %a.array, i32 %idx.2
 | |
|   %a.2 = load i32, i32* %gep.a.2
 | |
|   %gep.b.2 = getelementptr inbounds i32, i32* %b.array, i32 %idx.2
 | |
|   %b.2 = load i32, i32* %gep.b.2
 | |
|   %qadd.2 = call i32 @llvm.arm.qadd(i32 %a.2, i32 %b.2)
 | |
|   %addr.2 = getelementptr inbounds i32, i32* %out.array, i32 %idx.2
 | |
|   store i32 %qadd.2, i32* %addr.2
 | |
|   %idx.3 = add nuw nsw i32 %idx.1, 2
 | |
|   %gep.a.3 = getelementptr inbounds i32, i32* %a.array, i32 %idx.3
 | |
|   %a.3 = load i32, i32* %gep.a.3
 | |
|   %gep.b.3 = getelementptr inbounds i32, i32* %b.array, i32 %idx.3
 | |
|   %b.3 = load i32, i32* %gep.b.3
 | |
|   %qadd.3 = call i32 @llvm.arm.qadd(i32 %a.3, i32 %b.3)
 | |
|   %addr.3 = getelementptr inbounds i32, i32* %out.array, i32 %idx.3
 | |
|   store i32 %qadd.3, i32* %addr.3
 | |
|   %i.next = add nsw nuw i32 %i, -3
 | |
|   %idx.next = add nsw nuw i32 %idx.1, 3
 | |
|   %cmp = icmp ult i32 %i.next, %N
 | |
|   br i1 %cmp, label %loop, label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; CHECK-LABEL: test_qadd_4
 | |
| ; CHECK: @ %loop
 | |
| 
 | |
| ; TODO: pre-inc store
 | |
| 
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: str{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: str{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #12]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #12]
 | |
| ; CHECK-DEFAULT: str{{.*}}, #12]
 | |
| 
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #16]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #16]!
 | |
| ; CHECK-COMPLEX: str{{.*}}, #16]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #8]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #12]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #12]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #12]
 | |
| 
 | |
| ; DISABLED-NOT: ldr{{.*}}]!
 | |
| ; DISABLED-NOT: str{{.*}}]!
 | |
| 
 | |
| define void @test_qadd_4(i32* %a.array, i32* %b.array, i32* %out.array, i32 %N) {
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
 | |
|   %idx.1 = phi i32 [ 0, %entry ], [ %idx.next, %loop ]
 | |
|   %gep.a.1 = getelementptr inbounds i32, i32* %a.array, i32 %idx.1
 | |
|   %a.1 = load i32, i32* %gep.a.1
 | |
|   %gep.b.1 = getelementptr inbounds i32, i32* %b.array, i32 %idx.1
 | |
|   %b.1 = load i32, i32* %gep.b.1
 | |
|   %qadd.1 = call i32 @llvm.arm.qadd(i32 %a.1, i32 %b.1)
 | |
|   %addr.1 = getelementptr inbounds i32, i32* %out.array, i32 %idx.1
 | |
|   store i32 %qadd.1, i32* %addr.1
 | |
|   %idx.2 = or i32 %idx.1, 1
 | |
|   %gep.a.2 = getelementptr inbounds i32, i32* %a.array, i32 %idx.2
 | |
|   %a.2 = load i32, i32* %gep.a.2
 | |
|   %gep.b.2 = getelementptr inbounds i32, i32* %b.array, i32 %idx.2
 | |
|   %b.2 = load i32, i32* %gep.b.2
 | |
|   %qadd.2 = call i32 @llvm.arm.qadd(i32 %a.2, i32 %b.2)
 | |
|   %addr.2 = getelementptr inbounds i32, i32* %out.array, i32 %idx.2
 | |
|   store i32 %qadd.2, i32* %addr.2
 | |
|   %idx.3 = or i32 %idx.1, 2
 | |
|   %gep.a.3 = getelementptr inbounds i32, i32* %a.array, i32 %idx.3
 | |
|   %a.3 = load i32, i32* %gep.a.3
 | |
|   %gep.b.3 = getelementptr inbounds i32, i32* %b.array, i32 %idx.3
 | |
|   %b.3 = load i32, i32* %gep.b.3
 | |
|   %qadd.3 = call i32 @llvm.arm.qadd(i32 %a.3, i32 %b.3)
 | |
|   %addr.3 = getelementptr inbounds i32, i32* %out.array, i32 %idx.3
 | |
|   store i32 %qadd.3, i32* %addr.3
 | |
|   %idx.4 = or i32 %idx.1, 3
 | |
|   %gep.a.4 = getelementptr inbounds i32, i32* %a.array, i32 %idx.4
 | |
|   %a.4 = load i32, i32* %gep.a.4
 | |
|   %gep.b.4 = getelementptr inbounds i32, i32* %b.array, i32 %idx.4
 | |
|   %b.4 = load i32, i32* %gep.b.4
 | |
|   %qadd.4 = call i32 @llvm.arm.qadd(i32 %a.4, i32 %b.4)
 | |
|   %addr.4 = getelementptr inbounds i32, i32* %out.array, i32 %idx.4
 | |
|   store i32 %qadd.4, i32* %addr.4
 | |
|   %i.next = add nsw nuw i32 %i, -4
 | |
|   %idx.next = add nsw nuw i32 %idx.1, 4
 | |
|   %cmp = icmp ult i32 %i.next, %N
 | |
|   br i1 %cmp, label %loop, label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| ; CHECK-LABEL: test_qadd16_2
 | |
| ; CHECK: @ %loop
 | |
| ; TODO: pre-inc store.
 | |
| 
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #4]
 | |
| ; CHECK-DEFAULT: str{{.*}}, #8]
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]!
 | |
| ; CHECK-DEFAULT: ldr{{.*}}, #8]!
 | |
| ; CHECK-DEFAULT: str{{.*}}, #16]!
 | |
| 
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #8]!
 | |
| ; CHECK-COMPLEX: str{{.*}}, #16]!
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: ldr{{.*}}, #4]
 | |
| ; CHECK-COMPLEX: str{{.*}}, #8]
 | |
| 
 | |
| ; DISABLED-NOT: ldr{{.*}}]!
 | |
| ; DISABLED-NOT: str{{.*}}]!
 | |
| 
 | |
| define void @test_qadd16_2(i16* %a.array, i16* %b.array, i32* %out.array, i32 %N) {
 | |
| entry:
 | |
|   br label %loop
 | |
| 
 | |
| loop:
 | |
|   %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
 | |
|   %idx.1 = phi i32 [ 0, %entry ], [ %idx.next, %loop ]
 | |
|   %gep.a.1 = getelementptr inbounds i16, i16* %a.array, i32 %idx.1
 | |
|   %cast.a.1 = bitcast i16* %gep.a.1 to i32*
 | |
|   %a.1 = load i32, i32* %cast.a.1
 | |
|   %gep.b.1 = getelementptr inbounds i16, i16* %b.array, i32 %idx.1
 | |
|   %cast.b.1 = bitcast i16* %gep.b.1 to i32*
 | |
|   %b.1 = load i32, i32* %cast.b.1
 | |
|   %qadd.1 = call i32 @llvm.arm.qadd16(i32 %a.1, i32 %b.1)
 | |
|   %addr.1 = getelementptr inbounds i32, i32* %out.array, i32 %idx.1
 | |
|   store i32 %qadd.1, i32* %addr.1
 | |
|   %idx.2 = add nsw nuw i32 %idx.1, 2
 | |
|   %gep.a.2 = getelementptr inbounds i16, i16* %a.array, i32 %idx.2
 | |
|   %cast.a.2 = bitcast i16* %gep.a.2 to i32*
 | |
|   %a.2 = load i32, i32* %cast.a.2
 | |
|   %gep.b.2 = getelementptr inbounds i16, i16* %b.array, i32 %idx.2
 | |
|   %cast.b.2 = bitcast i16* %gep.b.2 to i32*
 | |
|   %b.2 = load i32, i32* %cast.b.2
 | |
|   %qadd.2 = call i32 @llvm.arm.qadd16(i32 %a.2, i32 %b.2)
 | |
|   %addr.2 = getelementptr inbounds i32, i32* %out.array, i32 %idx.2
 | |
|   store i32 %qadd.2, i32* %addr.2
 | |
|   %i.next = add nsw nuw i32 %i, -2
 | |
|   %idx.next = add nsw nuw i32 %idx.1, 4
 | |
|   %cmp = icmp ult i32 %i.next, %N
 | |
|   br i1 %cmp, label %loop, label %exit
 | |
| 
 | |
| exit:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| declare i32 @llvm.arm.qadd(i32, i32)
 | |
| declare i32 @llvm.arm.qadd16(i32, i32)
 |