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