| ; Test insertions of i32s into the low half of an i64. |
| ; |
| ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s |
| |
| ; Insertion of an i32 can be done using LR. |
| define i64 @f1(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f1: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %low = zext i32 %b to i64 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %high, %low |
| ret i64 %res |
| } |
| |
| ; ... and again with the operands reversed. |
| define i64 @f2(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f2: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %low = zext i32 %b to i64 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %low, %high |
| ret i64 %res |
| } |
| |
| ; Like f1, but with "in register" zero extension. |
| define i64 @f3(i64 %a, i64 %b) { |
| ; CHECK-LABEL: f3: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %low = and i64 %b, 4294967295 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %high, %low |
| ret i64 %res |
| } |
| |
| ; ... and again with the operands reversed. |
| define i64 @f4(i64 %a, i64 %b) { |
| ; CHECK-LABEL: f4: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %low = and i64 %b, 4294967295 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %low, %high |
| ret i64 %res |
| } |
| |
| ; Unary operations can be done directly into the low half. |
| define i64 @f5(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f5: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lcr %r2, %r3 |
| ; CHECK: br %r14 |
| %neg = sub i32 0, %b |
| %low = zext i32 %neg to i64 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %high, %low |
| ret i64 %res |
| } |
| |
| ; ...likewise three-operand binary operations like RLL. |
| define i64 @f6(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f6: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: rll %r2, %r3, 1 |
| ; CHECK: br %r14 |
| %parta = shl i32 %b, 1 |
| %partb = lshr i32 %b, 31 |
| %rot = or i32 %parta, %partb |
| %low = zext i32 %rot to i64 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %low, %high |
| ret i64 %res |
| } |
| |
| ; Loads can be done directly into the low half. The range of L is checked |
| ; in the move tests. |
| define i64 @f7(i64 %a, i32 *%src) { |
| ; CHECK-LABEL: f7: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: l %r2, 0(%r3) |
| ; CHECK: br %r14 |
| %b = load i32, i32 *%src |
| %low = zext i32 %b to i64 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %high, %low |
| ret i64 %res |
| } |
| |
| ; ...likewise extending loads. |
| define i64 @f8(i64 %a, i8 *%src) { |
| ; CHECK-LABEL: f8: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lb %r2, 0(%r3) |
| ; CHECK: br %r14 |
| %byte = load i8, i8 *%src |
| %b = sext i8 %byte to i32 |
| %low = zext i32 %b to i64 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %high, %low |
| ret i64 %res |
| } |
| |
| ; Check a case like f1 in which there is no AND. We simply know from context |
| ; that the upper half of one OR operand and the lower half of the other are |
| ; both clear. |
| define i64 @f9(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f9: |
| ; CHECK: sllg %r2, %r2, 32 |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %shift = shl i64 %a, 32 |
| %low = zext i32 %b to i64 |
| %or = or i64 %shift, %low |
| ret i64 %or |
| } |
| |
| ; ...and again with the operands reversed. |
| define i64 @f10(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f10: |
| ; CHECK: sllg %r2, %r2, 32 |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %shift = shl i64 %a, 32 |
| %low = zext i32 %b to i64 |
| %or = or i64 %low, %shift |
| ret i64 %or |
| } |
| |
| ; Like f9, but with "in register" zero extension. |
| define i64 @f11(i64 %a, i64 %b) { |
| ; CHECK-LABEL: f11: |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %shift = shl i64 %a, 32 |
| %low = and i64 %b, 4294967295 |
| %or = or i64 %shift, %low |
| ret i64 %or |
| } |
| |
| ; ...and again with the operands reversed. |
| define i64 @f12(i64 %a, i64 %b) { |
| ; CHECK-LABEL: f12: |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %shift = shl i64 %a, 32 |
| %low = and i64 %b, 4294967295 |
| %or = or i64 %low, %shift |
| ret i64 %or |
| } |
| |
| ; Like f9, but for larger shifts than 32. |
| define i64 @f13(i64 %a, i32 %b) { |
| ; CHECK-LABEL: f13: |
| ; CHECK: sllg %r2, %r2, 60 |
| ; CHECK: lr %r2, %r3 |
| ; CHECK: br %r14 |
| %shift = shl i64 %a, 60 |
| %low = zext i32 %b to i64 |
| %or = or i64 %shift, %low |
| ret i64 %or |
| } |
| |
| ; We previously wrongly removed the upper AND as dead. |
| define i64 @f14(i64 %a, i64 %b) { |
| ; CHECK-LABEL: f14: |
| ; CHECK: risbg {{%r[0-5]}}, %r2, 6, 134, 0 |
| ; CHECK: br %r14 |
| %and1 = and i64 %a, 144115188075855872 |
| %and2 = and i64 %b, 15 |
| %or = or i64 %and1, %and2 |
| %res = icmp eq i64 %or, 0 |
| %ext = sext i1 %res to i64 |
| ret i64 %ext |
| } |
| |
| ; Check another representation of f8. |
| define i64 @f15(i64 %a, i8 *%src) { |
| ; CHECK-LABEL: f15: |
| ; CHECK-NOT: {{%r[23]}} |
| ; CHECK: lb %r2, 0(%r3) |
| ; CHECK: br %r14 |
| %byte = load i8, i8 *%src |
| %b = sext i8 %byte to i64 |
| %low = and i64 %b, 4294967295 |
| %high = and i64 %a, -4294967296 |
| %res = or i64 %high, %low |
| ret i64 %res |
| } |