1; RUN: llc < %s -mtriple=armv6-linux-gnueabi | FileCheck %s -check-prefix=CHECKELF 2; RUN: llc < %s -mtriple=thumbv7-apple-ios5.0 | FileCheck %s -check-prefix=CHECKT2D 3 4declare i16 @identity16(i16 returned %x) 5declare i32 @identity32(i32 returned %x) 6declare zeroext i16 @retzext16(i16 returned %x) 7declare i16 @paramzext16(i16 zeroext returned %x) 8declare zeroext i16 @bothzext16(i16 zeroext returned %x) 9 10; The zeroext param attribute below is meant to have no effect 11define i16 @test_identity(i16 zeroext %x) { 12entry: 13; CHECKELF-LABEL: test_identity: 14; CHECKELF: mov [[SAVEX:r[0-9]+]], r0 15; CHECKELF: bl identity16 16; CHECKELF: uxth r0, r0 17; CHECKELF: bl identity32 18; CHECKELF: mov r0, [[SAVEX]] 19; CHECKT2D-LABEL: test_identity: 20; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0 21; CHECKT2D: bl _identity16 22; CHECKT2D: uxth r0, r0 23; CHECKT2D: bl _identity32 24; CHECKT2D: mov r0, [[SAVEX]] 25 %call = tail call i16 @identity16(i16 %x) 26 %b = zext i16 %call to i32 27 %call2 = tail call i32 @identity32(i32 %b) 28 ret i16 %x 29} 30 31; FIXME: This ought not to require register saving but currently does because 32; x is not considered equal to %call (see SelectionDAGBuilder.cpp) 33define i16 @test_matched_ret(i16 %x) { 34entry: 35; CHECKELF-LABEL: test_matched_ret: 36 37; This shouldn't be required 38; CHECKELF: mov [[SAVEX:r[0-9]+]], r0 39 40; CHECKELF: bl retzext16 41; CHECKELF-NOT: uxth r0, {{r[0-9]+}} 42; CHECKELF: bl identity32 43 44; This shouldn't be required 45; CHECKELF: mov r0, [[SAVEX]] 46 47; CHECKT2D-LABEL: test_matched_ret: 48 49; This shouldn't be required 50; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0 51 52; CHECKT2D: bl _retzext16 53; CHECKT2D-NOT: uxth r0, {{r[0-9]+}} 54; CHECKT2D: bl _identity32 55 56; This shouldn't be required 57; CHECKT2D: mov r0, [[SAVEX]] 58 59 %call = tail call i16 @retzext16(i16 %x) 60 %b = zext i16 %call to i32 61 %call2 = tail call i32 @identity32(i32 %b) 62 ret i16 %x 63} 64 65define i16 @test_mismatched_ret(i16 %x) { 66entry: 67; CHECKELF-LABEL: test_mismatched_ret: 68; CHECKELF: mov [[SAVEX:r[0-9]+]], r0 69; CHECKELF: bl retzext16 70; CHECKELF: sxth r0, {{r[0-9]+}} 71; CHECKELF: bl identity32 72; CHECKELF: mov r0, [[SAVEX]] 73; CHECKT2D-LABEL: test_mismatched_ret: 74; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0 75; CHECKT2D: bl _retzext16 76; CHECKT2D: sxth r0, {{r[0-9]+}} 77; CHECKT2D: bl _identity32 78; CHECKT2D: mov r0, [[SAVEX]] 79 %call = tail call i16 @retzext16(i16 %x) 80 %b = sext i16 %call to i32 81 %call2 = tail call i32 @identity32(i32 %b) 82 ret i16 %x 83} 84 85define i16 @test_matched_paramext(i16 %x) { 86entry: 87; CHECKELF-LABEL: test_matched_paramext: 88; CHECKELF: uxth r0, r0 89; CHECKELF: bl paramzext16 90; CHECKELF: uxth r0, r0 91; CHECKELF: bl identity32 92; CHECKELF: b paramzext16 93; CHECKT2D-LABEL: test_matched_paramext: 94; CHECKT2D: uxth r0, r0 95; CHECKT2D: bl _paramzext16 96; CHECKT2D: uxth r0, r0 97; CHECKT2D: bl _identity32 98; CHECKT2D: b.w _paramzext16 99 %call = tail call i16 @paramzext16(i16 %x) 100 %b = zext i16 %call to i32 101 %call2 = tail call i32 @identity32(i32 %b) 102 %call3 = tail call i16 @paramzext16(i16 %call) 103 ret i16 %call3 104} 105 106; FIXME: This theoretically ought to optimize to exact same output as the 107; version above, but doesn't currently (see SelectionDAGBuilder.cpp) 108define i16 @test_matched_paramext2(i16 %x) { 109entry: 110 111; Since there doesn't seem to be an unambiguous optimal selection and 112; scheduling of uxth and mov instructions below in lieu of the 'returned' 113; optimization, don't bother checking: just verify that the calls are made 114; in the correct order as a basic sanity check 115 116; CHECKELF-LABEL: test_matched_paramext2: 117; CHECKELF: bl paramzext16 118; CHECKELF: bl identity32 119; CHECKELF: b paramzext16 120; CHECKT2D-LABEL: test_matched_paramext2: 121; CHECKT2D: bl _paramzext16 122; CHECKT2D: bl _identity32 123; CHECKT2D: b.w _paramzext16 124 %call = tail call i16 @paramzext16(i16 %x) 125 126; Should make no difference if %x is used below rather than %call, but it does 127 %b = zext i16 %x to i32 128 129 %call2 = tail call i32 @identity32(i32 %b) 130 %call3 = tail call i16 @paramzext16(i16 %call) 131 ret i16 %call3 132} 133 134define i16 @test_matched_bothext(i16 %x) { 135entry: 136; CHECKELF-LABEL: test_matched_bothext: 137; CHECKELF: uxth r0, r0 138; CHECKELF: bl bothzext16 139; CHECKELF-NOT: uxth r0, r0 140 141; FIXME: Tail call should be OK here 142; CHECKELF: bl identity32 143 144; CHECKT2D-LABEL: test_matched_bothext: 145; CHECKT2D: uxth r0, r0 146; CHECKT2D: bl _bothzext16 147; CHECKT2D-NOT: uxth r0, r0 148 149; FIXME: Tail call should be OK here 150; CHECKT2D: bl _identity32 151 152 %call = tail call i16 @bothzext16(i16 %x) 153 %b = zext i16 %x to i32 154 %call2 = tail call i32 @identity32(i32 %b) 155 ret i16 %call 156} 157 158define i16 @test_mismatched_bothext(i16 %x) { 159entry: 160; CHECKELF-LABEL: test_mismatched_bothext: 161; CHECKELF: mov [[SAVEX:r[0-9]+]], r0 162; CHECKELF: uxth r0, {{r[0-9]+}} 163; CHECKELF: bl bothzext16 164; CHECKELF: sxth r0, [[SAVEX]] 165; CHECKELF: bl identity32 166; CHECKELF: mov r0, [[SAVEX]] 167; CHECKT2D-LABEL: test_mismatched_bothext: 168; CHECKT2D: mov [[SAVEX:r[0-9]+]], r0 169; CHECKT2D: uxth r0, {{r[0-9]+}} 170; CHECKT2D: bl _bothzext16 171; CHECKT2D: sxth r0, [[SAVEX]] 172; CHECKT2D: bl _identity32 173; CHECKT2D: mov r0, [[SAVEX]] 174 %call = tail call i16 @bothzext16(i16 %x) 175 %b = sext i16 %x to i32 176 %call2 = tail call i32 @identity32(i32 %b) 177 ret i16 %x 178} 179