blob: 6ce95f9031b15db73b0a8e2cd7d93478d377a2be [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=bpfel -mcpu=v3 -verify-machineinstrs < %s | FileCheck %s
; Reg-reg ADD, OR, AND, XOR and MUL are commutable, in both the 64-bit and the
; 32-bit (alu32) forms. Each loop loads one value and folds it into one
; accumulator per operation, with the accumulator as the second operand.
; Without commuting, the two-address form would copy the accumulators and the
; loaded value in every iteration. SUB is not commutable, so its copies stay.
define i64 @add_or_and_i64(ptr %p, i64 %n) {
; CHECK-LABEL: add_or_and_i64:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: r3 = -1
; CHECK-NEXT: r0 = 0
; CHECK-NEXT: r5 = 0
; CHECK-NEXT: r4 = 0
; CHECK-NEXT: .LBB0_1: # %loop
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: r6 = *(u64 *)(r1 + 0)
; CHECK-NEXT: r3 &= r6
; CHECK-NEXT: r4 |= r6
; CHECK-NEXT: r0 += r6
; CHECK-NEXT: r1 += 8
; CHECK-NEXT: r5 += 1
; CHECK-NEXT: if r5 < r2 goto .LBB0_1
; CHECK-NEXT: # %bb.2: # %exit
; CHECK-NEXT: r0 ^= r4
; CHECK-NEXT: r0 ^= r3
; CHECK-NEXT: exit
entry:
br label %loop
loop:
%i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
%add = phi i64 [ 0, %entry ], [ %add.next, %loop ]
%or = phi i64 [ 0, %entry ], [ %or.next, %loop ]
%and = phi i64 [ -1, %entry ], [ %and.next, %loop ]
%a = getelementptr inbounds i64, ptr %p, i64 %i
%v = load i64, ptr %a
%add.next = add i64 %v, %add
%or.next = or i64 %v, %or
%and.next = and i64 %v, %and
%i.next = add i64 %i, 1
%c = icmp ult i64 %i.next, %n
br i1 %c, label %loop, label %exit
exit:
%r0 = xor i64 %add.next, %or.next
%r1 = xor i64 %r0, %and.next
ret i64 %r1
}
define i64 @xor_mul_sub_i64(ptr %p, i64 %n) {
; CHECK-LABEL: xor_mul_sub_i64:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: r3 = 1
; CHECK-NEXT: r0 = 0
; CHECK-NEXT: r4 = 0
; CHECK-NEXT: r5 = 0
; CHECK-NEXT: .LBB1_1: # %loop
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: r6 = r5
; CHECK-NEXT: r7 = *(u64 *)(r1 + 0)
; CHECK-NEXT: r5 = r7
; CHECK-NEXT: r5 -= r6
; CHECK-NEXT: r3 *= r7
; CHECK-NEXT: r0 ^= r7
; CHECK-NEXT: r1 += 8
; CHECK-NEXT: r4 += 1
; CHECK-NEXT: if r4 < r2 goto .LBB1_1
; CHECK-NEXT: # %bb.2: # %exit
; CHECK-NEXT: r0 ^= r3
; CHECK-NEXT: r0 ^= r5
; CHECK-NEXT: exit
entry:
br label %loop
loop:
%i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
%xor = phi i64 [ 0, %entry ], [ %xor.next, %loop ]
%mul = phi i64 [ 1, %entry ], [ %mul.next, %loop ]
%sub = phi i64 [ 0, %entry ], [ %sub.next, %loop ]
%a = getelementptr inbounds i64, ptr %p, i64 %i
%v = load i64, ptr %a
%xor.next = xor i64 %v, %xor
%mul.next = mul i64 %v, %mul
%sub.next = sub i64 %v, %sub
%i.next = add i64 %i, 1
%c = icmp ult i64 %i.next, %n
br i1 %c, label %loop, label %exit
exit:
%r0 = xor i64 %xor.next, %mul.next
%r1 = xor i64 %r0, %sub.next
ret i64 %r1
}
define i32 @add_or_and_i32(ptr %p, i64 %n) {
; CHECK-LABEL: add_or_and_i32:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: w3 = -1
; CHECK-NEXT: w0 = 0
; CHECK-NEXT: r4 = 0
; CHECK-NEXT: w5 = 0
; CHECK-NEXT: .LBB2_1: # %loop
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: w6 = *(u32 *)(r1 + 0)
; CHECK-NEXT: w3 &= w6
; CHECK-NEXT: w5 |= w6
; CHECK-NEXT: w0 += w6
; CHECK-NEXT: r1 += 4
; CHECK-NEXT: r4 += 1
; CHECK-NEXT: if r4 < r2 goto .LBB2_1
; CHECK-NEXT: # %bb.2: # %exit
; CHECK-NEXT: w0 ^= w5
; CHECK-NEXT: w0 ^= w3
; CHECK-NEXT: exit
entry:
br label %loop
loop:
%i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
%add = phi i32 [ 0, %entry ], [ %add.next, %loop ]
%or = phi i32 [ 0, %entry ], [ %or.next, %loop ]
%and = phi i32 [ -1, %entry ], [ %and.next, %loop ]
%a = getelementptr inbounds i32, ptr %p, i64 %i
%v = load i32, ptr %a
%add.next = add i32 %v, %add
%or.next = or i32 %v, %or
%and.next = and i32 %v, %and
%i.next = add i64 %i, 1
%c = icmp ult i64 %i.next, %n
br i1 %c, label %loop, label %exit
exit:
%r0 = xor i32 %add.next, %or.next
%r1 = xor i32 %r0, %and.next
ret i32 %r1
}
define i32 @xor_mul_sub_i32(ptr %p, i64 %n) {
; CHECK-LABEL: xor_mul_sub_i32:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: w3 = 1
; CHECK-NEXT: w0 = 0
; CHECK-NEXT: r4 = 0
; CHECK-NEXT: w5 = 0
; CHECK-NEXT: .LBB3_1: # %loop
; CHECK-NEXT: # =>This Inner Loop Header: Depth=1
; CHECK-NEXT: w6 = w5
; CHECK-NEXT: w7 = *(u32 *)(r1 + 0)
; CHECK-NEXT: w5 = w7
; CHECK-NEXT: w5 -= w6
; CHECK-NEXT: w3 *= w7
; CHECK-NEXT: w0 ^= w7
; CHECK-NEXT: r1 += 4
; CHECK-NEXT: r4 += 1
; CHECK-NEXT: if r4 < r2 goto .LBB3_1
; CHECK-NEXT: # %bb.2: # %exit
; CHECK-NEXT: w0 ^= w3
; CHECK-NEXT: w0 ^= w5
; CHECK-NEXT: exit
entry:
br label %loop
loop:
%i = phi i64 [ 0, %entry ], [ %i.next, %loop ]
%xor = phi i32 [ 0, %entry ], [ %xor.next, %loop ]
%mul = phi i32 [ 1, %entry ], [ %mul.next, %loop ]
%sub = phi i32 [ 0, %entry ], [ %sub.next, %loop ]
%a = getelementptr inbounds i32, ptr %p, i64 %i
%v = load i32, ptr %a
%xor.next = xor i32 %v, %xor
%mul.next = mul i32 %v, %mul
%sub.next = sub i32 %v, %sub
%i.next = add i64 %i, 1
%c = icmp ult i64 %i.next, %n
br i1 %c, label %loop, label %exit
exit:
%r0 = xor i32 %xor.next, %mul.next
%r1 = xor i32 %r0, %sub.next
ret i32 %r1
}