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)
 |