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 4 declare i16 @identity16(i16 returned %x) 5 declare i32 @identity32(i32 returned %x) 6 declare zeroext i16 @retzext16(i16 returned %x) 7 declare i16 @paramzext16(i16 zeroext returned %x) 8 declare zeroext i16 @bothzext16(i16 zeroext returned %x) 9 10 ; The zeroext param attribute below is meant to have no effect 11 define i16 @test_identity(i16 zeroext %x) { 12 entry: 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) 33 define i16 @test_matched_ret(i16 %x) { 34 entry: 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 65 define i16 @test_mismatched_ret(i16 %x) { 66 entry: 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 85 define i16 @test_matched_paramext(i16 %x) { 86 entry: 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) 108 define i16 @test_matched_paramext2(i16 %x) { 109 entry: 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 134 define i16 @test_matched_bothext(i16 %x) { 135 entry: 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 158 define i16 @test_mismatched_bothext(i16 %x) { 159 entry: 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