1 ; This tests Read-Modify-Write (RMW) detection and lowering at the O2 2 ; optimization level. 3 4 ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ 5 ; RUN: --target x8632 -i %s --args -O2 \ 6 ; RUN: | %if --need=target_X8632 --command FileCheck %s 7 8 define internal void @rmw_add_i32_var(i32 %addr_arg, i32 %var) { 9 entry: 10 %addr = inttoptr i32 %addr_arg to i32* 11 %val = load i32, i32* %addr, align 1 12 %rmw = add i32 %val, %var 13 store i32 %rmw, i32* %addr, align 1 14 ret void 15 } 16 ; Look for something like: add DWORD PTR [eax],ecx 17 ; CHECK-LABEL: rmw_add_i32_var 18 ; CHECK: add DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],e{{ax|bx|cx|dx|bp|di|si}} 19 20 define internal void @rmw_add_i32_imm(i32 %addr_arg) { 21 entry: 22 %addr = inttoptr i32 %addr_arg to i32* 23 %val = load i32, i32* %addr, align 1 24 %rmw = add i32 %val, 19 25 store i32 %rmw, i32* %addr, align 1 26 ret void 27 } 28 ; Look for something like: add DWORD PTR [eax],0x13 29 ; CHECK-LABEL: rmw_add_i32_imm 30 ; CHECK: add DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],0x13 31 32 define internal i32 @no_rmw_add_i32_var(i32 %addr_arg, i32 %var) { 33 entry: 34 %addr = inttoptr i32 %addr_arg to i32* 35 %val = load i32, i32* %addr, align 1 36 %rmw = add i32 %val, %var 37 store i32 %rmw, i32* %addr, align 1 38 ret i32 %rmw 39 } 40 ; CHECK-LABEL: no_rmw_add_i32_var 41 ; CHECK: add e{{ax|bx|cx|dx|bp|di|si}},DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}] 42 43 define internal void @rmw_add_i16_var(i32 %addr_arg, i32 %var32) { 44 entry: 45 %var = trunc i32 %var32 to i16 46 %addr = inttoptr i32 %addr_arg to i16* 47 %val = load i16, i16* %addr, align 1 48 %rmw = add i16 %val, %var 49 store i16 %rmw, i16* %addr, align 1 50 ret void 51 } 52 ; Look for something like: add WORD PTR [eax],cx 53 ; CHECK-LABEL: rmw_add_i16_var 54 ; CHECK: add WORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],{{ax|bx|cx|dx|bp|di|si}} 55 56 define internal void @rmw_add_i16_imm(i32 %addr_arg) { 57 entry: 58 %addr = inttoptr i32 %addr_arg to i16* 59 %val = load i16, i16* %addr, align 1 60 %rmw = add i16 %val, 19 61 store i16 %rmw, i16* %addr, align 1 62 ret void 63 } 64 ; Look for something like: add WORD PTR [eax],0x13 65 ; CHECK-LABEL: rmw_add_i16_imm 66 ; CHECK: add WORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],0x13 67 68 define internal void @rmw_add_i8_var(i32 %addr_arg, i32 %var32) { 69 entry: 70 %var = trunc i32 %var32 to i8 71 %addr = inttoptr i32 %addr_arg to i8* 72 %val = load i8, i8* %addr, align 1 73 %rmw = add i8 %val, %var 74 store i8 %rmw, i8* %addr, align 1 75 ret void 76 } 77 ; Look for something like: add BYTE PTR [eax],cl 78 ; CHECK-LABEL: rmw_add_i8_var 79 ; CHECK: add BYTE PTR [e{{ax|bx|cx|dx|bp|di|si}}],{{al|bl|cl|dl}} 80 81 define internal void @rmw_add_i8_imm(i32 %addr_arg) { 82 entry: 83 %addr = inttoptr i32 %addr_arg to i8* 84 %val = load i8, i8* %addr, align 1 85 %rmw = add i8 %val, 19 86 store i8 %rmw, i8* %addr, align 1 87 ret void 88 } 89 ; Look for something like: add BYTE PTR [eax],0x13 90 ; CHECK-LABEL: rmw_add_i8_imm 91 ; CHECK: add BYTE PTR [e{{ax|bx|cx|dx|bp|di|si}}],0x13 92 93 define internal void @rmw_add_i32_var_addropt(i32 %addr_arg, i32 %var) { 94 entry: 95 %addr_arg_plus_12 = add i32 %addr_arg, 12 96 %var_times_4 = mul i32 %var, 4 97 %addr_base = add i32 %addr_arg_plus_12 , %var_times_4 98 %addr = inttoptr i32 %addr_base to i32* 99 %val = load i32, i32* %addr, align 1 100 %rmw = add i32 %val, %var 101 store i32 %rmw, i32* %addr, align 1 102 ret void 103 } 104 ; Look for something like: add DWORD PTR [eax+ecx*4+12],ecx 105 ; CHECK-LABEL: rmw_add_i32_var_addropt 106 ; CHECK: add DWORD PTR [e{{..}}+e{{..}}*4+0xc],e{{ax|bx|cx|dx|bp|di|si}} 107 108 ; Test for commutativity opportunities. This is the same as rmw_add_i32_var 109 ; except with the "add" operands reversed. 110 define internal void @rmw_add_i32_var_comm(i32 %addr_arg, i32 %var) { 111 entry: 112 %addr = inttoptr i32 %addr_arg to i32* 113 %val = load i32, i32* %addr, align 1 114 %rmw = add i32 %var, %val 115 store i32 %rmw, i32* %addr, align 1 116 ret void 117 } 118 ; Look for something like: add DWORD PTR [eax],ecx 119 ; CHECK-LABEL: rmw_add_i32_var_comm 120 ; CHECK: add DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],e{{ax|bx|cx|dx|bp|di|si}} 121 122 ; Test that commutativity isn't triggered for a non-commutative arithmetic 123 ; operator (sub). This is the same as rmw_add_i32_var_comm except with a 124 ; "sub" operation. 125 define internal i32 @no_rmw_sub_i32_var(i32 %addr_arg, i32 %var) { 126 entry: 127 %addr = inttoptr i32 %addr_arg to i32* 128 %val = load i32, i32* %addr, align 1 129 %rmw = sub i32 %var, %val 130 store i32 %rmw, i32* %addr, align 1 131 ret i32 %rmw 132 } 133 ; CHECK-LABEL: no_rmw_sub_i32_var 134 ; CHECK: sub e{{ax|bx|cx|dx|bp|di|si}},DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}] 135 136 define internal void @rmw_add_i64_undef(i32 %addr_arg) { 137 entry: 138 %addr = inttoptr i32 %addr_arg to i64* 139 %val = load i64, i64* %addr, align 1 140 %rmw = add i64 %val, undef 141 store i64 %rmw, i64* %addr, align 1 142 ret void 143 } 144 ; CHECK-LABEL: rmw_add_i64_undef 145 ; CHECK: add DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}],0x0 146 ; CHECK: adc DWORD PTR [e{{ax|bx|cx|dx|bp|di|si}}+0x4],0x0 147