; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 ; RUN: llc -mtriple=riscv64 < %s | FileCheck %s define i1 @sink_li(ptr %text, ptr %text.addr.0) nounwind { ; CHECK-LABEL: sink_li: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: addi sp, sp, -32 ; CHECK-NEXT: sd ra, 24(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 16(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s1, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s2, 0(sp) # 8-byte Folded Spill ; CHECK-NEXT: mv s1, a1 ; CHECK-NEXT: mv s0, a0 ; CHECK-NEXT: call toupper ; CHECK-NEXT: li a1, 0 ; CHECK-NEXT: beqz s0, .LBB0_25 ; CHECK-NEXT: .LBB0_1: # %while.body ; CHECK-NEXT: # =>This Inner Loop Header: Depth=1 ; CHECK-NEXT: j .LBB0_3 ; CHECK-NEXT: # %bb.2: # %while.body ; CHECK-NEXT: j .LBB0_15 ; CHECK-NEXT: .LBB0_3: # %while.body.1 ; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1 ; CHECK-NEXT: j .LBB0_5 ; CHECK-NEXT: # %bb.4: # %while.body.1 ; CHECK-NEXT: j .LBB0_16 ; CHECK-NEXT: .LBB0_5: # %while.body.3 ; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1 ; CHECK-NEXT: j .LBB0_7 ; CHECK-NEXT: # %bb.6: # %while.body.3 ; CHECK-NEXT: j .LBB0_18 ; CHECK-NEXT: .LBB0_7: # %while.body.4 ; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1 ; CHECK-NEXT: j .LBB0_9 ; CHECK-NEXT: # %bb.8: # %while.body.4 ; CHECK-NEXT: j .LBB0_20 ; CHECK-NEXT: .LBB0_9: # %while.body.5 ; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1 ; CHECK-NEXT: j .LBB0_11 ; CHECK-NEXT: # %bb.10: # %while.body.5 ; CHECK-NEXT: j .LBB0_22 ; CHECK-NEXT: .LBB0_11: # %while.body.6 ; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1 ; CHECK-NEXT: j .LBB0_1 ; CHECK-NEXT: # %bb.12: # %while.body.6 ; CHECK-NEXT: # %bb.13: # %while.body.6 ; CHECK-NEXT: # %bb.14: # %strdup.exit.split.loop.exit126 ; CHECK-NEXT: addi s0, s1, 7 ; CHECK-NEXT: j .LBB0_24 ; CHECK-NEXT: .LBB0_15: # %while.body ; CHECK-NEXT: j .LBB0_17 ; CHECK-NEXT: .LBB0_16: # %while.body.1 ; CHECK-NEXT: .LBB0_17: # %strdup.exit.loopexit ; CHECK-NEXT: li s0, 0 ; CHECK-NEXT: j .LBB0_24 ; CHECK-NEXT: .LBB0_18: # %while.body.3 ; CHECK-NEXT: # %bb.19: # %strdup.exit.split.loop.exit120 ; CHECK-NEXT: addi s0, s1, 4 ; CHECK-NEXT: j .LBB0_24 ; CHECK-NEXT: .LBB0_20: # %while.body.4 ; CHECK-NEXT: # %bb.21: # %strdup.exit.split.loop.exit122 ; CHECK-NEXT: addi s0, s1, 5 ; CHECK-NEXT: j .LBB0_24 ; CHECK-NEXT: .LBB0_22: # %while.body.5 ; CHECK-NEXT: j .LBB0_24 ; CHECK-NEXT: # %bb.23: ; CHECK-NEXT: li a1, 0 ; CHECK-NEXT: j .LBB0_25 ; CHECK-NEXT: .LBB0_24: # %strdup.exit ; CHECK-NEXT: li s1, 0 ; CHECK-NEXT: mv s2, a0 ; CHECK-NEXT: li a0, 0 ; CHECK-NEXT: mv a1, s0 ; CHECK-NEXT: jalr s1 ; CHECK-NEXT: li a0, 0 ; CHECK-NEXT: mv a1, s2 ; CHECK-NEXT: li a2, 0 ; CHECK-NEXT: jalr s1 ; CHECK-NEXT: li a1, 1 ; CHECK-NEXT: .LBB0_25: # %return ; CHECK-NEXT: mv a0, a1 ; CHECK-NEXT: ld ra, 24(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 16(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s1, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s2, 0(sp) # 8-byte Folded Reload ; CHECK-NEXT: addi sp, sp, 32 ; CHECK-NEXT: ret entry: %call = call i32 @toupper() %tobool.not = icmp eq ptr %text, null br i1 %tobool.not, label %return, label %while.body while.body: ; preds = %while.body.6, %while.body.6, %entry switch i8 1, label %strdup.exit.split.loop.exit114 [ i8 1, label %while.body.1 i8 9, label %while.body.1 i8 0, label %return ] while.body.1: ; preds = %while.body, %while.body switch i8 1, label %strdup.exit [ i8 1, label %while.body.3 i8 9, label %while.body.3 i8 0, label %return ] while.body.3: ; preds = %while.body.1, %while.body.1 switch i8 1, label %strdup.exit.split.loop.exit120 [ i8 32, label %while.body.4 i8 1, label %while.body.4 i8 0, label %return ] while.body.4: ; preds = %while.body.3, %while.body.3 switch i8 1, label %strdup.exit.split.loop.exit122 [ i8 32, label %while.body.5 i8 1, label %while.body.5 i8 0, label %return ] while.body.5: ; preds = %while.body.4, %while.body.4 switch i8 1, label %strdup.exit.split.loop.exit124 [ i8 1, label %while.body.6 i8 9, label %while.body.6 i8 0, label %return ] while.body.6: ; preds = %while.body.5, %while.body.5 switch i8 1, label %strdup.exit.split.loop.exit126 [ i8 1, label %while.body i8 9, label %while.body i8 0, label %return ] strdup.exit.split.loop.exit114: ; preds = %while.body br label %strdup.exit strdup.exit.split.loop.exit120: ; preds = %while.body.3 %incdec.ptr.3.le = getelementptr i8, ptr %text.addr.0, i64 4 br label %strdup.exit strdup.exit.split.loop.exit122: ; preds = %while.body.4 %incdec.ptr.4.le = getelementptr i8, ptr %text.addr.0, i64 5 br label %strdup.exit strdup.exit.split.loop.exit124: ; preds = %while.body.5 br label %strdup.exit strdup.exit.split.loop.exit126: ; preds = %while.body.6 %incdec.ptr.6.le = getelementptr i8, ptr %text.addr.0, i64 7 br label %strdup.exit strdup.exit: ; preds = %strdup.exit.split.loop.exit126, %strdup.exit.split.loop.exit124, %strdup.exit.split.loop.exit122, %strdup.exit.split.loop.exit120, %strdup.exit.split.loop.exit114, %while.body.1 %text.addr.0.lcssa = phi ptr [ null, %strdup.exit.split.loop.exit114 ], [ %incdec.ptr.3.le, %strdup.exit.split.loop.exit120 ], [ %incdec.ptr.4.le, %strdup.exit.split.loop.exit122 ], [ %text, %strdup.exit.split.loop.exit124 ], [ %incdec.ptr.6.le, %strdup.exit.split.loop.exit126 ], [ null, %while.body.1 ] %call5.i = tail call ptr null(ptr null, ptr %text.addr.0.lcssa) %memchr64 = tail call ptr null(ptr null, i32 %call, i64 0) br label %return return: ; preds = %strdup.exit, %while.body.6, %while.body.5, %while.body.4, %while.body.3, %while.body.1, %while.body, %entry %retval.1 = phi i1 [ false, %entry ], [ true, %strdup.exit ], [ false, %while.body ], [ false, %while.body.1 ], [ false, %while.body.3 ], [ false, %while.body.4 ], [ false, %while.body.5 ], [ false, %while.body.6 ] ret i1 %retval.1 } declare i32 @toupper() ; In this example, %arg and the return value (13) have overlapping live ; intervals because the ABI mandidates they both be placed in a0. define signext i32 @overlap_live_ranges(ptr %arg, i32 signext %arg1) { ; CHECK-LABEL: overlap_live_ranges: ; CHECK: # %bb.0: # %bb ; CHECK-NEXT: li a2, 1 ; CHECK-NEXT: bne a1, a2, .LBB1_2 ; CHECK-NEXT: # %bb.1: # %bb2 ; CHECK-NEXT: lw a0, 4(a0) ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB1_2: ; CHECK-NEXT: li a0, 13 ; CHECK-NEXT: ret bb: %i = icmp eq i32 %arg1, 1 br i1 %i, label %bb2, label %bb5 bb2: ; preds = %bb %i3 = getelementptr inbounds nuw i8, ptr %arg, i64 4 %i4 = load i32, ptr %i3, align 4 br label %bb5 bb5: ; preds = %bb2, %bb %i6 = phi i32 [ %i4, %bb2 ], [ 13, %bb ] ret i32 %i6 } ; For switches, the values feeding the phi are always sunk into the ; target blocks as the IR syntax requires the intermediate block and ; DAG lowers it in the immediate predecessor of the phi. define signext i32 @switch_dispatch(i8 %a) { ; CHECK-LABEL: switch_dispatch: ; CHECK: # %bb.0: # %bb ; CHECK-NEXT: addi sp, sp, -16 ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 0(sp) # 8-byte Folded Spill ; CHECK-NEXT: .cfi_offset ra, -8 ; CHECK-NEXT: .cfi_offset s0, -16 ; CHECK-NEXT: zext.b a0, a0 ; CHECK-NEXT: li a1, 31 ; CHECK-NEXT: blt a1, a0, .LBB2_5 ; CHECK-NEXT: # %bb.1: # %bb ; CHECK-NEXT: beqz a0, .LBB2_10 ; CHECK-NEXT: # %bb.2: # %bb ; CHECK-NEXT: li a1, 12 ; CHECK-NEXT: beq a0, a1, .LBB2_11 ; CHECK-NEXT: # %bb.3: # %bb ; CHECK-NEXT: li a1, 13 ; CHECK-NEXT: bne a0, a1, .LBB2_9 ; CHECK-NEXT: # %bb.4: # %case.4 ; CHECK-NEXT: li s0, 644 ; CHECK-NEXT: j .LBB2_13 ; CHECK-NEXT: .LBB2_5: # %bb ; CHECK-NEXT: li a1, 234 ; CHECK-NEXT: beq a0, a1, .LBB2_9 ; CHECK-NEXT: # %bb.6: # %bb ; CHECK-NEXT: li a1, 70 ; CHECK-NEXT: beq a0, a1, .LBB2_12 ; CHECK-NEXT: # %bb.7: # %bb ; CHECK-NEXT: li a1, 32 ; CHECK-NEXT: bne a0, a1, .LBB2_9 ; CHECK-NEXT: # %bb.8: # %case.0 ; CHECK-NEXT: li s0, 13 ; CHECK-NEXT: j .LBB2_13 ; CHECK-NEXT: .LBB2_9: # %case.default ; CHECK-NEXT: li s0, 23 ; CHECK-NEXT: j .LBB2_13 ; CHECK-NEXT: .LBB2_10: # %case.5 ; CHECK-NEXT: li s0, 54 ; CHECK-NEXT: j .LBB2_13 ; CHECK-NEXT: .LBB2_11: # %case.1 ; CHECK-NEXT: li s0, 53 ; CHECK-NEXT: j .LBB2_13 ; CHECK-NEXT: .LBB2_12: # %case.2 ; CHECK-NEXT: li s0, 33 ; CHECK-NEXT: .LBB2_13: # %merge ; CHECK-NEXT: mv a0, s0 ; CHECK-NEXT: call use ; CHECK-NEXT: mv a0, s0 ; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 0(sp) # 8-byte Folded Reload ; CHECK-NEXT: .cfi_restore ra ; CHECK-NEXT: .cfi_restore s0 ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: .cfi_def_cfa_offset 0 ; CHECK-NEXT: ret bb: switch i8 %a, label %case.default [ i8 32, label %case.0 i8 12, label %case.1 i8 70, label %case.2 i8 -22, label %case.3 i8 13, label %case.4 i8 0, label %case.5 ] case.0: br label %merge case.1: br label %merge case.2: br label %merge case.3: br label %merge case.4: br label %merge case.5: br label %merge case.default: br label %merge merge: %res = phi i32 [ 23, %case.default ], [ 13, %case.0 ], [ 53, %case.1 ], [ 33, %case.2 ], [ 23, %case.3 ], [ 644, %case.4 ], [ 54, %case.5 ] call void @use(i32 %res) ret i32 %res } ; Same as for the switch, but written via manual branching. define signext i32 @branch_dispatch(i8 %a) { ; CHECK-LABEL: branch_dispatch: ; CHECK: # %bb.0: # %case.0 ; CHECK-NEXT: addi sp, sp, -16 ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill ; CHECK-NEXT: sd s0, 0(sp) # 8-byte Folded Spill ; CHECK-NEXT: .cfi_offset ra, -8 ; CHECK-NEXT: .cfi_offset s0, -16 ; CHECK-NEXT: .cfi_remember_state ; CHECK-NEXT: zext.b a0, a0 ; CHECK-NEXT: li a1, 32 ; CHECK-NEXT: beq a0, a1, .LBB3_7 ; CHECK-NEXT: # %bb.1: # %case.1 ; CHECK-NEXT: li a1, 12 ; CHECK-NEXT: beq a0, a1, .LBB3_8 ; CHECK-NEXT: # %bb.2: # %case.2 ; CHECK-NEXT: li a1, 70 ; CHECK-NEXT: beq a0, a1, .LBB3_9 ; CHECK-NEXT: # %bb.3: # %case.3 ; CHECK-NEXT: li a1, 234 ; CHECK-NEXT: li s0, 23 ; CHECK-NEXT: beq a0, a1, .LBB3_10 ; CHECK-NEXT: # %bb.4: # %case.4 ; CHECK-NEXT: beqz a0, .LBB3_11 ; CHECK-NEXT: # %bb.5: # %case.5 ; CHECK-NEXT: li a1, 5 ; CHECK-NEXT: bne a0, a1, .LBB3_10 ; CHECK-NEXT: # %bb.6: ; CHECK-NEXT: li s0, 54 ; CHECK-NEXT: j .LBB3_10 ; CHECK-NEXT: .LBB3_7: ; CHECK-NEXT: li s0, 13 ; CHECK-NEXT: j .LBB3_10 ; CHECK-NEXT: .LBB3_8: ; CHECK-NEXT: li s0, 53 ; CHECK-NEXT: j .LBB3_10 ; CHECK-NEXT: .LBB3_9: ; CHECK-NEXT: li s0, 33 ; CHECK-NEXT: .LBB3_10: # %merge ; CHECK-NEXT: mv a0, s0 ; CHECK-NEXT: call use ; CHECK-NEXT: mv a0, s0 ; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; CHECK-NEXT: ld s0, 0(sp) # 8-byte Folded Reload ; CHECK-NEXT: .cfi_restore ra ; CHECK-NEXT: .cfi_restore s0 ; CHECK-NEXT: addi sp, sp, 16 ; CHECK-NEXT: .cfi_def_cfa_offset 0 ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB3_11: ; CHECK-NEXT: .cfi_restore_state ; CHECK-NEXT: li s0, 644 ; CHECK-NEXT: j .LBB3_10 case.0: %c0 = icmp ne i8 %a, 32 br i1 %c0, label %case.1, label %merge case.1: %c1 = icmp ne i8 %a, 12 br i1 %c1, label %case.2, label %merge case.2: %c2 = icmp ne i8 %a, 70 br i1 %c2, label %case.3, label %merge case.3: %c3 = icmp ne i8 %a, -22 br i1 %c3, label %case.4, label %merge case.4: %c4 = icmp ne i8 %a, 0 br i1 %c4, label %case.5, label %merge case.5: %c5 = icmp ne i8 %a, 5 br i1 %c5, label %case.default, label %merge case.default: br label %merge merge: %res = phi i32 [ 23, %case.default ], [ 13, %case.0 ], [ 53, %case.1 ], [ 33, %case.2 ], [ 23, %case.3 ], [ 644, %case.4 ], [ 54, %case.5 ] call void @use(i32 %res) ret i32 %res } declare void @use(i32)