Home | History | Annotate | Download | only in SystemZ
      1 ; Test 128-bit subtraction in which the second operand is variable.
      2 ;
      3 ; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
      4 ; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s
      5 
      6 declare i128 *@foo()
      7 
      8 ; Test register addition.
      9 define void @f1(i128 *%ptr, i64 %high, i64 %low) {
     10 ; CHECK-LABEL: f1:
     11 ; CHECK: slgr {{%r[0-5]}}, %r4
     12 ; CHECK: slbgr {{%r[0-5]}}, %r3
     13 ; CHECK: br %r14
     14   %a = load i128 , i128 *%ptr
     15   %highx = zext i64 %high to i128
     16   %lowx = zext i64 %low to i128
     17   %bhigh = shl i128 %highx, 64
     18   %b = or i128 %bhigh, %lowx
     19   %sub = sub i128 %a, %b
     20   store i128 %sub, i128 *%ptr
     21   ret void
     22 }
     23 
     24 ; Test memory addition with no offset.
     25 define void @f2(i64 %addr) {
     26 ; CHECK-LABEL: f2:
     27 ; CHECK: slg {{%r[0-5]}}, 8(%r2)
     28 ; CHECK: slbg {{%r[0-5]}}, 0(%r2)
     29 ; CHECK: br %r14
     30   %bptr = inttoptr i64 %addr to i128 *
     31   %aptr = getelementptr i128, i128 *%bptr, i64 -8
     32   %a = load i128 , i128 *%aptr
     33   %b = load i128 , i128 *%bptr
     34   %sub = sub i128 %a, %b
     35   store i128 %sub, i128 *%aptr
     36   ret void
     37 }
     38 
     39 ; Test the highest aligned offset that is in range of both SLG and SLBG.
     40 define void @f3(i64 %base) {
     41 ; CHECK-LABEL: f3:
     42 ; CHECK: slg {{%r[0-5]}}, 524280(%r2)
     43 ; CHECK: slbg {{%r[0-5]}}, 524272(%r2)
     44 ; CHECK: br %r14
     45   %addr = add i64 %base, 524272
     46   %bptr = inttoptr i64 %addr to i128 *
     47   %aptr = getelementptr i128, i128 *%bptr, i64 -8
     48   %a = load i128 , i128 *%aptr
     49   %b = load i128 , i128 *%bptr
     50   %sub = sub i128 %a, %b
     51   store i128 %sub, i128 *%aptr
     52   ret void
     53 }
     54 
     55 ; Test the next doubleword up, which requires separate address logic for SLG.
     56 define void @f4(i64 %base) {
     57 ; CHECK-LABEL: f4:
     58 ; CHECK: lgr [[BASE:%r[1-5]]], %r2
     59 ; CHECK: agfi [[BASE]], 524288
     60 ; CHECK: slg {{%r[0-5]}}, 0([[BASE]])
     61 ; CHECK: slbg {{%r[0-5]}}, 524280(%r2)
     62 ; CHECK: br %r14
     63   %addr = add i64 %base, 524280
     64   %bptr = inttoptr i64 %addr to i128 *
     65   %aptr = getelementptr i128, i128 *%bptr, i64 -8
     66   %a = load i128 , i128 *%aptr
     67   %b = load i128 , i128 *%bptr
     68   %sub = sub i128 %a, %b
     69   store i128 %sub, i128 *%aptr
     70   ret void
     71 }
     72 
     73 ; Test the next doubleword after that, which requires separate logic for
     74 ; both instructions.  It would be better to create an anchor at 524288
     75 ; that both instructions can use, but that isn't implemented yet.
     76 define void @f5(i64 %base) {
     77 ; CHECK-LABEL: f5:
     78 ; CHECK: slg {{%r[0-5]}}, 0({{%r[1-5]}})
     79 ; CHECK: slbg {{%r[0-5]}}, 0({{%r[1-5]}})
     80 ; CHECK: br %r14
     81   %addr = add i64 %base, 524288
     82   %bptr = inttoptr i64 %addr to i128 *
     83   %aptr = getelementptr i128, i128 *%bptr, i64 -8
     84   %a = load i128 , i128 *%aptr
     85   %b = load i128 , i128 *%bptr
     86   %sub = sub i128 %a, %b
     87   store i128 %sub, i128 *%aptr
     88   ret void
     89 }
     90 
     91 ; Test the lowest displacement that is in range of both SLG and SLBG.
     92 define void @f6(i64 %base) {
     93 ; CHECK-LABEL: f6:
     94 ; CHECK: slg {{%r[0-5]}}, -524280(%r2)
     95 ; CHECK: slbg {{%r[0-5]}}, -524288(%r2)
     96 ; CHECK: br %r14
     97   %addr = add i64 %base, -524288
     98   %bptr = inttoptr i64 %addr to i128 *
     99   %aptr = getelementptr i128, i128 *%bptr, i64 -8
    100   %a = load i128 , i128 *%aptr
    101   %b = load i128 , i128 *%bptr
    102   %sub = sub i128 %a, %b
    103   store i128 %sub, i128 *%aptr
    104   ret void
    105 }
    106 
    107 ; Test the next doubleword down, which is out of range of the SLBG.
    108 define void @f7(i64 %base) {
    109 ; CHECK-LABEL: f7:
    110 ; CHECK: slg {{%r[0-5]}}, -524288(%r2)
    111 ; CHECK: slbg {{%r[0-5]}}, 0({{%r[1-5]}})
    112 ; CHECK: br %r14
    113   %addr = add i64 %base, -524296
    114   %bptr = inttoptr i64 %addr to i128 *
    115   %aptr = getelementptr i128, i128 *%bptr, i64 -8
    116   %a = load i128 , i128 *%aptr
    117   %b = load i128 , i128 *%bptr
    118   %sub = sub i128 %a, %b
    119   store i128 %sub, i128 *%aptr
    120   ret void
    121 }
    122 
    123 ; Check that subtractions of spilled values can use SLG and SLBG rather than
    124 ; SLGR and SLBGR.
    125 define void @f8(i128 *%ptr0) {
    126 ; CHECK-LABEL: f8:
    127 ; CHECK: brasl %r14, foo@PLT
    128 ; CHECK: slg {{%r[0-9]+}}, {{[0-9]+}}(%r15)
    129 ; CHECK: slbg {{%r[0-9]+}}, {{[0-9]+}}(%r15)
    130 ; CHECK: br %r14
    131   %ptr1 = getelementptr i128, i128 *%ptr0, i128 2
    132   %ptr2 = getelementptr i128, i128 *%ptr0, i128 4
    133   %ptr3 = getelementptr i128, i128 *%ptr0, i128 6
    134   %ptr4 = getelementptr i128, i128 *%ptr0, i128 8
    135 
    136   %val0 = load i128 , i128 *%ptr0
    137   %val1 = load i128 , i128 *%ptr1
    138   %val2 = load i128 , i128 *%ptr2
    139   %val3 = load i128 , i128 *%ptr3
    140   %val4 = load i128 , i128 *%ptr4
    141 
    142   %retptr = call i128 *@foo()
    143 
    144   %ret = load i128 , i128 *%retptr
    145   %sub0 = sub i128 %ret, %val0
    146   %sub1 = sub i128 %sub0, %val1
    147   %sub2 = sub i128 %sub1, %val2
    148   %sub3 = sub i128 %sub2, %val3
    149   %sub4 = sub i128 %sub3, %val4
    150   store i128 %sub4, i128 *%retptr
    151 
    152   ret void
    153 }
    154