1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=m68k-linux -verify-machineinstrs | FileCheck %s 3 4define zeroext i8 @smul_i8(i8 signext %a, i8 signext %b) nounwind ssp { 5; CHECK-LABEL: smul_i8: 6; CHECK: ; %bb.0: ; %entry 7; CHECK-NEXT: move.b (11,%sp), %d0 8; CHECK-NEXT: and.l #255, %d0 9; CHECK-NEXT: move.b (7,%sp), %d1 10; CHECK-NEXT: and.l #255, %d1 11; CHECK-NEXT: muls %d0, %d1 12; CHECK-NEXT: move.l %d1, %d0 13; CHECK-NEXT: and.l #65535, %d0 14; CHECK-NEXT: and.l #255, %d0 15; CHECK-NEXT: rts 16entry: 17 %smul = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 %b) 18 %cmp = extractvalue { i8, i1 } %smul, 1 19 %smul.result = extractvalue { i8, i1 } %smul, 0 20 %X = select i1 %cmp, i8 42, i8 %smul.result 21 ret i8 %X 22} 23 24define zeroext i8 @smul_i8_no_ovf(i8 signext %a, i8 signext %b) nounwind ssp { 25; CHECK-LABEL: smul_i8_no_ovf: 26; CHECK: ; %bb.0: ; %entry 27; CHECK-NEXT: moveq #42, %d0 28; CHECK-NEXT: rts 29entry: 30 %smul = tail call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %a, i8 %b) 31 %cmp = extractvalue { i8, i1 } %smul, 1 32 %smul.result = extractvalue { i8, i1 } %smul, 0 33 %X = select i1 %cmp, i8 %smul.result, i8 42 34 ret i8 %X 35} 36 37declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8) nounwind readnone 38 39define zeroext i16 @smul_i16(i16 signext %a, i16 signext %b) nounwind ssp { 40; CHECK-LABEL: smul_i16: 41; CHECK: ; %bb.0: ; %entry 42; CHECK-NEXT: move.w (6,%sp), %d0 43; CHECK-NEXT: move.w (10,%sp), %d1 44; CHECK-NEXT: muls %d1, %d0 45; CHECK-NEXT: and.l #65535, %d0 46; CHECK-NEXT: rts 47entry: 48 %smul = tail call { i16, i1 } @llvm.smul.with.overflow.i16(i16 %a, i16 %b) 49 %cmp = extractvalue { i16, i1 } %smul, 1 50 %smul.result = extractvalue { i16, i1 } %smul, 0 51 %X = select i1 %cmp, i16 42, i16 %smul.result 52 ret i16 %X 53} 54 55declare { i16, i1 } @llvm.smul.with.overflow.i16(i16, i16) nounwind readnone 56 57declare i32 @printf(ptr, ...) nounwind 58declare {i32, i1} @llvm.smul.with.overflow.i32(i32, i32) 59 60@ok = internal constant [4 x i8] c"%d\0A\00" 61@no = internal constant [4 x i8] c"no\0A\00" 62 63define fastcc i1 @test1(i32 %v1, i32 %v2) nounwind { 64; CHECK-LABEL: test1: 65; CHECK: ; %bb.0: ; %entry 66; CHECK-NEXT: suba.l #12, %sp 67; CHECK-NEXT: muls.l %d1, %d0 68; CHECK-NEXT: bvc .LBB3_1 69; CHECK-NEXT: ; %bb.2: ; %overflow 70; CHECK-NEXT: lea (no,%pc), %a0 71; CHECK-NEXT: move.l %a0, (%sp) 72; CHECK-NEXT: jsr printf 73; CHECK-NEXT: moveq #0, %d0 74; CHECK-NEXT: adda.l #12, %sp 75; CHECK-NEXT: rts 76; CHECK-NEXT: .LBB3_1: ; %normal 77; CHECK-NEXT: move.l %d0, (4,%sp) 78; CHECK-NEXT: lea (ok,%pc), %a0 79; CHECK-NEXT: move.l %a0, (%sp) 80; CHECK-NEXT: jsr printf 81; CHECK-NEXT: moveq #1, %d0 82; CHECK-NEXT: adda.l #12, %sp 83; CHECK-NEXT: rts 84entry: 85 %t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2) 86 %sum = extractvalue {i32, i1} %t, 0 87 %obit = extractvalue {i32, i1} %t, 1 88 br i1 %obit, label %overflow, label %normal 89 90normal: 91 %t1 = tail call i32 (ptr, ...) @printf( ptr @ok, i32 %sum ) nounwind 92 ret i1 true 93 94overflow: 95 %t2 = tail call i32 (ptr, ...) @printf( ptr @no ) nounwind 96 ret i1 false 97} 98 99define fastcc i1 @test2(i32 %v1, i32 %v2) nounwind { 100; CHECK-LABEL: test2: 101; CHECK: ; %bb.0: ; %entry 102; CHECK-NEXT: suba.l #12, %sp 103; CHECK-NEXT: muls.l %d1, %d0 104; CHECK-NEXT: svs %d1 105; CHECK-NEXT: sub.b #1, %d1 106; CHECK-NEXT: bne .LBB4_2 107; CHECK-NEXT: ; %bb.1: ; %overflow 108; CHECK-NEXT: lea (no,%pc), %a0 109; CHECK-NEXT: move.l %a0, (%sp) 110; CHECK-NEXT: jsr printf 111; CHECK-NEXT: moveq #0, %d0 112; CHECK-NEXT: adda.l #12, %sp 113; CHECK-NEXT: rts 114; CHECK-NEXT: .LBB4_2: ; %normal 115; CHECK-NEXT: move.l %d0, (4,%sp) 116; CHECK-NEXT: lea (ok,%pc), %a0 117; CHECK-NEXT: move.l %a0, (%sp) 118; CHECK-NEXT: jsr printf 119; CHECK-NEXT: moveq #1, %d0 120; CHECK-NEXT: adda.l #12, %sp 121; CHECK-NEXT: rts 122entry: 123 %t = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %v1, i32 %v2) 124 %sum = extractvalue {i32, i1} %t, 0 125 %obit = extractvalue {i32, i1} %t, 1 126 br i1 %obit, label %overflow, label %normal 127 128overflow: 129 %t2 = tail call i32 (ptr, ...) @printf( ptr @no ) nounwind 130 ret i1 false 131 132normal: 133 %t1 = tail call i32 (ptr, ...) @printf( ptr @ok, i32 %sum ) nounwind 134 ret i1 true 135} 136 137define i32 @test3(i32 %a, i32 %b) nounwind readnone { 138; CHECK-LABEL: test3: 139; CHECK: ; %bb.0: ; %entry 140; CHECK-NEXT: move.l (8,%sp), %d0 141; CHECK-NEXT: add.l (4,%sp), %d0 142; CHECK-NEXT: add.l %d0, %d0 143; CHECK-NEXT: rts 144entry: 145 %tmp0 = add i32 %b, %a 146 %tmp1 = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %tmp0, i32 2) 147 %tmp2 = extractvalue { i32, i1 } %tmp1, 0 148 ret i32 %tmp2 149} 150 151; Same as umul-with-overflow, we shouldn't fallback to 152; builtin here 153define i32 @test4(i32 %a, i32 %b) nounwind readnone { 154; CHECK-LABEL: test4: 155; CHECK: ; %bb.0: ; %entry 156; CHECK-NEXT: move.l (8,%sp), %d0 157; CHECK-NEXT: add.l (4,%sp), %d0 158; CHECK-NEXT: moveq #4, %d1 159; CHECK-NEXT: muls.l %d1, %d0 160; CHECK-NEXT: rts 161entry: 162 %tmp0 = add i32 %b, %a 163 %tmp1 = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %tmp0, i32 4) 164 %tmp2 = extractvalue { i32, i1 } %tmp1, 0 165 ret i32 %tmp2 166} 167