1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=thumbv6m-none-unknown-eabi -mcpu=cortex-m0 | FileCheck %s --check-prefix=ARM 3 4declare i4 @llvm.umul.fix.sat.i4 (i4, i4, i32) 5declare i32 @llvm.umul.fix.sat.i32 (i32, i32, i32) 6declare i64 @llvm.umul.fix.sat.i64 (i64, i64, i32) 7 8define i32 @func(i32 %x, i32 %y) nounwind { 9; ARM-LABEL: func: 10; ARM: @ %bb.0: 11; ARM-NEXT: .save {r4, lr} 12; ARM-NEXT: push {r4, lr} 13; ARM-NEXT: mov r2, r1 14; ARM-NEXT: movs r4, #0 15; ARM-NEXT: mov r1, r4 16; ARM-NEXT: mov r3, r4 17; ARM-NEXT: bl __aeabi_lmul 18; ARM-NEXT: cmp r1, #3 19; ARM-NEXT: bhi .LBB0_2 20; ARM-NEXT: @ %bb.1: 21; ARM-NEXT: lsrs r0, r0, #2 22; ARM-NEXT: lsls r1, r1, #30 23; ARM-NEXT: adds r0, r1, r0 24; ARM-NEXT: pop {r4, pc} 25; ARM-NEXT: .LBB0_2: 26; ARM-NEXT: mvns r0, r4 27; ARM-NEXT: pop {r4, pc} 28 %tmp = call i32 @llvm.umul.fix.sat.i32(i32 %x, i32 %y, i32 2) 29 ret i32 %tmp 30} 31 32define i64 @func2(i64 %x, i64 %y) nounwind { 33; ARM-LABEL: func2: 34; ARM: @ %bb.0: 35; ARM-NEXT: .save {r4, r5, r6, r7, lr} 36; ARM-NEXT: push {r4, r5, r6, r7, lr} 37; ARM-NEXT: .pad #20 38; ARM-NEXT: sub sp, #20 39; ARM-NEXT: str r3, [sp, #12] @ 4-byte Spill 40; ARM-NEXT: mov r6, r2 41; ARM-NEXT: mov r7, r1 42; ARM-NEXT: str r1, [sp, #8] @ 4-byte Spill 43; ARM-NEXT: mov r5, r0 44; ARM-NEXT: movs r4, #0 45; ARM-NEXT: mov r1, r4 46; ARM-NEXT: mov r3, r4 47; ARM-NEXT: bl __aeabi_lmul 48; ARM-NEXT: str r0, [sp, #16] @ 4-byte Spill 49; ARM-NEXT: str r1, [sp, #4] @ 4-byte Spill 50; ARM-NEXT: mov r0, r7 51; ARM-NEXT: mov r1, r4 52; ARM-NEXT: mov r2, r6 53; ARM-NEXT: mov r3, r4 54; ARM-NEXT: bl __aeabi_lmul 55; ARM-NEXT: mov r6, r1 56; ARM-NEXT: ldr r1, [sp, #4] @ 4-byte Reload 57; ARM-NEXT: adds r7, r0, r1 58; ARM-NEXT: adcs r6, r4 59; ARM-NEXT: mov r0, r5 60; ARM-NEXT: mov r1, r4 61; ARM-NEXT: ldr r5, [sp, #12] @ 4-byte Reload 62; ARM-NEXT: mov r2, r5 63; ARM-NEXT: mov r3, r4 64; ARM-NEXT: bl __aeabi_lmul 65; ARM-NEXT: adds r0, r0, r7 66; ARM-NEXT: str r0, [sp, #4] @ 4-byte Spill 67; ARM-NEXT: adcs r1, r4 68; ARM-NEXT: adds r6, r6, r1 69; ARM-NEXT: mov r7, r4 70; ARM-NEXT: adcs r7, r4 71; ARM-NEXT: ldr r0, [sp, #8] @ 4-byte Reload 72; ARM-NEXT: mov r1, r4 73; ARM-NEXT: mov r2, r5 74; ARM-NEXT: mov r3, r4 75; ARM-NEXT: bl __aeabi_lmul 76; ARM-NEXT: adds r0, r0, r6 77; ARM-NEXT: adcs r1, r7 78; ARM-NEXT: lsrs r6, r0, #2 79; ARM-NEXT: orrs r6, r1 80; ARM-NEXT: lsls r0, r0, #30 81; ARM-NEXT: ldr r3, [sp, #4] @ 4-byte Reload 82; ARM-NEXT: lsrs r1, r3, #2 83; ARM-NEXT: adds r2, r0, r1 84; ARM-NEXT: lsls r0, r3, #30 85; ARM-NEXT: ldr r1, [sp, #16] @ 4-byte Reload 86; ARM-NEXT: lsrs r1, r1, #2 87; ARM-NEXT: adds r3, r0, r1 88; ARM-NEXT: mvns r1, r4 89; ARM-NEXT: cmp r6, #0 90; ARM-NEXT: mov r0, r1 91; ARM-NEXT: beq .LBB1_3 92; ARM-NEXT: @ %bb.1: 93; ARM-NEXT: beq .LBB1_4 94; ARM-NEXT: .LBB1_2: 95; ARM-NEXT: add sp, #20 96; ARM-NEXT: pop {r4, r5, r6, r7, pc} 97; ARM-NEXT: .LBB1_3: 98; ARM-NEXT: mov r0, r3 99; ARM-NEXT: bne .LBB1_2 100; ARM-NEXT: .LBB1_4: 101; ARM-NEXT: mov r1, r2 102; ARM-NEXT: add sp, #20 103; ARM-NEXT: pop {r4, r5, r6, r7, pc} 104 %tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 2) 105 ret i64 %tmp 106} 107 108define i4 @func3(i4 %x, i4 %y) nounwind { 109; ARM-LABEL: func3: 110; ARM: @ %bb.0: 111; ARM-NEXT: .save {r4, lr} 112; ARM-NEXT: push {r4, lr} 113; ARM-NEXT: movs r2, #15 114; ARM-NEXT: ands r2, r1 115; ARM-NEXT: lsls r0, r0, #28 116; ARM-NEXT: movs r4, #0 117; ARM-NEXT: mov r1, r4 118; ARM-NEXT: mov r3, r4 119; ARM-NEXT: bl __aeabi_lmul 120; ARM-NEXT: cmp r1, #3 121; ARM-NEXT: bhi .LBB2_2 122; ARM-NEXT: @ %bb.1: 123; ARM-NEXT: lsrs r0, r0, #2 124; ARM-NEXT: lsls r1, r1, #30 125; ARM-NEXT: adds r0, r1, r0 126; ARM-NEXT: lsrs r0, r0, #28 127; ARM-NEXT: pop {r4, pc} 128; ARM-NEXT: .LBB2_2: 129; ARM-NEXT: mvns r0, r4 130; ARM-NEXT: lsrs r0, r0, #28 131; ARM-NEXT: pop {r4, pc} 132 %tmp = call i4 @llvm.umul.fix.sat.i4(i4 %x, i4 %y, i32 2) 133 ret i4 %tmp 134} 135 136;; These result in regular integer multiplication with a saturation check. 137define i32 @func4(i32 %x, i32 %y) nounwind { 138; ARM-LABEL: func4: 139; ARM: @ %bb.0: 140; ARM-NEXT: .save {r4, lr} 141; ARM-NEXT: push {r4, lr} 142; ARM-NEXT: mov r2, r1 143; ARM-NEXT: movs r4, #0 144; ARM-NEXT: mov r1, r4 145; ARM-NEXT: mov r3, r4 146; ARM-NEXT: bl __aeabi_lmul 147; ARM-NEXT: cmp r1, #0 148; ARM-NEXT: bls .LBB3_2 149; ARM-NEXT: @ %bb.1: 150; ARM-NEXT: mvns r0, r4 151; ARM-NEXT: .LBB3_2: 152; ARM-NEXT: pop {r4, pc} 153 %tmp = call i32 @llvm.umul.fix.sat.i32(i32 %x, i32 %y, i32 0) 154 ret i32 %tmp 155} 156 157define i64 @func5(i64 %x, i64 %y) { 158; ARM-LABEL: func5: 159; ARM: @ %bb.0: 160; ARM-NEXT: .save {r4, r5, r6, r7, lr} 161; ARM-NEXT: push {r4, r5, r6, r7, lr} 162; ARM-NEXT: .pad #12 163; ARM-NEXT: sub sp, #12 164; ARM-NEXT: mov r6, r3 165; ARM-NEXT: str r2, [sp, #8] @ 4-byte Spill 166; ARM-NEXT: mov r4, r1 167; ARM-NEXT: mov r2, r0 168; ARM-NEXT: str r0, [sp, #4] @ 4-byte Spill 169; ARM-NEXT: movs r5, #0 170; ARM-NEXT: mov r0, r3 171; ARM-NEXT: mov r1, r5 172; ARM-NEXT: mov r3, r5 173; ARM-NEXT: bl __aeabi_lmul 174; ARM-NEXT: str r0, [sp] @ 4-byte Spill 175; ARM-NEXT: mov r7, r1 176; ARM-NEXT: subs r0, r1, #1 177; ARM-NEXT: sbcs r7, r0 178; ARM-NEXT: mov r0, r4 179; ARM-NEXT: mov r1, r5 180; ARM-NEXT: ldr r2, [sp, #8] @ 4-byte Reload 181; ARM-NEXT: mov r3, r5 182; ARM-NEXT: bl __aeabi_lmul 183; ARM-NEXT: subs r2, r1, #1 184; ARM-NEXT: sbcs r1, r2 185; ARM-NEXT: subs r2, r6, #1 186; ARM-NEXT: sbcs r6, r2 187; ARM-NEXT: subs r2, r4, #1 188; ARM-NEXT: sbcs r4, r2 189; ARM-NEXT: ands r4, r6 190; ARM-NEXT: orrs r4, r1 191; ARM-NEXT: orrs r4, r7 192; ARM-NEXT: ldr r1, [sp] @ 4-byte Reload 193; ARM-NEXT: adds r6, r0, r1 194; ARM-NEXT: ldr r0, [sp, #4] @ 4-byte Reload 195; ARM-NEXT: mov r1, r5 196; ARM-NEXT: ldr r2, [sp, #8] @ 4-byte Reload 197; ARM-NEXT: mov r3, r5 198; ARM-NEXT: bl __aeabi_lmul 199; ARM-NEXT: adds r3, r1, r6 200; ARM-NEXT: mov r2, r5 201; ARM-NEXT: adcs r2, r5 202; ARM-NEXT: orrs r2, r4 203; ARM-NEXT: mvns r1, r5 204; ARM-NEXT: cmp r2, #0 205; ARM-NEXT: mov r2, r1 206; ARM-NEXT: bne .LBB4_2 207; ARM-NEXT: @ %bb.1: 208; ARM-NEXT: mov r2, r0 209; ARM-NEXT: .LBB4_2: 210; ARM-NEXT: bne .LBB4_4 211; ARM-NEXT: @ %bb.3: 212; ARM-NEXT: mov r1, r3 213; ARM-NEXT: .LBB4_4: 214; ARM-NEXT: mov r0, r2 215; ARM-NEXT: add sp, #12 216; ARM-NEXT: pop {r4, r5, r6, r7, pc} 217 %tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 0) 218 ret i64 %tmp 219} 220 221define i4 @func6(i4 %x, i4 %y) nounwind { 222; ARM-LABEL: func6: 223; ARM: @ %bb.0: 224; ARM-NEXT: .save {r4, lr} 225; ARM-NEXT: push {r4, lr} 226; ARM-NEXT: movs r2, #15 227; ARM-NEXT: ands r2, r1 228; ARM-NEXT: lsls r0, r0, #28 229; ARM-NEXT: movs r4, #0 230; ARM-NEXT: mov r1, r4 231; ARM-NEXT: mov r3, r4 232; ARM-NEXT: bl __aeabi_lmul 233; ARM-NEXT: cmp r1, #0 234; ARM-NEXT: bls .LBB5_2 235; ARM-NEXT: @ %bb.1: 236; ARM-NEXT: mvns r0, r4 237; ARM-NEXT: .LBB5_2: 238; ARM-NEXT: lsrs r0, r0, #28 239; ARM-NEXT: pop {r4, pc} 240 %tmp = call i4 @llvm.umul.fix.sat.i4(i4 %x, i4 %y, i32 0) 241 ret i4 %tmp 242} 243 244define <4 x i32> @vec2(<4 x i32> %x, <4 x i32> %y) nounwind { 245; ARM-LABEL: vec2: 246; ARM: @ %bb.0: 247; ARM-NEXT: .save {r4, r5, r6, r7, lr} 248; ARM-NEXT: push {r4, r5, r6, r7, lr} 249; ARM-NEXT: .pad #12 250; ARM-NEXT: sub sp, #12 251; ARM-NEXT: str r3, [sp, #8] @ 4-byte Spill 252; ARM-NEXT: mov r7, r2 253; ARM-NEXT: mov r5, r1 254; ARM-NEXT: ldr r2, [sp, #32] 255; ARM-NEXT: movs r6, #0 256; ARM-NEXT: mov r1, r6 257; ARM-NEXT: mov r3, r6 258; ARM-NEXT: bl __aeabi_lmul 259; ARM-NEXT: mvns r4, r6 260; ARM-NEXT: cmp r1, #0 261; ARM-NEXT: mov r1, r4 262; ARM-NEXT: bhi .LBB6_2 263; ARM-NEXT: @ %bb.1: 264; ARM-NEXT: mov r1, r0 265; ARM-NEXT: .LBB6_2: 266; ARM-NEXT: str r1, [sp, #4] @ 4-byte Spill 267; ARM-NEXT: ldr r2, [sp, #36] 268; ARM-NEXT: mov r0, r5 269; ARM-NEXT: mov r1, r6 270; ARM-NEXT: mov r3, r6 271; ARM-NEXT: bl __aeabi_lmul 272; ARM-NEXT: cmp r1, #0 273; ARM-NEXT: mov r5, r4 274; ARM-NEXT: bhi .LBB6_4 275; ARM-NEXT: @ %bb.3: 276; ARM-NEXT: mov r5, r0 277; ARM-NEXT: .LBB6_4: 278; ARM-NEXT: ldr r2, [sp, #40] 279; ARM-NEXT: mov r0, r7 280; ARM-NEXT: mov r1, r6 281; ARM-NEXT: mov r3, r6 282; ARM-NEXT: bl __aeabi_lmul 283; ARM-NEXT: cmp r1, #0 284; ARM-NEXT: mov r7, r4 285; ARM-NEXT: bhi .LBB6_6 286; ARM-NEXT: @ %bb.5: 287; ARM-NEXT: mov r7, r0 288; ARM-NEXT: .LBB6_6: 289; ARM-NEXT: ldr r2, [sp, #44] 290; ARM-NEXT: ldr r0, [sp, #8] @ 4-byte Reload 291; ARM-NEXT: mov r1, r6 292; ARM-NEXT: mov r3, r6 293; ARM-NEXT: bl __aeabi_lmul 294; ARM-NEXT: cmp r1, #0 295; ARM-NEXT: bhi .LBB6_8 296; ARM-NEXT: @ %bb.7: 297; ARM-NEXT: mov r4, r0 298; ARM-NEXT: .LBB6_8: 299; ARM-NEXT: ldr r0, [sp, #4] @ 4-byte Reload 300; ARM-NEXT: mov r1, r5 301; ARM-NEXT: mov r2, r7 302; ARM-NEXT: mov r3, r4 303; ARM-NEXT: add sp, #12 304; ARM-NEXT: pop {r4, r5, r6, r7, pc} 305 %tmp = call <4 x i32> @llvm.umul.fix.sat.v4i32(<4 x i32> %x, <4 x i32> %y, i32 0) 306 ret <4 x i32> %tmp 307} 308 309define i64 @func7(i64 %x, i64 %y) nounwind { 310; ARM-LABEL: func7: 311; ARM: @ %bb.0: 312; ARM-NEXT: .save {r4, r5, r6, r7, lr} 313; ARM-NEXT: push {r4, r5, r6, r7, lr} 314; ARM-NEXT: .pad #12 315; ARM-NEXT: sub sp, #12 316; ARM-NEXT: str r3, [sp, #8] @ 4-byte Spill 317; ARM-NEXT: mov r5, r2 318; ARM-NEXT: mov r6, r1 319; ARM-NEXT: str r1, [sp, #4] @ 4-byte Spill 320; ARM-NEXT: mov r7, r0 321; ARM-NEXT: movs r4, #0 322; ARM-NEXT: mov r1, r4 323; ARM-NEXT: mov r3, r4 324; ARM-NEXT: bl __aeabi_lmul 325; ARM-NEXT: str r1, [sp] @ 4-byte Spill 326; ARM-NEXT: mov r0, r6 327; ARM-NEXT: mov r1, r4 328; ARM-NEXT: mov r2, r5 329; ARM-NEXT: mov r3, r4 330; ARM-NEXT: bl __aeabi_lmul 331; ARM-NEXT: mov r5, r1 332; ARM-NEXT: ldr r1, [sp] @ 4-byte Reload 333; ARM-NEXT: adds r0, r0, r1 334; ARM-NEXT: str r0, [sp] @ 4-byte Spill 335; ARM-NEXT: adcs r5, r4 336; ARM-NEXT: mov r0, r7 337; ARM-NEXT: mov r1, r4 338; ARM-NEXT: ldr r6, [sp, #8] @ 4-byte Reload 339; ARM-NEXT: mov r2, r6 340; ARM-NEXT: mov r3, r4 341; ARM-NEXT: bl __aeabi_lmul 342; ARM-NEXT: ldr r2, [sp] @ 4-byte Reload 343; ARM-NEXT: adds r0, r0, r2 344; ARM-NEXT: str r0, [sp] @ 4-byte Spill 345; ARM-NEXT: adcs r1, r4 346; ARM-NEXT: adds r5, r5, r1 347; ARM-NEXT: mov r7, r4 348; ARM-NEXT: adcs r7, r4 349; ARM-NEXT: ldr r0, [sp, #4] @ 4-byte Reload 350; ARM-NEXT: mov r1, r4 351; ARM-NEXT: mov r2, r6 352; ARM-NEXT: mov r3, r4 353; ARM-NEXT: bl __aeabi_lmul 354; ARM-NEXT: mov r2, r1 355; ARM-NEXT: adds r3, r0, r5 356; ARM-NEXT: adcs r2, r7 357; ARM-NEXT: mvns r1, r4 358; ARM-NEXT: cmp r2, #0 359; ARM-NEXT: mov r0, r1 360; ARM-NEXT: beq .LBB7_3 361; ARM-NEXT: @ %bb.1: 362; ARM-NEXT: beq .LBB7_4 363; ARM-NEXT: .LBB7_2: 364; ARM-NEXT: add sp, #12 365; ARM-NEXT: pop {r4, r5, r6, r7, pc} 366; ARM-NEXT: .LBB7_3: 367; ARM-NEXT: ldr r0, [sp] @ 4-byte Reload 368; ARM-NEXT: bne .LBB7_2 369; ARM-NEXT: .LBB7_4: 370; ARM-NEXT: mov r1, r3 371; ARM-NEXT: add sp, #12 372; ARM-NEXT: pop {r4, r5, r6, r7, pc} 373 %tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 32) 374 ret i64 %tmp 375} 376 377define i64 @func8(i64 %x, i64 %y) nounwind { 378; ARM-LABEL: func8: 379; ARM: @ %bb.0: 380; ARM-NEXT: .save {r4, r5, r6, r7, lr} 381; ARM-NEXT: push {r4, r5, r6, r7, lr} 382; ARM-NEXT: .pad #12 383; ARM-NEXT: sub sp, #12 384; ARM-NEXT: str r3, [sp, #8] @ 4-byte Spill 385; ARM-NEXT: mov r5, r2 386; ARM-NEXT: mov r6, r1 387; ARM-NEXT: str r1, [sp, #4] @ 4-byte Spill 388; ARM-NEXT: mov r7, r0 389; ARM-NEXT: movs r4, #0 390; ARM-NEXT: mov r1, r4 391; ARM-NEXT: mov r3, r4 392; ARM-NEXT: bl __aeabi_lmul 393; ARM-NEXT: str r1, [sp] @ 4-byte Spill 394; ARM-NEXT: mov r0, r6 395; ARM-NEXT: mov r1, r4 396; ARM-NEXT: mov r2, r5 397; ARM-NEXT: mov r3, r4 398; ARM-NEXT: bl __aeabi_lmul 399; ARM-NEXT: mov r5, r1 400; ARM-NEXT: ldr r1, [sp] @ 4-byte Reload 401; ARM-NEXT: adds r0, r0, r1 402; ARM-NEXT: str r0, [sp] @ 4-byte Spill 403; ARM-NEXT: adcs r5, r4 404; ARM-NEXT: mov r0, r7 405; ARM-NEXT: mov r1, r4 406; ARM-NEXT: ldr r6, [sp, #8] @ 4-byte Reload 407; ARM-NEXT: mov r2, r6 408; ARM-NEXT: mov r3, r4 409; ARM-NEXT: bl __aeabi_lmul 410; ARM-NEXT: ldr r2, [sp] @ 4-byte Reload 411; ARM-NEXT: adds r0, r0, r2 412; ARM-NEXT: str r0, [sp] @ 4-byte Spill 413; ARM-NEXT: adcs r1, r4 414; ARM-NEXT: adds r5, r5, r1 415; ARM-NEXT: mov r7, r4 416; ARM-NEXT: adcs r7, r4 417; ARM-NEXT: ldr r0, [sp, #4] @ 4-byte Reload 418; ARM-NEXT: mov r1, r4 419; ARM-NEXT: mov r2, r6 420; ARM-NEXT: mov r3, r4 421; ARM-NEXT: bl __aeabi_lmul 422; ARM-NEXT: adds r0, r0, r5 423; ARM-NEXT: adcs r1, r7 424; ARM-NEXT: lsls r1, r1, #1 425; ARM-NEXT: lsrs r5, r0, #31 426; ARM-NEXT: adds r2, r1, r5 427; ARM-NEXT: lsls r0, r0, #1 428; ARM-NEXT: ldr r1, [sp] @ 4-byte Reload 429; ARM-NEXT: lsrs r1, r1, #31 430; ARM-NEXT: adds r3, r0, r1 431; ARM-NEXT: mvns r1, r4 432; ARM-NEXT: cmp r5, #0 433; ARM-NEXT: mov r0, r1 434; ARM-NEXT: beq .LBB8_3 435; ARM-NEXT: @ %bb.1: 436; ARM-NEXT: beq .LBB8_4 437; ARM-NEXT: .LBB8_2: 438; ARM-NEXT: add sp, #12 439; ARM-NEXT: pop {r4, r5, r6, r7, pc} 440; ARM-NEXT: .LBB8_3: 441; ARM-NEXT: mov r0, r3 442; ARM-NEXT: bne .LBB8_2 443; ARM-NEXT: .LBB8_4: 444; ARM-NEXT: mov r1, r2 445; ARM-NEXT: add sp, #12 446; ARM-NEXT: pop {r4, r5, r6, r7, pc} 447 %tmp = call i64 @llvm.umul.fix.sat.i64(i64 %x, i64 %y, i32 63) 448 ret i64 %tmp 449} 450