; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=arm -passes=typepromotion,verify -S %s -o - | FileCheck %s
; Check that the arguments are extended but then nothing else is.
; This also ensures that the pass can handle loops.
define void @phi_feeding_phi_args(i8 %a, i8 %b) {
; CHECK-LABEL: @phi_feeding_phi_args(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[B:%.*]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br i1 [[TMP2]], label [[PREHEADER:%.*]], label [[EMPTY:%.*]]
; CHECK: empty:
; CHECK-NEXT: br label [[PREHEADER]]
; CHECK: preheader:
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[TMP1]], [[EMPTY]] ]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ [[TMP3]], [[PREHEADER]] ], [ [[INC2:%.*]], [[IF_END:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[VAL]], 254
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[INC:%.*]] = sub nuw i32 [[VAL]], 2
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.else:
; CHECK-NEXT: [[INC1:%.*]] = shl nuw i32 [[VAL]], 1
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[INC2]] = phi i32 [ [[INC]], [[IF_THEN]] ], [ [[INC1]], [[IF_ELSE]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[INC2]], 255
; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%0 = icmp ugt i8 %a, %b
br i1 %0, label %preheader, label %empty
empty:
br label %preheader
preheader:
%1 = phi i8 [ %a, %entry ], [ %b, %empty ]
br label %loop
loop:
%val = phi i8 [ %1, %preheader ], [ %inc2, %if.end ]
%cmp = icmp ult i8 %val, 254
br i1 %cmp, label %if.then, label %if.else
if.then:
%inc = sub nuw i8 %val, 2
br label %if.end
if.else:
%inc1 = shl nuw i8 %val, 1
br label %if.end
if.end:
%inc2 = phi i8 [ %inc, %if.then], [ %inc1, %if.else ]
%cmp1 = icmp eq i8 %inc2, 255
br i1 %cmp1, label %exit, label %loop
exit:
ret void
}
; Same as above, but as the args are zeroext, we shouldn't see any uxts.
define void @phi_feeding_phi_zeroext_args(i8 zeroext %a, i8 zeroext %b) {
; CHECK-LABEL: @phi_feeding_phi_zeroext_args(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[A:%.*]] to i32
; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[B:%.*]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br i1 [[TMP2]], label [[PREHEADER:%.*]], label [[EMPTY:%.*]]
; CHECK: empty:
; CHECK-NEXT: br label [[PREHEADER]]
; CHECK: preheader:
; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[TMP1]], [[EMPTY]] ]
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ [[TMP3]], [[PREHEADER]] ], [ [[INC2:%.*]], [[IF_END:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[VAL]], 254
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[INC:%.*]] = sub nuw i32 [[VAL]], 2
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.else:
; CHECK-NEXT: [[INC1:%.*]] = shl nuw i32 [[VAL]], 1
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[INC2]] = phi i32 [ [[INC]], [[IF_THEN]] ], [ [[INC1]], [[IF_ELSE]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[INC2]], 255
; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%0 = icmp ugt i8 %a, %b
br i1 %0, label %preheader, label %empty
empty:
br label %preheader
preheader:
%1 = phi i8 [ %a, %entry ], [ %b, %empty ]
br label %loop
loop:
%val = phi i8 [ %1, %preheader ], [ %inc2, %if.end ]
%cmp = icmp ult i8 %val, 254
br i1 %cmp, label %if.then, label %if.else
if.then:
%inc = sub nuw i8 %val, 2
br label %if.end
if.else:
%inc1 = shl nuw i8 %val, 1
br label %if.end
if.end:
%inc2 = phi i8 [ %inc, %if.then], [ %inc1, %if.else ]
%cmp1 = icmp eq i8 %inc2, 255
br i1 %cmp1, label %exit, label %loop
exit:
ret void
}
; Just check that phis also work with i16s.
define void @phi_i16() {
; CHECK-LABEL: @phi_i16(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[IF_END:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[VAL]], 128
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[INC:%.*]] = add nuw i32 [[VAL]], 2
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.else:
; CHECK-NEXT: [[INC1:%.*]] = add nuw i32 [[VAL]], 1
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[INC2]] = phi i32 [ [[INC]], [[IF_THEN]] ], [ [[INC1]], [[IF_ELSE]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[INC2]], 253
; CHECK-NEXT: br i1 [[CMP1]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%val = phi i16 [ 0, %entry ], [ %inc2, %if.end ]
%cmp = icmp ult i16 %val, 128
br i1 %cmp, label %if.then, label %if.else
if.then:
%inc = add nuw i16 %val, 2
br label %if.end
if.else:
%inc1 = add nuw i16 %val, 1
br label %if.end
if.end:
%inc2 = phi i16 [ %inc, %if.then], [ %inc1, %if.else ]
%cmp1 = icmp ult i16 %inc2, 253
br i1 %cmp1, label %loop, label %exit
exit:
ret void
}
define i8 @ret_i8() {
; CHECK-LABEL: @ret_i8(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[IF_END:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[VAL]], 128
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[INC:%.*]] = add nuw i32 [[VAL]], 2
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.else:
; CHECK-NEXT: [[INC1:%.*]] = add nuw i32 [[VAL]], 1
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[INC2]] = phi i32 [ [[INC]], [[IF_THEN]] ], [ [[INC1]], [[IF_ELSE]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[INC2]], 253
; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: [[TMP0:%.*]] = trunc i32 [[INC2]] to i8
; CHECK-NEXT: ret i8 [[TMP0]]
;
entry:
br label %loop
loop:
%val = phi i8 [ 0, %entry ], [ %inc2, %if.end ]
%cmp = icmp ult i8 %val, 128
br i1 %cmp, label %if.then, label %if.else
if.then:
%inc = add nuw i8 %val, 2
br label %if.end
if.else:
%inc1 = add nuw i8 %val, 1
br label %if.end
if.end:
%inc2 = phi i8 [ %inc, %if.then], [ %inc1, %if.else ]
%cmp1 = icmp ult i8 %inc2, 253
br i1 %cmp1, label %exit, label %loop
exit:
ret i8 %inc2
}
define i16 @phi_multiple_undefs(i16 zeroext %arg) {
; CHECK-LABEL: @phi_multiple_undefs(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC2:%.*]], [[IF_END:%.*]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[VAL]], 128
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[INC:%.*]] = add nuw i32 [[VAL]], 2
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.else:
; CHECK-NEXT: [[INC1:%.*]] = add nuw i32 [[VAL]], 1
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: [[INC2]] = phi i32 [ [[INC]], [[IF_THEN]] ], [ [[INC1]], [[IF_ELSE]] ]
; CHECK-NEXT: [[UNRELATED:%.*]] = phi i16 [ undef, [[IF_THEN]] ], [ [[ARG:%.*]], [[IF_ELSE]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[INC2]], 253
; CHECK-NEXT: br i1 [[CMP1]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret i16 [[UNRELATED]]
;
entry:
br label %loop
loop:
%val = phi i16 [ undef, %entry ], [ %inc2, %if.end ]
%cmp = icmp ult i16 %val, 128
br i1 %cmp, label %if.then, label %if.else
if.then:
%inc = add nuw i16 %val, 2
br label %if.end
if.else:
%inc1 = add nuw i16 %val, 1
br label %if.end
if.end:
%inc2 = phi i16 [ %inc, %if.then], [ %inc1, %if.else ]
%unrelated = phi i16 [ undef, %if.then ], [ %arg, %if.else ]
%cmp1 = icmp ult i16 %inc2, 253
br i1 %cmp1, label %loop, label %exit
exit:
ret i16 %unrelated
}
define i16 @promote_arg_return(i16 zeroext %arg1, i16 zeroext %arg2, ptr %res) {
; CHECK-LABEL: @promote_arg_return(
; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[ARG1:%.*]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[ARG2:%.*]] to i32
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[TMP1]], 15
; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i32 [[ADD]], 3
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[MUL]], [[TMP2]]
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i8
; CHECK-NEXT: store i8 [[CONV]], ptr [[RES:%.*]], align 1
; CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP1]] to i16
; CHECK-NEXT: ret i16 [[TMP3]]
;
%add = add nuw i16 %arg1, 15
%mul = mul nuw nsw i16 %add, 3
%cmp = icmp ult i16 %mul, %arg2
%conv = zext i1 %cmp to i8
store i8 %conv, ptr %res
ret i16 %arg1
}
define i16 @signext_bitcast_phi_select(i16 signext %start, ptr %in) {
; CHECK-LABEL: @signext_bitcast_phi_select(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = zext i16 [[START:%.*]] to i32
; CHECK-NEXT: [[CONST:%.*]] = bitcast i16 -1 to i16
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[SELECT:%.*]], [[IF_ELSE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[IDX]] to i16
; CHECK-NEXT: [[CMP_I:%.*]] = icmp sgt i16 [[TMP1]], [[CONST]]
; CHECK-NEXT: br i1 [[CMP_I]], label [[EXIT:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[IDX_NEXT:%.*]] = getelementptr i16, ptr [[IN:%.*]], i32 [[IDX]]
; CHECK-NEXT: [[LD:%.*]] = load i16, ptr [[IDX_NEXT]], align 2
; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[LD]] to i32
; CHECK-NEXT: [[CMP1_I:%.*]] = icmp eq i32 [[TMP2]], [[IDX]]
; CHECK-NEXT: br i1 [[CMP1_I]], label [[EXIT]], label [[IF_ELSE]]
; CHECK: if.else:
; CHECK-NEXT: [[LOBIT:%.*]] = lshr i32 [[IDX]], 15
; CHECK-NEXT: [[LOBIT_NOT:%.*]] = xor i32 [[LOBIT]], 1
; CHECK-NEXT: [[SELECT]] = add nuw i32 [[LOBIT_NOT]], [[IDX]]
; CHECK-NEXT: br label [[FOR_BODY]]
; CHECK: exit:
; CHECK-NEXT: [[RES:%.*]] = phi i32 [ [[TMP2]], [[IF_THEN]] ], [ 0, [[FOR_BODY]] ]
; CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[RES]] to i16
; CHECK-NEXT: ret i16 [[TMP3]]
;
entry:
%const = bitcast i16 -1 to i16
br label %for.body
for.body:
%idx = phi i16 [ %select, %if.else ], [ %start, %entry ]
%cmp.i = icmp sgt i16 %idx, %const
br i1 %cmp.i, label %exit, label %if.then
if.then:
%idx.next = getelementptr i16, ptr %in, i16 %idx
%ld = load i16, ptr %idx.next, align 2
%cmp1.i = icmp eq i16 %ld, %idx
br i1 %cmp1.i, label %exit, label %if.else
if.else:
%lobit = lshr i16 %idx, 15
%lobit.not = xor i16 %lobit, 1
%select = add nuw i16 %lobit.not, %idx
br label %for.body
exit:
%res = phi i16 [ %ld, %if.then ], [ 0, %for.body ]
ret i16 %res
}