1; This file checks support for address mode optimization. 2 3; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 \ 4; RUN: -allow-externally-defined-symbols | FileCheck %s 5; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 -mattr=sse4.1 \ 6; RUN: -allow-externally-defined-symbols | FileCheck --check-prefix=SSE41 %s 7 8define internal float @load_arg_plus_200000(float* %arg) { 9entry: 10 %arg.int = ptrtoint float* %arg to i32 11 %addr.int = add i32 %arg.int, 200000 12 %addr.ptr = inttoptr i32 %addr.int to float* 13 %addr.load = load float, float* %addr.ptr, align 4 14 ret float %addr.load 15; CHECK-LABEL: load_arg_plus_200000 16; CHECK: movss xmm0,DWORD PTR [eax+0x30d40] 17} 18 19define internal float @load_200000_plus_arg(float* %arg) { 20entry: 21 %arg.int = ptrtoint float* %arg to i32 22 %addr.int = add i32 200000, %arg.int 23 %addr.ptr = inttoptr i32 %addr.int to float* 24 %addr.load = load float, float* %addr.ptr, align 4 25 ret float %addr.load 26; CHECK-LABEL: load_200000_plus_arg 27; CHECK: movss xmm0,DWORD PTR [eax+0x30d40] 28} 29 30define internal float @load_arg_minus_200000(float* %arg) { 31entry: 32 %arg.int = ptrtoint float* %arg to i32 33 %addr.int = sub i32 %arg.int, 200000 34 %addr.ptr = inttoptr i32 %addr.int to float* 35 %addr.load = load float, float* %addr.ptr, align 4 36 ret float %addr.load 37; CHECK-LABEL: load_arg_minus_200000 38; CHECK: movss xmm0,DWORD PTR [eax-0x30d40] 39} 40 41define internal float @load_200000_minus_arg(float* %arg) { 42entry: 43 %arg.int = ptrtoint float* %arg to i32 44 %addr.int = sub i32 200000, %arg.int 45 %addr.ptr = inttoptr i32 %addr.int to float* 46 %addr.load = load float, float* %addr.ptr, align 4 47 ret float %addr.load 48; CHECK-LABEL: load_200000_minus_arg 49; CHECK: movss xmm0,DWORD PTR [e{{..}}] 50} 51 52define internal <8 x i16> @load_mul_v8i16_mem(<8 x i16> %arg0, i32 %arg1_iptr) { 53entry: 54 %addr_sub = sub i32 %arg1_iptr, 200000 55 %addr_ptr = inttoptr i32 %addr_sub to <8 x i16>* 56 %arg1 = load <8 x i16>, <8 x i16>* %addr_ptr, align 2 57 %res_vec = mul <8 x i16> %arg0, %arg1 58 ret <8 x i16> %res_vec 59; Address mode optimization is generally unsafe for SSE vector instructions. 60; CHECK-LABEL: load_mul_v8i16_mem 61; CHECK-NOT: pmullw xmm{{.*}},XMMWORD PTR [e{{..}}-0x30d40] 62} 63 64define internal <4 x i32> @load_mul_v4i32_mem(<4 x i32> %arg0, i32 %arg1_iptr) { 65entry: 66 %addr_sub = sub i32 %arg1_iptr, 200000 67 %addr_ptr = inttoptr i32 %addr_sub to <4 x i32>* 68 %arg1 = load <4 x i32>, <4 x i32>* %addr_ptr, align 4 69 %res = mul <4 x i32> %arg0, %arg1 70 ret <4 x i32> %res 71; Address mode optimization is generally unsafe for SSE vector instructions. 72; CHECK-LABEL: load_mul_v4i32_mem 73; CHECK-NOT: pmuludq xmm{{.*}},XMMWORD PTR [e{{..}}-0x30d40] 74; CHECK: pmuludq 75; 76; SSE41-LABEL: load_mul_v4i32_mem 77; SSE41-NOT: pmulld xmm{{.*}},XMMWORD PTR [e{{..}}-0x30d40] 78} 79 80define internal float @address_mode_opt_chaining(float* %arg) { 81entry: 82 %arg.int = ptrtoint float* %arg to i32 83 %addr1.int = add i32 12, %arg.int 84 %addr2.int = sub i32 %addr1.int, 4 85 %addr2.ptr = inttoptr i32 %addr2.int to float* 86 %addr2.load = load float, float* %addr2.ptr, align 4 87 ret float %addr2.load 88; CHECK-LABEL: address_mode_opt_chaining 89; CHECK: movss xmm0,DWORD PTR [eax+0x8] 90} 91 92define internal float @address_mode_opt_chaining_overflow(float* %arg) { 93entry: 94 %arg.int = ptrtoint float* %arg to i32 95 %addr1.int = add i32 2147483640, %arg.int 96 %addr2.int = add i32 %addr1.int, 2147483643 97 %addr2.ptr = inttoptr i32 %addr2.int to float* 98 %addr2.load = load float, float* %addr2.ptr, align 4 99 ret float %addr2.load 100; CHECK-LABEL: address_mode_opt_chaining_overflow 101; CHECK: 0x7ffffff8 102; CHECK: movss xmm0,DWORD PTR [{{.*}}+0x7ffffffb] 103} 104 105define internal float @address_mode_opt_chaining_overflow_sub(float* %arg) { 106entry: 107 %arg.int = ptrtoint float* %arg to i32 108 %addr1.int = sub i32 %arg.int, 2147483640 109 %addr2.int = sub i32 %addr1.int, 2147483643 110 %addr2.ptr = inttoptr i32 %addr2.int to float* 111 %addr2.load = load float, float* %addr2.ptr, align 4 112 ret float %addr2.load 113; CHECK-LABEL: address_mode_opt_chaining_overflow_sub 114; CHECK: 0x7ffffff8 115; CHECK: movss xmm0,DWORD PTR [{{.*}}-0x7ffffffb] 116} 117 118define internal float @address_mode_opt_chaining_no_overflow(float* %arg) { 119entry: 120 %arg.int = ptrtoint float* %arg to i32 121 %addr1.int = sub i32 %arg.int, 2147483640 122 %addr2.int = add i32 %addr1.int, 2147483643 123 %addr2.ptr = inttoptr i32 %addr2.int to float* 124 %addr2.load = load float, float* %addr2.ptr, align 4 125 ret float %addr2.load 126; CHECK-LABEL: address_mode_opt_chaining_no_overflow 127; CHECK: movss xmm0,DWORD PTR [{{.*}}+0x3] 128} 129 130define internal float @address_mode_opt_add_pos_min_int(float* %arg) { 131entry: 132 %arg.int = ptrtoint float* %arg to i32 133 %addr1.int = add i32 %arg.int, 2147483648 134 %addr1.ptr = inttoptr i32 %addr1.int to float* 135 %addr1.load = load float, float* %addr1.ptr, align 4 136 ret float %addr1.load 137; CHECK-LABEL: address_mode_opt_add_pos_min_int 138; CHECK: movss xmm0,DWORD PTR [{{.*}}-0x80000000] 139} 140 141define internal float @address_mode_opt_sub_min_int(float* %arg) { 142entry: 143 %arg.int = ptrtoint float* %arg to i32 144 %addr1.int = sub i32 %arg.int, 2147483648 145 %addr1.ptr = inttoptr i32 %addr1.int to float* 146 %addr1.load = load float, float* %addr1.ptr, align 4 147 ret float %addr1.load 148; CHECK-LABEL: address_mode_opt_sub_min_int 149; CHECK: movss xmm0,DWORD PTR [{{.*}}-0x80000000] 150} 151 152define internal float @load_1_or__2_shl_arg(float* %arg) { 153entry: 154 %arg.int = ptrtoint float* %arg to i32 155 %shl1 = shl i32 %arg.int, 2 156 %addr.int = or i32 1, %shl1 157 %addr.ptr = inttoptr i32 %addr.int to float* 158 %addr.load = load float, float* %addr.ptr, align 4 159 ret float %addr.load 160; CHECK-LABEL: load_1_or__2_shl_arg 161; CHECK-NOT: or 162; CHECK: movss xmm{{[0-9]+}},DWORD PTR [{{e..}}*4+0x1] 163} 164 165define internal float @or_add_boundary_check_1(float* %arg) { 166entry: 167 %arg.int = ptrtoint float* %arg to i32 168 %shl1 = shl i32 %arg.int, 2 169 %addr.int = or i32 5, %shl1 170 %addr.ptr = inttoptr i32 %addr.int to float* 171 %addr.load = load float, float* %addr.ptr, align 4 172 ret float %addr.load 173; CHECK-LABEL: or_add_boundary_check_1 174; CHECK: or 175; CHECK-NOT: movss xmm{{[0-9]+}},DWORD PTR [{{e..}}*4+0x5] 176} 177 178define internal float @or_add_boundary_check_2(float* %arg) { 179entry: 180 %arg.int = ptrtoint float* %arg to i32 181 %shl1 = shl i32 %arg.int, 2 182 %addr.int = or i32 -1, %shl1 183 %addr.ptr = inttoptr i32 %addr.int to float* 184 %addr.load = load float, float* %addr.ptr, align 4 185 ret float %addr.load 186; CHECK-LABEL: or_add_boundary_check_2 187; CHECK: or 188; CHECK-NOT: movss xmm{{[0-9]+}},DWORD PTR [{{e..}}*4+0xFFFF] 189} 190 191define internal void @invert_icmp(i32* %arg1, i32* %arg2) { 192entry: 193 %addr.other = load i32, i32* %arg2, align 1 194 br label %next 195next: 196 %addr.load = load i32, i32* %arg1, align 1 197 %cond = icmp slt i32 %addr.load, %addr.other 198 br i1 %cond, label %if.then, label %if.else 199if.then: 200 ret void 201if.else: 202 ret void 203; CHECK-LABEL: invert_icmp 204; CHECK: cmp {{e..}},DWORD PTR [{{e..}}] 205; CHECK: jle 206}