| OLD | NEW |
| (Empty) | |
| 1 //===- subzero/unittest/AssemblerX8664/GPRArith.cpp -----------------------===// |
| 2 // |
| 3 // The Subzero Code Generator |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 #include "AssemblerX8664/TestUtil.h" |
| 10 |
| 11 namespace Ice { |
| 12 namespace X8664 { |
| 13 namespace Test { |
| 14 namespace { |
| 15 |
| 16 TEST_F(AssemblerX8664Test, PopAddr) { |
| 17 const uint32_t T0 = allocateQword(); |
| 18 constexpr uint64_t V0 = 0x3AABBEFABBBAA3ull; |
| 19 |
| 20 __ mov(IceType_i32, GPRRegister::Encoded_Reg_eax, Immediate(0xC0FFEE)); |
| 21 __ pushl(GPRRegister::Encoded_Reg_eax); |
| 22 __ popl(dwordAddress(T0)); |
| 23 |
| 24 AssembledTest test = assemble(); |
| 25 test.setQwordTo(T0, V0); |
| 26 |
| 27 test.run(); |
| 28 |
| 29 ASSERT_EQ(0xC0FFEEul, test.contentsOfQword(T0)); |
| 30 } |
| 31 |
| 32 TEST_F(AssemblerX8664Test, SetCC) { |
| 33 #define TestSetCC(C, Dest, IsTrue, Src0, Value0, Src1, Value1) \ |
| 34 do { \ |
| 35 static constexpr char TestString[] = \ |
| 36 "(" #C ", " #Dest ", " #IsTrue ", " #Src0 ", " #Value0 ", " #Src1 \ |
| 37 ", " #Value1 ")"; \ |
| 38 const uint32_t T0 = allocateDword(); \ |
| 39 constexpr uint32_t V0 = 0xF00F00; \ |
| 40 __ mov(IceType_i32, Encoded_GPR_##Src0(), Immediate(Value0)); \ |
| 41 __ mov(IceType_i32, Encoded_GPR_##Src1(), Immediate(Value1)); \ |
| 42 __ cmp(IceType_i32, Encoded_GPR_##Src0(), Encoded_GPR_##Src1()); \ |
| 43 __ mov(IceType_i32, Encoded_GPR_##Dest(), Immediate(0)); \ |
| 44 __ setcc(Cond::Br_##C, RegX8664::getEncodedByteReg(Encoded_GPR_##Dest())); \ |
| 45 __ setcc(Cond::Br_##C, dwordAddress(T0)); \ |
| 46 \ |
| 47 AssembledTest test = assemble(); \ |
| 48 test.setDwordTo(T0, V0); \ |
| 49 \ |
| 50 test.run(); \ |
| 51 \ |
| 52 ASSERT_EQ(IsTrue, test.Dest()) << TestString; \ |
| 53 ASSERT_EQ((0xF00F00 | IsTrue), test.contentsOfDword(T0)) << TestString; \ |
| 54 reset(); \ |
| 55 } while (0) |
| 56 |
| 57 #define TestImpl(Dest, Src0, Src1) \ |
| 58 do { \ |
| 59 TestSetCC(o, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 60 TestSetCC(o, Dest, 0u, Src0, 0x1u, Src1, 0x10000000u); \ |
| 61 TestSetCC(no, Dest, 1u, Src0, 0x1u, Src1, 0x10000000u); \ |
| 62 TestSetCC(no, Dest, 0u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 63 TestSetCC(b, Dest, 1u, Src0, 0x1, Src1, 0x80000000u); \ |
| 64 TestSetCC(b, Dest, 0u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 65 TestSetCC(ae, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 66 TestSetCC(ae, Dest, 0u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 67 TestSetCC(e, Dest, 1u, Src0, 0x1u, Src1, 0x1u); \ |
| 68 TestSetCC(e, Dest, 0u, Src0, 0x1u, Src1, 0x11111u); \ |
| 69 TestSetCC(ne, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 70 TestSetCC(ne, Dest, 0u, Src0, 0x1u, Src1, 0x1u); \ |
| 71 TestSetCC(be, Dest, 1u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 72 TestSetCC(be, Dest, 0u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 73 TestSetCC(a, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 74 TestSetCC(a, Dest, 0u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 75 TestSetCC(s, Dest, 1u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 76 TestSetCC(s, Dest, 0u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 77 TestSetCC(ns, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 78 TestSetCC(ns, Dest, 0u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 79 TestSetCC(p, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 80 TestSetCC(p, Dest, 0u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 81 TestSetCC(np, Dest, 1u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 82 TestSetCC(np, Dest, 0u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 83 TestSetCC(l, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 84 TestSetCC(l, Dest, 0u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 85 TestSetCC(ge, Dest, 1u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 86 TestSetCC(ge, Dest, 0u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 87 TestSetCC(le, Dest, 1u, Src0, 0x80000000u, Src1, 0x1u); \ |
| 88 TestSetCC(le, Dest, 0u, Src0, 0x1u, Src1, 0x80000000u); \ |
| 89 } while (0) |
| 90 |
| 91 TestImpl(r1, r2, r3); |
| 92 TestImpl(r2, r3, r4); |
| 93 TestImpl(r3, r4, r5); |
| 94 TestImpl(r4, r5, r6); |
| 95 TestImpl(r5, r6, r7); |
| 96 TestImpl(r6, r7, r8); |
| 97 TestImpl(r7, r8, r10); |
| 98 TestImpl(r8, r10, r11); |
| 99 TestImpl(r10, r11, r12); |
| 100 TestImpl(r11, r12, r13); |
| 101 TestImpl(r12, r13, r14); |
| 102 TestImpl(r13, r14, r15); |
| 103 TestImpl(r14, r15, r1); |
| 104 TestImpl(r15, r1, r2); |
| 105 |
| 106 #undef TestImpl |
| 107 #undef TestSetCC |
| 108 } |
| 109 |
| 110 TEST_F(AssemblerX8664Test, Lea) { |
| 111 #define TestLeaBaseDisp(Base, BaseValue, Disp, Dst) \ |
| 112 do { \ |
| 113 static constexpr char TestString[] = \ |
| 114 "(" #Base ", " #BaseValue ", " #Dst ")"; \ |
| 115 if (Encoded_GPR_##Base() != Encoded_GPR_esp() && \ |
| 116 Encoded_GPR_##Base() != Encoded_GPR_r9()) { \ |
| 117 __ mov(IceType_i32, Encoded_GPR_##Base(), Immediate(BaseValue)); \ |
| 118 } \ |
| 119 __ lea(IceType_i32, Encoded_GPR_##Dst(), \ |
| 120 Address(Encoded_GPR_##Base(), Disp)); \ |
| 121 AssembledTest test = assemble(); \ |
| 122 test.run(); \ |
| 123 ASSERT_EQ(test.Base##d() + (Disp), test.Dst##d()) \ |
| 124 << TestString << " with Disp " << Disp; \ |
| 125 reset(); \ |
| 126 } while (0) |
| 127 |
| 128 #define TestLeaIndex32bitDisp(Index, IndexValue, Disp, Dst0, Dst1, Dst2, Dst3) \ |
| 129 do { \ |
| 130 static constexpr char TestString[] = \ |
| 131 "(" #Index ", " #IndexValue ", " #Dst0 ", " #Dst1 ", " #Dst2 \ |
| 132 ", " #Dst3 ")"; \ |
| 133 if (Encoded_GPR_##Index() != Encoded_GPR_r9()) { \ |
| 134 __ mov(IceType_i32, Encoded_GPR_##Index(), Immediate(IndexValue)); \ |
| 135 } \ |
| 136 __ lea(IceType_i32, Encoded_GPR_##Dst0(), \ |
| 137 Address(Encoded_GPR_##Index(), Traits::TIMES_1, Disp)); \ |
| 138 __ lea(IceType_i32, Encoded_GPR_##Dst1(), \ |
| 139 Address(Encoded_GPR_##Index(), Traits::TIMES_2, Disp)); \ |
| 140 __ lea(IceType_i32, Encoded_GPR_##Dst2(), \ |
| 141 Address(Encoded_GPR_##Index(), Traits::TIMES_4, Disp)); \ |
| 142 __ lea(IceType_i32, Encoded_GPR_##Dst3(), \ |
| 143 Address(Encoded_GPR_##Index(), Traits::TIMES_8, Disp)); \ |
| 144 AssembledTest test = assemble(); \ |
| 145 test.run(); \ |
| 146 ASSERT_EQ((test.Index##d() << Traits::TIMES_1) + (Disp), test.Dst0##d()) \ |
| 147 << TestString << " " << Disp; \ |
| 148 ASSERT_EQ((test.Index##d() << Traits::TIMES_2) + (Disp), test.Dst1##d()) \ |
| 149 << TestString << " " << Disp; \ |
| 150 ASSERT_EQ((test.Index##d() << Traits::TIMES_4) + (Disp), test.Dst2##d()) \ |
| 151 << TestString << " " << Disp; \ |
| 152 ASSERT_EQ((test.Index##d() << Traits::TIMES_8) + (Disp), test.Dst3##d()) \ |
| 153 << TestString << " " << Disp; \ |
| 154 reset(); \ |
| 155 } while (0) |
| 156 |
| 157 #define TestLeaBaseIndexDisp(Base, BaseValue, Index, IndexValue, Disp, Dst0, \ |
| 158 Dst1, Dst2, Dst3) \ |
| 159 do { \ |
| 160 static constexpr char TestString[] = \ |
| 161 "(" #Base ", " #BaseValue ", " #Index ", " #IndexValue ", " #Dst0 \ |
| 162 ", " #Dst1 ", " #Dst2 ", " #Dst3 ")"; \ |
| 163 if (Encoded_GPR_##Base() != Encoded_GPR_esp() && \ |
| 164 Encoded_GPR_##Base() != Encoded_GPR_r9()) { \ |
| 165 __ mov(IceType_i32, Encoded_GPR_##Base(), Immediate(BaseValue)); \ |
| 166 } \ |
| 167 \ |
| 168 if (Encoded_GPR_##Index() != Encoded_GPR_r9()) { \ |
| 169 __ mov(IceType_i32, Encoded_GPR_##Index(), Immediate(IndexValue)); \ |
| 170 } \ |
| 171 \ |
| 172 __ lea(IceType_i32, Encoded_GPR_##Dst0(), \ |
| 173 Address(Encoded_GPR_##Base(), Encoded_GPR_##Index(), \ |
| 174 Traits::TIMES_1, Disp)); \ |
| 175 __ lea(IceType_i32, Encoded_GPR_##Dst1(), \ |
| 176 Address(Encoded_GPR_##Base(), Encoded_GPR_##Index(), \ |
| 177 Traits::TIMES_2, Disp)); \ |
| 178 __ lea(IceType_i32, Encoded_GPR_##Dst2(), \ |
| 179 Address(Encoded_GPR_##Base(), Encoded_GPR_##Index(), \ |
| 180 Traits::TIMES_4, Disp)); \ |
| 181 __ lea(IceType_i32, Encoded_GPR_##Dst3(), \ |
| 182 Address(Encoded_GPR_##Base(), Encoded_GPR_##Index(), \ |
| 183 Traits::TIMES_8, Disp)); \ |
| 184 AssembledTest test = assemble(); \ |
| 185 test.run(); \ |
| 186 uint32_t ExpectedIndexValue = test.Index(); \ |
| 187 if (Encoded_GPR_##Index() == Encoded_GPR_esp()) { \ |
| 188 ExpectedIndexValue = 0; \ |
| 189 } \ |
| 190 ASSERT_EQ(test.Base##d() + (ExpectedIndexValue << Traits::TIMES_1) + \ |
| 191 (Disp), \ |
| 192 test.Dst0##d()) \ |
| 193 << TestString << " " << Disp; \ |
| 194 ASSERT_EQ(test.Base##d() + (ExpectedIndexValue << Traits::TIMES_2) + \ |
| 195 (Disp), \ |
| 196 test.Dst1##d()) \ |
| 197 << TestString << " " << Disp; \ |
| 198 ASSERT_EQ(test.Base##d() + (ExpectedIndexValue << Traits::TIMES_4) + \ |
| 199 (Disp), \ |
| 200 test.Dst2##d()) \ |
| 201 << TestString << " " << Disp; \ |
| 202 ASSERT_EQ(test.Base##d() + (ExpectedIndexValue << Traits::TIMES_8) + \ |
| 203 (Disp), \ |
| 204 test.Dst3##d()) \ |
| 205 << TestString << " " << Disp; \ |
| 206 reset(); \ |
| 207 } while (0) |
| 208 |
| 209 for (const int32_t Disp : |
| 210 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) { |
| 211 TestLeaBaseDisp(r0, 0x22080Fu, Disp, r1); |
| 212 TestLeaBaseDisp(r1, 0x10000Fu, Disp, r2); |
| 213 TestLeaBaseDisp(r2, 0x20000Fu, Disp, r3); |
| 214 TestLeaBaseDisp(r3, 0x30000Fu, Disp, r4); |
| 215 TestLeaBaseDisp(r4, 0x40000Fu, Disp, r5); |
| 216 TestLeaBaseDisp(r5, 0x50000Fu, Disp, r6); |
| 217 TestLeaBaseDisp(r6, 0x60000Fu, Disp, r7); |
| 218 TestLeaBaseDisp(r7, 0x11000Fu, Disp, r8); |
| 219 TestLeaBaseDisp(r8, 0x11200Fu, Disp, r10); |
| 220 TestLeaBaseDisp(r9, 0x000000u, Disp, r10); |
| 221 TestLeaBaseDisp(r10, 0x22000Fu, Disp, r11); |
| 222 TestLeaBaseDisp(r11, 0x22030Fu, Disp, r12); |
| 223 TestLeaBaseDisp(r12, 0x22040Fu, Disp, r13); |
| 224 TestLeaBaseDisp(r13, 0x22050Fu, Disp, r14); |
| 225 TestLeaBaseDisp(r14, 0x22060Fu, Disp, r15); |
| 226 TestLeaBaseDisp(r15, 0x22070Fu, Disp, r1); |
| 227 } |
| 228 |
| 229 // esp is not a valid index register. |
| 230 // ebp is not valid in this addressing mode (rm = 0). |
| 231 for (const int32_t Disp : |
| 232 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) { |
| 233 TestLeaIndex32bitDisp(r1, 0x2000u, Disp, r2, r3, r4, r6); |
| 234 TestLeaIndex32bitDisp(r2, 0x4010u, Disp, r3, r4, r6, r7); |
| 235 TestLeaIndex32bitDisp(r3, 0x6020u, Disp, r4, r6, r7, r5); |
| 236 TestLeaIndex32bitDisp(r4, 0x8030u, Disp, r6, r7, r5, r10); |
| 237 TestLeaIndex32bitDisp(r6, 0xA040u, Disp, r7, r5, r10, r1); |
| 238 TestLeaIndex32bitDisp(r7, 0xC050u, Disp, r5, r10, r1, r11); |
| 239 TestLeaIndex32bitDisp(r8, 0xC060u, Disp, r10, r1, r11, r12); |
| 240 TestLeaIndex32bitDisp(r9, 0x0000u, Disp, r1, r11, r12, r13); |
| 241 TestLeaIndex32bitDisp(r10, 0xC008u, Disp, r11, r12, r13, r14); |
| 242 TestLeaIndex32bitDisp(r11, 0xC009u, Disp, r12, r13, r14, r15); |
| 243 TestLeaIndex32bitDisp(r12, 0xC00Au, Disp, r13, r14, r15, r1); |
| 244 TestLeaIndex32bitDisp(r13, 0xC00Bu, Disp, r14, r15, r1, r2); |
| 245 TestLeaIndex32bitDisp(r14, 0xC00Cu, Disp, r15, r1, r2, r3); |
| 246 TestLeaIndex32bitDisp(r15, 0xC00Du, Disp, r1, r2, r3, r4); |
| 247 } |
| 248 |
| 249 for (const int32_t Disp : |
| 250 {0x00, 0x06, -0x06, 0x0600, -0x6000, 0x6000000, -0x6000000}) { |
| 251 TestLeaBaseIndexDisp(r1, 0x100000u, r2, 0x600u, Disp, r3, r4, r6, r7); |
| 252 TestLeaBaseIndexDisp(r2, 0x200000u, r3, 0x500u, Disp, r4, r6, r7, r8); |
| 253 TestLeaBaseIndexDisp(r3, 0x300000u, r4, 0x400u, Disp, r6, r7, r8, r5); |
| 254 TestLeaBaseIndexDisp(r4, 0x400000u, r6, 0x300u, Disp, r7, r8, r5, r10); |
| 255 TestLeaBaseIndexDisp(r6, 0x500000u, r7, 0x200u, Disp, r8, r5, r10, r11); |
| 256 TestLeaBaseIndexDisp(r7, 0x600000u, r8, 0x100u, Disp, r5, r10, r11, r12); |
| 257 TestLeaBaseIndexDisp(r8, 0x600000u, r9, 0x1A0u, Disp, r10, r11, r12, r13); |
| 258 TestLeaBaseIndexDisp(r9, 0x000000u, r10, 0x1B0u, Disp, r11, r12, r13, r14); |
| 259 TestLeaBaseIndexDisp(r10, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15); |
| 260 TestLeaBaseIndexDisp(r11, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1); |
| 261 TestLeaBaseIndexDisp(r12, 0x604000u, r13, 0x1E0u, Disp, r14, r15, r1, r2); |
| 262 TestLeaBaseIndexDisp(r13, 0x605000u, r14, 0x1F0u, Disp, r15, r1, r2, r3); |
| 263 TestLeaBaseIndexDisp(r14, 0x606000u, r15, 0x10Au, Disp, r1, r2, r3, r4); |
| 264 TestLeaBaseIndexDisp(r15, 0x607000u, r1, 0x10Bu, Disp, r2, r3, r4, r6); |
| 265 |
| 266 TestLeaBaseIndexDisp(r0, 0, r2, 0x600u, Disp, r3, r4, r6, r7); |
| 267 TestLeaBaseIndexDisp(r0, 0, r3, 0x500u, Disp, r4, r6, r7, r8); |
| 268 TestLeaBaseIndexDisp(r0, 0, r4, 0x400u, Disp, r6, r7, r8, r5); |
| 269 TestLeaBaseIndexDisp(r0, 0, r6, 0x300u, Disp, r7, r8, r5, r10); |
| 270 TestLeaBaseIndexDisp(r0, 0, r7, 0x200u, Disp, r8, r5, r10, r11); |
| 271 TestLeaBaseIndexDisp(r0, 0, r8, 0x100u, Disp, r5, r10, r11, r12); |
| 272 TestLeaBaseIndexDisp(r0, 0, r9, 0x000u, Disp, r10, r11, r12, r13); |
| 273 TestLeaBaseIndexDisp(r0, 0, r10, 0x1B0u, Disp, r11, r12, r13, r14); |
| 274 TestLeaBaseIndexDisp(r0, 0, r11, 0x1C0u, Disp, r12, r13, r14, r15); |
| 275 TestLeaBaseIndexDisp(r0, 0, r12, 0x1D0u, Disp, r13, r14, r15, r1); |
| 276 TestLeaBaseIndexDisp(r0, 0, r13, 0x1E0u, Disp, r14, r15, r1, r2); |
| 277 TestLeaBaseIndexDisp(r0, 0, r14, 0x1F0u, Disp, r15, r1, r2, r3); |
| 278 TestLeaBaseIndexDisp(r0, 0, r15, 0x10Au, Disp, r1, r2, r3, r4); |
| 279 TestLeaBaseIndexDisp(r0, 0, r1, 0x10Bu, Disp, r2, r3, r4, r6); |
| 280 |
| 281 TestLeaBaseIndexDisp(r5, 0x100000u, r2, 0x600u, Disp, r3, r4, r6, r7); |
| 282 TestLeaBaseIndexDisp(r5, 0x200000u, r3, 0x500u, Disp, r4, r6, r7, r8); |
| 283 TestLeaBaseIndexDisp(r5, 0x300000u, r4, 0x400u, Disp, r6, r7, r8, r1); |
| 284 TestLeaBaseIndexDisp(r5, 0x400000u, r6, 0x300u, Disp, r7, r8, r1, r10); |
| 285 TestLeaBaseIndexDisp(r5, 0x500000u, r7, 0x200u, Disp, r8, r1, r10, r11); |
| 286 TestLeaBaseIndexDisp(r5, 0x600000u, r8, 0x100u, Disp, r1, r10, r11, r12); |
| 287 TestLeaBaseIndexDisp(r5, 0x600000u, r9, 0x000u, Disp, r10, r11, r12, r13); |
| 288 TestLeaBaseIndexDisp(r5, 0x601000u, r10, 0x1B0u, Disp, r11, r12, r13, r14); |
| 289 TestLeaBaseIndexDisp(r5, 0x602000u, r11, 0x1C0u, Disp, r12, r13, r14, r15); |
| 290 TestLeaBaseIndexDisp(r5, 0x603000u, r12, 0x1D0u, Disp, r13, r14, r15, r1); |
| 291 TestLeaBaseIndexDisp(r5, 0x604000u, r13, 0x1E0u, Disp, r14, r15, r1, r2); |
| 292 TestLeaBaseIndexDisp(r5, 0x605000u, r14, 0x1F0u, Disp, r15, r1, r2, r3); |
| 293 TestLeaBaseIndexDisp(r5, 0x606000u, r15, 0x10Au, Disp, r1, r2, r3, r4); |
| 294 TestLeaBaseIndexDisp(r5, 0x607000u, r1, 0x10Bu, Disp, r2, r3, r4, r6); |
| 295 |
| 296 TestLeaBaseIndexDisp(r2, 0x100000u, r5, 0x600u, Disp, r3, r4, r6, r7); |
| 297 TestLeaBaseIndexDisp(r3, 0x200000u, r5, 0x500u, Disp, r4, r6, r7, r8); |
| 298 TestLeaBaseIndexDisp(r4, 0x300000u, r5, 0x400u, Disp, r6, r7, r8, r1); |
| 299 TestLeaBaseIndexDisp(r6, 0x400000u, r5, 0x300u, Disp, r7, r8, r1, r10); |
| 300 TestLeaBaseIndexDisp(r7, 0x500000u, r5, 0x200u, Disp, r8, r1, r10, r11); |
| 301 TestLeaBaseIndexDisp(r8, 0x600000u, r5, 0x100u, Disp, r1, r10, r11, r12); |
| 302 TestLeaBaseIndexDisp(r9, 0x000000u, r5, 0x1A0u, Disp, r10, r11, r12, r13); |
| 303 TestLeaBaseIndexDisp(r10, 0x601000u, r5, 0x1B0u, Disp, r11, r12, r13, r14); |
| 304 TestLeaBaseIndexDisp(r11, 0x602000u, r5, 0x1C0u, Disp, r12, r13, r14, r15); |
| 305 TestLeaBaseIndexDisp(r12, 0x603000u, r5, 0x1D0u, Disp, r13, r14, r15, r1); |
| 306 TestLeaBaseIndexDisp(r13, 0x604000u, r5, 0x1E0u, Disp, r14, r15, r1, r2); |
| 307 TestLeaBaseIndexDisp(r14, 0x605000u, r5, 0x1F0u, Disp, r15, r1, r2, r3); |
| 308 TestLeaBaseIndexDisp(r15, 0x606000u, r5, 0x10Au, Disp, r1, r2, r3, r4); |
| 309 TestLeaBaseIndexDisp(r1, 0x607000u, r5, 0x10Bu, Disp, r2, r3, r4, r6); |
| 310 |
| 311 TestLeaBaseIndexDisp(r0, 0, r5, 0xC0BEBEEF, Disp, r2, r3, r4, r6); |
| 312 } |
| 313 |
| 314 // Absolute addressing mode is tested in the Low Level tests. The encoding used |
| 315 // by the assembler has different meanings in x86-32 and x86-64. |
| 316 #undef TestLeaBaseIndexDisp |
| 317 #undef TestLeaScaled32bitDisp |
| 318 #undef TestLeaBaseDisp |
| 319 } |
| 320 |
| 321 TEST_F(AssemblerX8664LowLevelTest, LeaAbsolute) { |
| 322 #define TestLeaAbsolute(Dst, Value) \ |
| 323 do { \ |
| 324 static constexpr char TestString[] = "(" #Dst ", " #Value ")"; \ |
| 325 __ lea(IceType_i32, GPRRegister::Encoded_Reg_##Dst, \ |
| 326 Address(Address::ABSOLUTE, Value)); \ |
| 327 static constexpr uint32_t ByteCount = 6; \ |
| 328 ASSERT_EQ(ByteCount, codeBytesSize()) << TestString; \ |
| 329 static constexpr uint8_t Opcode = 0x8D; \ |
| 330 static constexpr uint8_t ModRM = \ |
| 331 /*mod=*/0x00 | /*reg*/ (GPRRegister::Encoded_Reg_##Dst << 3) | \ |
| 332 /*rm*/ GPRRegister::Encoded_Reg_ebp; \ |
| 333 ASSERT_TRUE(verifyBytes<ByteCount>( \ |
| 334 codeBytes(), Opcode, ModRM, (Value)&0xFF, (Value >> 8) & 0xFF, \ |
| 335 (Value >> 16) & 0xFF, (Value >> 24) & 0xFF)); \ |
| 336 reset(); \ |
| 337 } while (0) |
| 338 |
| 339 TestLeaAbsolute(eax, 0x11BEEF22); |
| 340 TestLeaAbsolute(ebx, 0x33BEEF44); |
| 341 TestLeaAbsolute(ecx, 0x55BEEF66); |
| 342 TestLeaAbsolute(edx, 0x77BEEF88); |
| 343 TestLeaAbsolute(esi, 0x99BEEFAA); |
| 344 TestLeaAbsolute(edi, 0xBBBEEFBB); |
| 345 |
| 346 #undef TesLeaAbsolute |
| 347 } |
| 348 |
| 349 TEST_F(AssemblerX8664Test, Test) { |
| 350 static constexpr uint32_t Mask8 = 0xFF; |
| 351 static constexpr uint32_t Mask16 = 0xFFFF; |
| 352 static constexpr uint32_t Mask32 = 0xFFFFFFFF; |
| 353 |
| 354 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \ |
| 355 do { \ |
| 356 static constexpr bool NearJump = true; \ |
| 357 static constexpr char TestString[] = \ |
| 358 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \ |
| 359 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \ |
| 360 static constexpr uint32_t ValueIfFalse = 0x11111111; \ |
| 361 \ |
| 362 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), Immediate(Value0)); \ |
| 363 __ mov(IceType_i##Size, Encoded_GPR_##Src(), Immediate(Value1)); \ |
| 364 __ test(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_##Src()); \ |
| 365 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(ValueIfFalse)); \ |
| 366 Label Done; \ |
| 367 __ j(Cond::Br_e, &Done, NearJump); \ |
| 368 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(ValueIfTrue)); \ |
| 369 __ bind(&Done); \ |
| 370 \ |
| 371 AssembledTest test = assemble(); \ |
| 372 test.run(); \ |
| 373 \ |
| 374 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \ |
| 375 : ValueIfFalse, \ |
| 376 test.Dst()) \ |
| 377 << TestString; \ |
| 378 reset(); \ |
| 379 } while (0) |
| 380 |
| 381 #define TestImplRegImm(Dst, Value0, Imm, Size) \ |
| 382 do { \ |
| 383 static constexpr bool NearJump = true; \ |
| 384 static constexpr char TestString[] = \ |
| 385 "(" #Dst ", " #Value0 ", " #Imm ", " #Size ")"; \ |
| 386 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \ |
| 387 static constexpr uint32_t ValueIfFalse = 0x11111111; \ |
| 388 \ |
| 389 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), Immediate(Value0)); \ |
| 390 __ test(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 391 Immediate((Imm)&Mask##Size)); \ |
| 392 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(ValueIfFalse)); \ |
| 393 Label Done; \ |
| 394 __ j(Cond::Br_e, &Done, NearJump); \ |
| 395 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(ValueIfTrue)); \ |
| 396 __ bind(&Done); \ |
| 397 \ |
| 398 AssembledTest test = assemble(); \ |
| 399 test.run(); \ |
| 400 \ |
| 401 ASSERT_EQ(((Value0)&Mask##Size) & ((Imm)&Mask##Size) ? ValueIfTrue \ |
| 402 : ValueIfFalse, \ |
| 403 test.Dst()) \ |
| 404 << TestString; \ |
| 405 reset(); \ |
| 406 } while (0) |
| 407 |
| 408 #define TestImplAddrReg(Value0, Src, Value1, Size) \ |
| 409 do { \ |
| 410 static constexpr bool NearJump = true; \ |
| 411 static constexpr char TestString[] = \ |
| 412 "(Addr, " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \ |
| 413 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \ |
| 414 static constexpr uint32_t ValueIfFalse = 0x11111111; \ |
| 415 const uint32_t T0 = allocateDword(); \ |
| 416 \ |
| 417 __ mov(IceType_i##Size, Encoded_GPR_##Src(), Immediate(Value1)); \ |
| 418 __ test(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Src()); \ |
| 419 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfFalse)); \ |
| 420 Label Done; \ |
| 421 __ j(Cond::Br_e, &Done, NearJump); \ |
| 422 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfTrue)); \ |
| 423 __ bind(&Done); \ |
| 424 \ |
| 425 AssembledTest test = assemble(); \ |
| 426 test.setDwordTo(T0, uint32_t(Value0)); \ |
| 427 test.run(); \ |
| 428 \ |
| 429 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \ |
| 430 : ValueIfFalse, \ |
| 431 test.contentsOfDword(T0)) \ |
| 432 << TestString; \ |
| 433 reset(); \ |
| 434 } while (0) |
| 435 |
| 436 #define TestImplAddrImm(Value0, Value1, Size) \ |
| 437 do { \ |
| 438 static constexpr bool NearJump = true; \ |
| 439 static constexpr char TestString[] = \ |
| 440 "(Addr, " #Value0 ", " #Value1 ", " #Size ")"; \ |
| 441 static constexpr uint32_t ValueIfTrue = 0xBEEFFEEB; \ |
| 442 static constexpr uint32_t ValueIfFalse = 0x11111111; \ |
| 443 const uint32_t T0 = allocateDword(); \ |
| 444 \ |
| 445 __ test(IceType_i##Size, dwordAddress(T0), \ |
| 446 Immediate((Value1)&Mask##Size)); \ |
| 447 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfFalse)); \ |
| 448 Label Done; \ |
| 449 __ j(Cond::Br_e, &Done, NearJump); \ |
| 450 __ mov(IceType_i32, dwordAddress(T0), Immediate(ValueIfTrue)); \ |
| 451 __ bind(&Done); \ |
| 452 \ |
| 453 AssembledTest test = assemble(); \ |
| 454 test.setDwordTo(T0, uint32_t(Value0)); \ |
| 455 test.run(); \ |
| 456 \ |
| 457 ASSERT_EQ(((Value0)&Mask##Size) & ((Value1)&Mask##Size) ? ValueIfTrue \ |
| 458 : ValueIfFalse, \ |
| 459 test.contentsOfDword(T0)) \ |
| 460 << TestString; \ |
| 461 reset(); \ |
| 462 } while (0) |
| 463 |
| 464 #define TestImplValues(Dst, Value0, Src, Value1, Size) \ |
| 465 do { \ |
| 466 TestImplRegReg(Dst, Value0, Src, Value1, Size); \ |
| 467 TestImplRegImm(Dst, Value0, Value1, Size); \ |
| 468 TestImplAddrReg(Value0, Src, Value1, Size); \ |
| 469 TestImplAddrImm(Value0, Value1, Size); \ |
| 470 } while (0) |
| 471 |
| 472 #define TestImplSize(Dst, Src, Size) \ |
| 473 do { \ |
| 474 TestImplValues(Dst, 0xF0F12101, Src, 0x00000000, Size); \ |
| 475 TestImplValues(Dst, 0xF0000000, Src, 0xF0000000, Size); \ |
| 476 TestImplValues(Dst, 0x0F00000F, Src, 0xF00000F0, Size); \ |
| 477 } while (0) |
| 478 |
| 479 #define TestImpl(Dst, Src) \ |
| 480 do { \ |
| 481 TestImplSize(Dst, Src, 8); \ |
| 482 TestImplSize(Dst, Src, 16); \ |
| 483 TestImplSize(Dst, Src, 32); \ |
| 484 } while (0) |
| 485 |
| 486 TestImpl(r1, r2); |
| 487 TestImpl(r2, r3); |
| 488 TestImpl(r3, r4); |
| 489 TestImpl(r4, r5); |
| 490 TestImpl(r5, r6); |
| 491 TestImpl(r6, r7); |
| 492 TestImpl(r7, r8); |
| 493 TestImpl(r8, r10); |
| 494 TestImpl(r10, r11); |
| 495 TestImpl(r11, r12); |
| 496 TestImpl(r12, r13); |
| 497 TestImpl(r13, r14); |
| 498 TestImpl(r14, r15); |
| 499 TestImpl(r15, r1); |
| 500 |
| 501 #undef TestImpl |
| 502 #undef TestImplSize |
| 503 #undef TestImplValues |
| 504 #undef TestImplAddrImm |
| 505 #undef TestImplAddrReg |
| 506 #undef TestImplRegImm |
| 507 #undef TestImplRegReg |
| 508 } |
| 509 |
| 510 // No mull/div because x86. |
| 511 // No shift because x86. |
| 512 TEST_F(AssemblerX8664Test, Arith_most) { |
| 513 static constexpr uint32_t Mask8 = 0xFF; |
| 514 static constexpr uint32_t Mask16 = 0xFFFF; |
| 515 static constexpr uint32_t Mask32 = 0xFFFFFFFF; |
| 516 |
| 517 #define TestImplRegReg(Inst, Dst, Value0, Src, Value1, Type, Size, Op) \ |
| 518 do { \ |
| 519 static constexpr char TestString[] = \ |
| 520 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \ |
| 521 ", " #Type #Size "_t, " #Op ")"; \ |
| 522 \ |
| 523 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), Immediate(Value0)); \ |
| 524 __ mov(IceType_i##Size, Encoded_GPR_##Src(), Immediate(Value1)); \ |
| 525 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_##Src()); \ |
| 526 \ |
| 527 AssembledTest test = assemble(); \ |
| 528 test.run(); \ |
| 529 \ |
| 530 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \ |
| 531 static_cast<Type##Size##_t>((Value0)&Mask##Size) \ |
| 532 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \ |
| 533 Mask##Size &test.Dst()) \ |
| 534 << TestString; \ |
| 535 reset(); \ |
| 536 } while (0) |
| 537 |
| 538 #define TestImplRegAddr(Inst, Dst, Value0, Value1, Type, Size, Op) \ |
| 539 do { \ |
| 540 static constexpr char TestString[] = \ |
| 541 "(" #Inst ", " #Dst ", " #Value0 ", Addr, " #Value1 ", " #Type #Size \ |
| 542 "_t, " #Op ")"; \ |
| 543 const uint32_t T0 = allocateDword(); \ |
| 544 const uint32_t V0 = Value1; \ |
| 545 \ |
| 546 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), Immediate(Value0)); \ |
| 547 __ mov(IceType_i##Size, dwordAddress(T0), Immediate(Value1)); \ |
| 548 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), dwordAddress(T0)); \ |
| 549 \ |
| 550 AssembledTest test = assemble(); \ |
| 551 test.setDwordTo(T0, V0); \ |
| 552 test.run(); \ |
| 553 \ |
| 554 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \ |
| 555 static_cast<Type##Size##_t>((Value0)&Mask##Size) \ |
| 556 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \ |
| 557 Mask##Size &test.Dst()) \ |
| 558 << TestString; \ |
| 559 reset(); \ |
| 560 } while (0) |
| 561 |
| 562 #define TestImplRegImm(Inst, Dst, Value0, Imm, Type, Size, Op) \ |
| 563 do { \ |
| 564 static constexpr char TestString[] = \ |
| 565 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Type #Size \ |
| 566 "_t, " #Op ")"; \ |
| 567 \ |
| 568 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), Immediate(Value0)); \ |
| 569 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 570 Immediate((Imm)&Mask##Size)); \ |
| 571 \ |
| 572 AssembledTest test = assemble(); \ |
| 573 test.run(); \ |
| 574 \ |
| 575 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \ |
| 576 static_cast<Type##Size##_t>((Value0)&Mask##Size) \ |
| 577 Op static_cast<Type##Size##_t>((Imm)&Mask##Size)), \ |
| 578 Mask##Size &test.Dst()) \ |
| 579 << TestString; \ |
| 580 reset(); \ |
| 581 } while (0) |
| 582 |
| 583 #define TestImplAddrReg(Inst, Value0, Src, Value1, Type, Size, Op) \ |
| 584 do { \ |
| 585 static constexpr char TestString[] = \ |
| 586 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Type #Size \ |
| 587 "_t, " #Op ")"; \ |
| 588 const uint32_t T0 = allocateDword(); \ |
| 589 const uint32_t V0 = Value0; \ |
| 590 \ |
| 591 __ mov(IceType_i##Size, Encoded_GPR_##Src(), Immediate(Value1)); \ |
| 592 __ Inst(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Src()); \ |
| 593 \ |
| 594 AssembledTest test = assemble(); \ |
| 595 test.setDwordTo(T0, V0); \ |
| 596 test.run(); \ |
| 597 \ |
| 598 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \ |
| 599 static_cast<Type##Size##_t>((Value0)&Mask##Size) \ |
| 600 Op static_cast<Type##Size##_t>((Value1)&Mask##Size)), \ |
| 601 Mask##Size &test.contentsOfDword(T0)) \ |
| 602 << TestString; \ |
| 603 reset(); \ |
| 604 } while (0) |
| 605 |
| 606 #define TestImplAddrImm(Inst, Value0, Imm, Type, Size, Op) \ |
| 607 do { \ |
| 608 static constexpr char TestString[] = \ |
| 609 "(" #Inst ", Addr, " #Value0 ", Imm, " #Imm ", " #Type #Size \ |
| 610 "_t, " #Op ")"; \ |
| 611 const uint32_t T0 = allocateDword(); \ |
| 612 const uint32_t V0 = Value0; \ |
| 613 \ |
| 614 __ Inst(IceType_i##Size, dwordAddress(T0), Immediate((Imm)&Mask##Size)); \ |
| 615 \ |
| 616 AssembledTest test = assemble(); \ |
| 617 test.setDwordTo(T0, V0); \ |
| 618 test.run(); \ |
| 619 \ |
| 620 ASSERT_EQ(Mask##Size &static_cast<uint32_t>( \ |
| 621 static_cast<Type##Size##_t>((Value0)&Mask##Size) \ |
| 622 Op static_cast<Type##Size##_t>((Imm)&Mask##Size)), \ |
| 623 Mask##Size &test.contentsOfDword(T0)) \ |
| 624 << TestString; \ |
| 625 reset(); \ |
| 626 } while (0) |
| 627 |
| 628 #define TestImplOp(Inst, Dst, Value0, Src, Value1, Type, Size, Op) \ |
| 629 do { \ |
| 630 TestImplRegReg(Inst, Dst, Value0, Src, Value1, Type, Size, Op); \ |
| 631 TestImplRegAddr(Inst, Dst, Value0, Value1, Type, Size, Op); \ |
| 632 TestImplRegImm(Inst, Dst, Value0, Value1, Type, Size, Op); \ |
| 633 TestImplAddrReg(Inst, Value0, Src, Value1, Type, Size, Op); \ |
| 634 TestImplAddrImm(Inst, Value0, Value1, Type, Size, Op); \ |
| 635 } while (0) |
| 636 |
| 637 #define TestImplValues(Dst, Value0, Src, Value1, Size) \ |
| 638 do { \ |
| 639 TestImplOp(And, Dst, Value0, Src, Value1, int, Size, &); \ |
| 640 TestImplOp(And, Dst, Value0, Src, Value1, uint, Size, &); \ |
| 641 TestImplOp(Or, Dst, Value0, Src, Value1, int, Size, | ); \ |
| 642 TestImplOp(Or, Dst, Value0, Src, Value1, uint, Size, | ); \ |
| 643 TestImplOp(Xor, Dst, Value0, Src, Value1, int, Size, ^); \ |
| 644 TestImplOp(Xor, Dst, Value0, Src, Value1, uint, Size, ^); \ |
| 645 TestImplOp(add, Dst, Value0, Src, Value1, int, Size, +); \ |
| 646 TestImplOp(add, Dst, Value0, Src, Value1, uint, Size, +); \ |
| 647 TestImplOp(sub, Dst, Value0, Src, Value1, int, Size, -); \ |
| 648 TestImplOp(sub, Dst, Value0, Src, Value1, uint, Size, -); \ |
| 649 } while (0) |
| 650 |
| 651 #define TestImplSize(Dst, Src, Size) \ |
| 652 do { \ |
| 653 TestImplValues(Dst, 0xF0F12101, Src, 0x00000000, Size); \ |
| 654 TestImplValues(Dst, 0xF0000000, Src, 0xF0000000, Size); \ |
| 655 TestImplValues(Dst, 0x0F00000F, Src, 0xF0000070, Size); \ |
| 656 TestImplValues(Dst, 0x0F00F00F, Src, 0xF000F070, Size); \ |
| 657 } while (0) |
| 658 |
| 659 #define TestImpl(Dst, Src) \ |
| 660 do { \ |
| 661 TestImplSize(Dst, Src, 8); \ |
| 662 TestImplSize(Dst, Src, 16); \ |
| 663 TestImplSize(Dst, Src, 32); \ |
| 664 } while (0) |
| 665 |
| 666 TestImpl(r1, r2); |
| 667 TestImpl(r2, r3); |
| 668 TestImpl(r3, r4); |
| 669 TestImpl(r4, r5); |
| 670 TestImpl(r5, r6); |
| 671 TestImpl(r6, r7); |
| 672 TestImpl(r7, r8); |
| 673 TestImpl(r8, r10); |
| 674 TestImpl(r10, r11); |
| 675 TestImpl(r11, r12); |
| 676 TestImpl(r12, r13); |
| 677 TestImpl(r13, r14); |
| 678 TestImpl(r14, r15); |
| 679 TestImpl(r15, r1); |
| 680 |
| 681 #undef TestImpl |
| 682 #undef TestImplSize |
| 683 #undef TestImplValues |
| 684 #undef TestImplOp |
| 685 #undef TestImplAddrImm |
| 686 #undef TestImplAddrReg |
| 687 #undef TestImplRegImm |
| 688 #undef TestImplRegAddr |
| 689 #undef TestImplRegReg |
| 690 } |
| 691 |
| 692 TEST_F(AssemblerX8664Test, Arith_BorrowNCarry) { |
| 693 const uint32_t Mask8 = 0x000000FF; |
| 694 const uint32_t Mask16 = 0x0000FFFF; |
| 695 const uint32_t Mask32 = 0xFFFFFFFF; |
| 696 |
| 697 const uint64_t ResultMask8 = 0x000000000000FFFFull; |
| 698 const uint64_t ResultMask16 = 0x00000000FFFFFFFFull; |
| 699 const uint64_t ResultMask32 = 0xFFFFFFFFFFFFFFFFull; |
| 700 |
| 701 #define TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, \ |
| 702 Op, Size) \ |
| 703 do { \ |
| 704 static_assert(Size == 8 || Size == 16 || Size == 32, \ |
| 705 "Invalid size " #Size); \ |
| 706 static constexpr char TestString[] = \ |
| 707 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 ", " #Src0 \ |
| 708 ", " #Src1 ", " #Value1 ", " #Op ", " #Size ")"; \ |
| 709 __ mov(IceType_i##Size, Encoded_GPR_##Dst0(), \ |
| 710 Immediate(uint64_t(Value0) & Mask##Size)); \ |
| 711 __ mov(IceType_i##Size, Encoded_GPR_##Dst1(), \ |
| 712 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \ |
| 713 __ mov(IceType_i##Size, Encoded_GPR_##Src0(), \ |
| 714 Immediate(uint64_t(Value1) & Mask##Size)); \ |
| 715 __ mov(IceType_i##Size, Encoded_GPR_##Src1(), \ |
| 716 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \ |
| 717 __ Inst0(IceType_i##Size, Encoded_GPR_##Dst0(), Encoded_GPR_##Src0()); \ |
| 718 __ Inst1(IceType_i##Size, Encoded_GPR_##Dst1(), Encoded_GPR_##Src1()); \ |
| 719 \ |
| 720 AssembledTest test = assemble(); \ |
| 721 test.run(); \ |
| 722 \ |
| 723 static constexpr uint64_t Result = \ |
| 724 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \ |
| 725 ResultMask##Size); \ |
| 726 static constexpr uint32_t Expected0 = Result & Mask##Size; \ |
| 727 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \ |
| 728 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \ |
| 729 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \ |
| 730 reset(); \ |
| 731 } while (0) |
| 732 |
| 733 #define TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size) \ |
| 734 do { \ |
| 735 static_assert(Size == 8 || Size == 16 || Size == 32, \ |
| 736 "Invalid size " #Size); \ |
| 737 static constexpr char TestString[] = \ |
| 738 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \ |
| 739 ", Addr, " #Value1 ", " #Op ", " #Size ")"; \ |
| 740 const uint32_t T0 = allocateDword(); \ |
| 741 const uint32_t V0 = uint64_t(Value1) & Mask##Size; \ |
| 742 const uint32_t T1 = allocateDword(); \ |
| 743 const uint32_t V1 = (uint64_t(Value1) >> Size) & Mask##Size; \ |
| 744 __ mov(IceType_i##Size, Encoded_GPR_##Dst0(), \ |
| 745 Immediate(uint64_t(Value0) & Mask##Size)); \ |
| 746 __ mov(IceType_i##Size, Encoded_GPR_##Dst1(), \ |
| 747 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \ |
| 748 __ Inst0(IceType_i##Size, Encoded_GPR_##Dst0(), dwordAddress(T0)); \ |
| 749 __ Inst1(IceType_i##Size, Encoded_GPR_##Dst1(), dwordAddress(T1)); \ |
| 750 \ |
| 751 AssembledTest test = assemble(); \ |
| 752 test.setDwordTo(T0, V0); \ |
| 753 test.setDwordTo(T1, V1); \ |
| 754 test.run(); \ |
| 755 \ |
| 756 static constexpr uint64_t Result = \ |
| 757 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \ |
| 758 ResultMask##Size); \ |
| 759 static constexpr uint32_t Expected0 = Result & Mask##Size; \ |
| 760 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \ |
| 761 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \ |
| 762 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \ |
| 763 reset(); \ |
| 764 } while (0) |
| 765 |
| 766 #define TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Imm, Op, Size) \ |
| 767 do { \ |
| 768 static_assert(Size == 8 || Size == 16 || Size == 32, \ |
| 769 "Invalid size " #Size); \ |
| 770 static constexpr char TestString[] = \ |
| 771 "(" #Inst0 ", " #Inst1 ", " #Dst0 ", " #Dst1 ", " #Value0 \ |
| 772 ", Imm(" #Imm "), " #Op ", " #Size ")"; \ |
| 773 __ mov(IceType_i##Size, Encoded_GPR_##Dst0(), \ |
| 774 Immediate(uint64_t(Value0) & Mask##Size)); \ |
| 775 __ mov(IceType_i##Size, Encoded_GPR_##Dst1(), \ |
| 776 Immediate((uint64_t(Value0) >> Size) & Mask##Size)); \ |
| 777 __ Inst0(IceType_i##Size, Encoded_GPR_##Dst0(), \ |
| 778 Immediate(uint64_t(Imm) & Mask##Size)); \ |
| 779 __ Inst1(IceType_i##Size, Encoded_GPR_##Dst1(), \ |
| 780 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \ |
| 781 \ |
| 782 AssembledTest test = assemble(); \ |
| 783 test.run(); \ |
| 784 \ |
| 785 static constexpr uint64_t Result = \ |
| 786 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Imm) & \ |
| 787 ResultMask##Size); \ |
| 788 static constexpr uint32_t Expected0 = Result & Mask##Size; \ |
| 789 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \ |
| 790 ASSERT_EQ(Expected0, test.Dst0()) << TestString << ": 0"; \ |
| 791 ASSERT_EQ(Expected1, test.Dst1()) << TestString << ": 1"; \ |
| 792 reset(); \ |
| 793 } while (0) |
| 794 |
| 795 #define TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size) \ |
| 796 do { \ |
| 797 static_assert(Size == 8 || Size == 16 || Size == 32, \ |
| 798 "Invalid size " #Size); \ |
| 799 static constexpr char TestString[] = \ |
| 800 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", " #Src0 ", " #Src1 \ |
| 801 ", " #Value1 ", " #Op ", " #Size ")"; \ |
| 802 const uint32_t T0 = allocateDword(); \ |
| 803 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \ |
| 804 const uint32_t T1 = allocateDword(); \ |
| 805 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \ |
| 806 __ mov(IceType_i##Size, Encoded_GPR_##Src0(), \ |
| 807 Immediate(uint64_t(Value1) & Mask##Size)); \ |
| 808 __ mov(IceType_i##Size, Encoded_GPR_##Src1(), \ |
| 809 Immediate((uint64_t(Value1) >> Size) & Mask##Size)); \ |
| 810 __ Inst0(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Src0()); \ |
| 811 __ Inst1(IceType_i##Size, dwordAddress(T1), Encoded_GPR_##Src1()); \ |
| 812 \ |
| 813 AssembledTest test = assemble(); \ |
| 814 test.setDwordTo(T0, V0); \ |
| 815 test.setDwordTo(T1, V1); \ |
| 816 test.run(); \ |
| 817 \ |
| 818 static constexpr uint64_t Result = \ |
| 819 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Value1) & \ |
| 820 ResultMask##Size); \ |
| 821 static constexpr uint32_t Expected0 = Result & Mask##Size; \ |
| 822 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \ |
| 823 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \ |
| 824 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \ |
| 825 reset(); \ |
| 826 } while (0) |
| 827 |
| 828 #define TestImplAddrImm(Inst0, Inst1, Value0, Imm, Op, Size) \ |
| 829 do { \ |
| 830 static_assert(Size == 8 || Size == 16 || Size == 32, \ |
| 831 "Invalid size " #Size); \ |
| 832 static constexpr char TestString[] = \ |
| 833 "(" #Inst0 ", " #Inst1 ", Addr, " #Value0 ", Imm(" #Imm "), " #Op \ |
| 834 ", " #Size ")"; \ |
| 835 const uint32_t T0 = allocateDword(); \ |
| 836 const uint32_t V0 = uint64_t(Value0) & Mask##Size; \ |
| 837 const uint32_t T1 = allocateDword(); \ |
| 838 const uint32_t V1 = (uint64_t(Value0) >> Size) & Mask##Size; \ |
| 839 __ Inst0(IceType_i##Size, dwordAddress(T0), \ |
| 840 Immediate(uint64_t(Imm) & Mask##Size)); \ |
| 841 __ Inst1(IceType_i##Size, dwordAddress(T1), \ |
| 842 Immediate((uint64_t(Imm) >> Size) & Mask##Size)); \ |
| 843 \ |
| 844 AssembledTest test = assemble(); \ |
| 845 test.setDwordTo(T0, V0); \ |
| 846 test.setDwordTo(T1, V1); \ |
| 847 test.run(); \ |
| 848 \ |
| 849 static constexpr uint64_t Result = \ |
| 850 (uint64_t(Value0) & ResultMask##Size)Op(uint64_t(Imm) & \ |
| 851 ResultMask##Size); \ |
| 852 static constexpr uint32_t Expected0 = Result & Mask##Size; \ |
| 853 static constexpr uint32_t Expected1 = (Result >> Size) & Mask##Size; \ |
| 854 ASSERT_EQ(Expected0, test.contentsOfDword(T0)) << TestString << ": 0"; \ |
| 855 ASSERT_EQ(Expected1, test.contentsOfDword(T1)) << TestString << ": 1"; \ |
| 856 reset(); \ |
| 857 } while (0) |
| 858 |
| 859 #define TestImplOp(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \ |
| 860 Size) \ |
| 861 do { \ |
| 862 TestImplRegReg(Inst0, Inst1, Dst0, Dst1, Value0, Src0, Src1, Value1, Op, \ |
| 863 Size); \ |
| 864 TestImplRegAddr(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \ |
| 865 TestImplRegImm(Inst0, Inst1, Dst0, Dst1, Value0, Value1, Op, Size); \ |
| 866 TestImplAddrReg(Inst0, Inst1, Value0, Src0, Src1, Value1, Op, Size); \ |
| 867 TestImplAddrImm(Inst0, Inst1, Value0, Value1, Op, Size); \ |
| 868 } while (0) |
| 869 |
| 870 #define TestImplValues(Dst0, Dst1, Value0, Src0, Src1, Value1, Size) \ |
| 871 do { \ |
| 872 TestImplOp(add, adc, Dst0, Dst1, Value0, Src0, Src1, Value1, +, Size); \ |
| 873 TestImplOp(sub, sbb, Dst0, Dst1, Value0, Src0, Src1, Value1, -, Size); \ |
| 874 } while (0) |
| 875 |
| 876 #define TestImplSize(Dst0, Dst1, Src0, Src1, Size) \ |
| 877 do { \ |
| 878 TestImplValues(Dst0, Dst1, 0xFFFFFFFFFFFFFF00ull, Src0, Src1, \ |
| 879 0xFFFFFFFF0000017Full, Size); \ |
| 880 } while (0) |
| 881 |
| 882 #define TestImpl(Dst0, Dst1, Src0, Src1) \ |
| 883 do { \ |
| 884 TestImplSize(Dst0, Dst1, Src0, Src1, 8); \ |
| 885 TestImplSize(Dst0, Dst1, Src0, Src1, 16); \ |
| 886 TestImplSize(Dst0, Dst1, Src0, Src1, 32); \ |
| 887 } while (0) |
| 888 |
| 889 TestImpl(r1, r2, r3, r5); |
| 890 TestImpl(r2, r3, r4, r6); |
| 891 TestImpl(r3, r4, r5, r7); |
| 892 TestImpl(r4, r5, r6, r8); |
| 893 TestImpl(r5, r6, r7, r10); |
| 894 TestImpl(r6, r7, r8, r11); |
| 895 TestImpl(r7, r8, r10, r12); |
| 896 TestImpl(r8, r10, r11, r13); |
| 897 TestImpl(r10, r11, r12, r14); |
| 898 TestImpl(r11, r12, r13, r15); |
| 899 TestImpl(r12, r13, r14, r1); |
| 900 TestImpl(r13, r14, r15, r2); |
| 901 TestImpl(r14, r15, r1, r3); |
| 902 TestImpl(r15, r1, r2, r4); |
| 903 |
| 904 #undef TestImpl |
| 905 #undef TestImplSize |
| 906 #undef TestImplValues |
| 907 #undef TestImplOp |
| 908 #undef TestImplAddrImm |
| 909 #undef TestImplAddrReg |
| 910 #undef TestImplRegImm |
| 911 #undef TestImplRegAddr |
| 912 #undef TestImplRegReg |
| 913 } |
| 914 |
| 915 TEST_F(AssemblerX8664LowLevelTest, Cbw_Cwd_Cdq) { |
| 916 #define TestImpl(Inst, BytesSize, ...) \ |
| 917 do { \ |
| 918 __ Inst(); \ |
| 919 ASSERT_EQ(BytesSize, codeBytesSize()) << #Inst; \ |
| 920 ASSERT_TRUE(verifyBytes<BytesSize>(codeBytes(), __VA_ARGS__)); \ |
| 921 reset(); \ |
| 922 } while (0) |
| 923 |
| 924 TestImpl(cbw, 2u, 0x66, 0x98); |
| 925 TestImpl(cwd, 2u, 0x66, 0x99); |
| 926 TestImpl(cdq, 1u, 0x99); |
| 927 |
| 928 #undef TestImpl |
| 929 } |
| 930 |
| 931 TEST_F(AssemblerX8664Test, SingleOperandMul) { |
| 932 static constexpr uint32_t Mask8 = 0x000000FF; |
| 933 static constexpr uint32_t Mask16 = 0x0000FFFF; |
| 934 static constexpr uint32_t Mask32 = 0xFFFFFFFF; |
| 935 |
| 936 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \ |
| 937 do { \ |
| 938 static_assert(Encoded_GPR_eax() != Encoded_GPR_##Src(), \ |
| 939 "eax can not be src1."); \ |
| 940 \ |
| 941 static constexpr char TestString[] = \ |
| 942 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \ |
| 943 ")"; \ |
| 944 static constexpr Type##64_t OperandEax = \ |
| 945 static_cast<Type##Size##_t>((Value0)&Mask##Size); \ |
| 946 static constexpr Type##64_t OperandOther = \ |
| 947 static_cast<Type##Size##_t>((Value1)&Mask##Size); \ |
| 948 static constexpr uint32_t ExpectedEax = \ |
| 949 Mask##Size & (OperandEax * OperandOther); \ |
| 950 static constexpr uint32_t ExpectedEdx = \ |
| 951 Mask##Size & ((OperandEax * OperandOther) >> Size); \ |
| 952 \ |
| 953 __ mov(IceType_i##Size, Encoded_GPR_eax(), \ |
| 954 Immediate((Value0)&Mask##Size)); \ |
| 955 __ mov(IceType_i##Size, Encoded_GPR_##Src(), \ |
| 956 Immediate((Value1)&Mask##Size)); \ |
| 957 __ Inst(IceType_i##Size, Encoded_GPR_##Src()); \ |
| 958 \ |
| 959 if (Size == 8) { \ |
| 960 /* mov %ah, %dl */ \ |
| 961 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 962 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 963 __ And(IceType_i16, Encoded_GPR_ax(), Immediate(0x00FF)); \ |
| 964 } \ |
| 965 \ |
| 966 AssembledTest test = assemble(); \ |
| 967 test.run(); \ |
| 968 \ |
| 969 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \ |
| 970 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \ |
| 971 reset(); \ |
| 972 } while (0) |
| 973 |
| 974 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \ |
| 975 do { \ |
| 976 static constexpr char TestString[] = \ |
| 977 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \ |
| 978 static const uint32_t T0 = allocateDword(); \ |
| 979 static constexpr uint32_t V0 = Value1; \ |
| 980 static constexpr Type##64_t OperandEax = \ |
| 981 static_cast<Type##Size##_t>((Value0)&Mask##Size); \ |
| 982 static constexpr Type##64_t OperandOther = \ |
| 983 static_cast<Type##Size##_t>((Value1)&Mask##Size); \ |
| 984 static constexpr uint32_t ExpectedEax = \ |
| 985 Mask##Size & (OperandEax * OperandOther); \ |
| 986 static constexpr uint32_t ExpectedEdx = \ |
| 987 Mask##Size & ((OperandEax * OperandOther) >> Size); \ |
| 988 \ |
| 989 __ mov(IceType_i##Size, Encoded_GPR_eax(), \ |
| 990 Immediate((Value0)&Mask##Size)); \ |
| 991 __ Inst(IceType_i##Size, dwordAddress(T0)); \ |
| 992 \ |
| 993 if (Size == 8) { \ |
| 994 /* mov %ah, %dl */ \ |
| 995 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 996 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 997 __ And(IceType_i16, Encoded_GPR_ax(), Immediate(0x00FF)); \ |
| 998 } \ |
| 999 \ |
| 1000 AssembledTest test = assemble(); \ |
| 1001 test.setDwordTo(T0, V0); \ |
| 1002 test.run(); \ |
| 1003 \ |
| 1004 ASSERT_EQ(ExpectedEax, test.eax()) << TestString; \ |
| 1005 ASSERT_EQ(ExpectedEdx, test.edx()) << TestString; \ |
| 1006 reset(); \ |
| 1007 } while (0) |
| 1008 |
| 1009 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \ |
| 1010 do { \ |
| 1011 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \ |
| 1012 TestImplAddr(Inst, Value0, Value1, Type, Size); \ |
| 1013 } while (0) |
| 1014 |
| 1015 #define TestImplValue(Value0, Src, Value1, Size) \ |
| 1016 do { \ |
| 1017 TestImplOp(mul, Value0, Src, Value1, uint, Size); \ |
| 1018 TestImplOp(imul, Value0, Src, Value1, int, Size); \ |
| 1019 } while (0) |
| 1020 |
| 1021 #define TestImplSize(Src, Size) \ |
| 1022 do { \ |
| 1023 TestImplValue(10, Src, 1, Size); \ |
| 1024 TestImplValue(10, Src, -1, Size); \ |
| 1025 TestImplValue(-10, Src, 37, Size); \ |
| 1026 TestImplValue(-10, Src, -15, Size); \ |
| 1027 } while (0) |
| 1028 |
| 1029 #define TestImpl(Src) \ |
| 1030 do { \ |
| 1031 TestImplSize(Src, 8); \ |
| 1032 TestImplSize(Src, 16); \ |
| 1033 TestImplSize(Src, 32); \ |
| 1034 } while (0) |
| 1035 |
| 1036 TestImpl(r2); |
| 1037 TestImpl(r3); |
| 1038 TestImpl(r4); |
| 1039 TestImpl(r5); |
| 1040 TestImpl(r6); |
| 1041 TestImpl(r7); |
| 1042 TestImpl(r8); |
| 1043 TestImpl(r10); |
| 1044 TestImpl(r11); |
| 1045 TestImpl(r12); |
| 1046 TestImpl(r13); |
| 1047 TestImpl(r14); |
| 1048 TestImpl(r15); |
| 1049 |
| 1050 #undef TestImpl |
| 1051 #undef TestImplSize |
| 1052 #undef TestImplValue |
| 1053 #undef TestImplOp |
| 1054 #undef TestImplAddr |
| 1055 #undef TestImplReg |
| 1056 } |
| 1057 |
| 1058 TEST_F(AssemblerX8664Test, TwoOperandImul) { |
| 1059 static constexpr uint32_t Mask16 = 0x0000FFFF; |
| 1060 static constexpr uint32_t Mask32 = 0xFFFFFFFF; |
| 1061 |
| 1062 #define TestImplRegReg(Dst, Value0, Src, Value1, Size) \ |
| 1063 do { \ |
| 1064 static constexpr char TestString[] = \ |
| 1065 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Size ")"; \ |
| 1066 static constexpr int64_t Operand0 = \ |
| 1067 static_cast<int##Size##_t>((Value0)&Mask##Size); \ |
| 1068 static constexpr int64_t Operand1 = \ |
| 1069 static_cast<int##Size##_t>((Value1)&Mask##Size); \ |
| 1070 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \ |
| 1071 \ |
| 1072 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1073 Immediate((Value0)&Mask##Size)); \ |
| 1074 __ mov(IceType_i##Size, Encoded_GPR_##Src(), \ |
| 1075 Immediate((Value1)&Mask##Size)); \ |
| 1076 __ imul(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_##Src()); \ |
| 1077 \ |
| 1078 if (Size == 8) { \ |
| 1079 /* mov %ah, %dl */ \ |
| 1080 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 1081 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 1082 __ And(IceType_i16, Encoded_GPR_ax(), Immediate(0x00FF)); \ |
| 1083 } \ |
| 1084 \ |
| 1085 AssembledTest test = assemble(); \ |
| 1086 test.run(); \ |
| 1087 \ |
| 1088 ASSERT_EQ(Expected, test.Dst()) << TestString; \ |
| 1089 reset(); \ |
| 1090 } while (0) |
| 1091 |
| 1092 #define TestImplRegImm(Dst, Value0, Imm, Size) \ |
| 1093 do { \ |
| 1094 static constexpr char TestString[] = \ |
| 1095 "(" #Dst ", " #Value0 ", Imm(" #Imm "), " #Size ")"; \ |
| 1096 static constexpr int64_t Operand0 = \ |
| 1097 static_cast<int##Size##_t>((Value0)&Mask##Size); \ |
| 1098 static constexpr int64_t Operand1 = \ |
| 1099 static_cast<int##Size##_t>((Imm)&Mask##Size); \ |
| 1100 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \ |
| 1101 \ |
| 1102 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1103 Immediate((Value0)&Mask##Size)); \ |
| 1104 __ imul(IceType_i##Size, Encoded_GPR_##Dst(), Immediate(Imm)); \ |
| 1105 \ |
| 1106 if (Size == 8) { \ |
| 1107 /* mov %ah, %dl */ \ |
| 1108 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 1109 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 1110 __ And(IceType_i16, Encoded_GPR_ax(), Immediate(0x00FF)); \ |
| 1111 } \ |
| 1112 \ |
| 1113 AssembledTest test = assemble(); \ |
| 1114 test.run(); \ |
| 1115 \ |
| 1116 ASSERT_EQ(Expected, test.Dst()) << TestString; \ |
| 1117 reset(); \ |
| 1118 } while (0) |
| 1119 |
| 1120 #define TestImplRegAddr(Dst, Value0, Value1, Size) \ |
| 1121 do { \ |
| 1122 static constexpr char TestString[] = \ |
| 1123 "(" #Dst ", " #Value0 ", Addr," #Value1 ", " #Size ")"; \ |
| 1124 static constexpr int64_t Operand0 = \ |
| 1125 static_cast<int##Size##_t>((Value0)&Mask##Size); \ |
| 1126 static constexpr int64_t Operand1 = \ |
| 1127 static_cast<int##Size##_t>((Value1)&Mask##Size); \ |
| 1128 static constexpr uint32_t Expected = Mask##Size & (Operand0 * Operand1); \ |
| 1129 const uint32_t T0 = allocateDword(); \ |
| 1130 \ |
| 1131 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1132 Immediate((Value0)&Mask##Size)); \ |
| 1133 __ imul(IceType_i##Size, Encoded_GPR_##Dst(), dwordAddress(T0)); \ |
| 1134 \ |
| 1135 if (Size == 8) { \ |
| 1136 /* mov %ah, %dl */ \ |
| 1137 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 1138 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 1139 __ And(IceType_i16, Encoded_GPR_ax(), Immediate(0x00FF)); \ |
| 1140 } \ |
| 1141 \ |
| 1142 AssembledTest test = assemble(); \ |
| 1143 test.setDwordTo(T0, static_cast<uint32_t>(Operand1)); \ |
| 1144 test.run(); \ |
| 1145 \ |
| 1146 ASSERT_EQ(Expected, test.Dst()) << TestString; \ |
| 1147 reset(); \ |
| 1148 } while (0) |
| 1149 |
| 1150 #define TestImplValue(Dst, Value0, Src, Value1, Size) \ |
| 1151 do { \ |
| 1152 TestImplRegReg(Dst, Value0, Src, Value1, Size); \ |
| 1153 TestImplRegImm(Dst, Value0, Value1, Size); \ |
| 1154 TestImplRegAddr(Dst, Value0, Value1, Size); \ |
| 1155 } while (0) |
| 1156 |
| 1157 #define TestImplSize(Dst, Src, Size) \ |
| 1158 do { \ |
| 1159 TestImplValue(Dst, 1, Src, 1, Size); \ |
| 1160 TestImplValue(Dst, -10, Src, 0x4050AA20, Size); \ |
| 1161 TestImplValue(Dst, -2, Src, -55, Size); \ |
| 1162 } while (0) |
| 1163 |
| 1164 #define TestImpl(Dst, Src) \ |
| 1165 do { \ |
| 1166 TestImplSize(Dst, Src, 16); \ |
| 1167 TestImplSize(Dst, Src, 32); \ |
| 1168 } while (0) |
| 1169 |
| 1170 TestImpl(r1, r2); |
| 1171 TestImpl(r2, r3); |
| 1172 TestImpl(r3, r4); |
| 1173 TestImpl(r4, r5); |
| 1174 TestImpl(r5, r6); |
| 1175 TestImpl(r6, r7); |
| 1176 TestImpl(r7, r8); |
| 1177 TestImpl(r8, r10); |
| 1178 TestImpl(r10, r11); |
| 1179 TestImpl(r11, r12); |
| 1180 TestImpl(r12, r13); |
| 1181 TestImpl(r13, r14); |
| 1182 TestImpl(r14, r15); |
| 1183 TestImpl(r15, r1); |
| 1184 |
| 1185 #undef TestImpl |
| 1186 #undef TestImplSize |
| 1187 #undef TestImplValue |
| 1188 #undef TestImplRegAddr |
| 1189 #undef TestImplRegImm |
| 1190 #undef TestImplRegReg |
| 1191 } |
| 1192 |
| 1193 TEST_F(AssemblerX8664Test, Div) { |
| 1194 static constexpr uint32_t Mask8 = 0x000000FF; |
| 1195 static constexpr uint32_t Mask16 = 0x0000FFFF; |
| 1196 static constexpr uint32_t Mask32 = 0xFFFFFFFF; |
| 1197 |
| 1198 static constexpr uint64_t Operand0Mask8 = 0x00000000000000FFull; |
| 1199 static constexpr uint64_t Operand0Mask16 = 0x00000000FFFFFFFFull; |
| 1200 static constexpr uint64_t Operand0Mask32 = 0xFFFFFFFFFFFFFFFFull; |
| 1201 |
| 1202 using Operand0Type_int8 = int16_t; |
| 1203 using Operand0Type_uint8 = uint16_t; |
| 1204 using Operand0Type_int16 = int32_t; |
| 1205 using Operand0Type_uint16 = uint32_t; |
| 1206 using Operand0Type_int32 = int64_t; |
| 1207 using Operand0Type_uint32 = uint64_t; |
| 1208 |
| 1209 #define TestImplReg(Inst, Value0, Src, Value1, Type, Size) \ |
| 1210 do { \ |
| 1211 static_assert(Encoded_GPR_eax() != Encoded_GPR_##Src(), \ |
| 1212 "eax can not be src1."); \ |
| 1213 static_assert(Encoded_GPR_edx() != Encoded_GPR_##Src(), \ |
| 1214 "edx can not be src1."); \ |
| 1215 \ |
| 1216 static constexpr char TestString[] = \ |
| 1217 "(" #Inst ", " #Value0 ", " #Src ", " #Value1 ", " #Type ", " #Size \ |
| 1218 ")"; \ |
| 1219 static constexpr Operand0Type_##Type##Size Operand0 = \ |
| 1220 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \ |
| 1221 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \ |
| 1222 static constexpr Type##Size##_t Operand0Hi = \ |
| 1223 (Operand0 >> Size) & Mask##Size; \ |
| 1224 static constexpr Type##Size##_t Operand1 = \ |
| 1225 static_cast<Type##Size##_t>(Value1) & Mask##Size; \ |
| 1226 if (Size == 8) { \ |
| 1227 /* mov Operand0Hi|Operand0Lo, %ah|%al */ \ |
| 1228 __ mov( \ |
| 1229 IceType_i16, Encoded_GPR_eax(), \ |
| 1230 Immediate((static_cast<uint16_t>(Operand0Hi) << 8 | Operand0Lo))); \ |
| 1231 } else { \ |
| 1232 __ mov(IceType_i##Size, Encoded_GPR_eax(), Immediate(Operand0Lo)); \ |
| 1233 __ mov(IceType_i##Size, Encoded_GPR_edx(), Immediate(Operand0Hi)); \ |
| 1234 } \ |
| 1235 __ mov(IceType_i##Size, Encoded_GPR_##Src(), Immediate(Operand1)); \ |
| 1236 __ Inst(IceType_i##Size, Encoded_GPR_##Src()); \ |
| 1237 if (Size == 8) { \ |
| 1238 /* mov %ah, %dl */ \ |
| 1239 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 1240 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 1241 __ And(IceType_i16, Encoded_GPR_eax(), Immediate(0x00FF)); \ |
| 1242 if (Encoded_GPR_##Src() == Encoded_GPR_esi()) { \ |
| 1243 __ And(IceType_i16, Encoded_GPR_edx(), Immediate(0x00FF)); \ |
| 1244 } \ |
| 1245 } \ |
| 1246 \ |
| 1247 AssembledTest test = assemble(); \ |
| 1248 test.run(); \ |
| 1249 \ |
| 1250 static constexpr uint32_t Quocient = (Operand0 / Operand1) & Mask##Size; \ |
| 1251 static constexpr uint32_t Reminder = (Operand0 % Operand1) & Mask##Size; \ |
| 1252 ASSERT_EQ(Quocient, test.eax()) << TestString; \ |
| 1253 ASSERT_EQ(Reminder, test.edx()) << TestString; \ |
| 1254 reset(); \ |
| 1255 } while (0) |
| 1256 |
| 1257 #define TestImplAddr(Inst, Value0, Value1, Type, Size) \ |
| 1258 do { \ |
| 1259 static constexpr char TestString[] = \ |
| 1260 "(" #Inst ", " #Value0 ", Addr, " #Value1 ", " #Type ", " #Size ")"; \ |
| 1261 static constexpr Operand0Type_##Type##Size Operand0 = \ |
| 1262 static_cast<Type##64_t>(Value0) & Operand0Mask##Size; \ |
| 1263 static constexpr Type##Size##_t Operand0Lo = Operand0 & Mask##Size; \ |
| 1264 static constexpr Type##Size##_t Operand0Hi = \ |
| 1265 (Operand0 >> Size) & Mask##Size; \ |
| 1266 const uint32_t T0 = allocateDword(); \ |
| 1267 static constexpr Type##Size##_t V0 = \ |
| 1268 static_cast<Type##Size##_t>(Value1) & Mask##Size; \ |
| 1269 if (Size == 8) { \ |
| 1270 /* mov Operand0Hi|Operand0Lo, %ah|%al */ \ |
| 1271 __ mov( \ |
| 1272 IceType_i16, Encoded_GPR_eax(), \ |
| 1273 Immediate((static_cast<uint16_t>(Operand0Hi) << 8 | Operand0Lo))); \ |
| 1274 } else { \ |
| 1275 __ mov(IceType_i##Size, Encoded_GPR_eax(), Immediate(Operand0Lo)); \ |
| 1276 __ mov(IceType_i##Size, Encoded_GPR_edx(), Immediate(Operand0Hi)); \ |
| 1277 } \ |
| 1278 __ Inst(IceType_i##Size, dwordAddress(T0)); \ |
| 1279 if (Size == 8) { \ |
| 1280 /* mov %ah, %dl */ \ |
| 1281 __ mov(IceType_i16, Encoded_GPR_dx(), Encoded_GPR_ax()); \ |
| 1282 __ shr(IceType_i32, Encoded_GPR_edx(), Immediate(8)); \ |
| 1283 __ And(IceType_i16, Encoded_GPR_eax(), Immediate(0x00FF)); \ |
| 1284 } \ |
| 1285 \ |
| 1286 AssembledTest test = assemble(); \ |
| 1287 test.setDwordTo(T0, static_cast<uint32_t>(V0)); \ |
| 1288 test.run(); \ |
| 1289 \ |
| 1290 static constexpr uint32_t Quocient = (Operand0 / V0) & Mask##Size; \ |
| 1291 static constexpr uint32_t Reminder = (Operand0 % V0) & Mask##Size; \ |
| 1292 ASSERT_EQ(Quocient, test.eax()) << TestString; \ |
| 1293 ASSERT_EQ(Reminder, test.edx()) << TestString; \ |
| 1294 reset(); \ |
| 1295 } while (0) |
| 1296 |
| 1297 #define TestImplOp(Inst, Value0, Src, Value1, Type, Size) \ |
| 1298 do { \ |
| 1299 TestImplReg(Inst, Value0, Src, Value1, Type, Size); \ |
| 1300 TestImplAddr(Inst, Value0, Value1, Type, Size); \ |
| 1301 } while (0) |
| 1302 |
| 1303 #define TestImplValue(Value0, Src, Value1, Size) \ |
| 1304 do { \ |
| 1305 TestImplOp(div, Value0, Src, Value1, uint, Size); \ |
| 1306 TestImplOp(idiv, Value0, Src, Value1, int, Size); \ |
| 1307 } while (0) |
| 1308 |
| 1309 #define TestImplSize(Src, Size) \ |
| 1310 do { \ |
| 1311 TestImplValue(10, Src, 1, Size); \ |
| 1312 TestImplValue(10, Src, -1, Size); \ |
| 1313 } while (0) |
| 1314 |
| 1315 #define TestImpl(Src) \ |
| 1316 do { \ |
| 1317 TestImplSize(Src, 8); \ |
| 1318 TestImplSize(Src, 16); \ |
| 1319 TestImplSize(Src, 32); \ |
| 1320 } while (0) |
| 1321 |
| 1322 TestImpl(r2); |
| 1323 TestImpl(r3); |
| 1324 TestImpl(r5); |
| 1325 TestImpl(r6); |
| 1326 TestImpl(r7); |
| 1327 TestImpl(r8); |
| 1328 TestImpl(r10); |
| 1329 TestImpl(r11); |
| 1330 TestImpl(r12); |
| 1331 TestImpl(r13); |
| 1332 TestImpl(r14); |
| 1333 TestImpl(r15); |
| 1334 |
| 1335 #undef TestImpl |
| 1336 #undef TestImplSize |
| 1337 #undef TestImplValue |
| 1338 #undef TestImplOp |
| 1339 #undef TestImplAddr |
| 1340 #undef TestImplReg |
| 1341 } |
| 1342 |
| 1343 TEST_F(AssemblerX8664Test, Incl_Decl_Addr) { |
| 1344 #define TestImpl(Inst, Value0) \ |
| 1345 do { \ |
| 1346 const bool IsInc = std::string(#Inst).find("incl") != std::string::npos; \ |
| 1347 const uint32_t T0 = allocateDword(); \ |
| 1348 const uint32_t V0 = Value0; \ |
| 1349 \ |
| 1350 __ Inst(dwordAddress(T0)); \ |
| 1351 \ |
| 1352 AssembledTest test = assemble(); \ |
| 1353 test.setDwordTo(T0, V0); \ |
| 1354 test.run(); \ |
| 1355 \ |
| 1356 ASSERT_EQ(static_cast<uint32_t>(Value0 + (IsInc ? 1 : -1)), \ |
| 1357 test.contentsOfDword(T0)); \ |
| 1358 reset(); \ |
| 1359 } while (0) |
| 1360 |
| 1361 #define TestInc(Value0) \ |
| 1362 do { \ |
| 1363 TestImpl(incl, Value0); \ |
| 1364 } while (0) |
| 1365 |
| 1366 #define TestDec(Value0) \ |
| 1367 do { \ |
| 1368 TestImpl(decl, Value0); \ |
| 1369 } while (0) |
| 1370 |
| 1371 TestInc(230); |
| 1372 |
| 1373 TestDec(30); |
| 1374 |
| 1375 #undef TestInc |
| 1376 #undef TestDec |
| 1377 #undef TestImpl |
| 1378 } |
| 1379 |
| 1380 TEST_F(AssemblerX8664Test, Shifts) { |
| 1381 static constexpr uint32_t Mask8 = 0x000000FF; |
| 1382 static constexpr uint32_t Mask16 = 0x0000FFFF; |
| 1383 static constexpr uint32_t Mask32 = 0xFFFFFFFF; |
| 1384 |
| 1385 #define TestImplRegImm(Inst, Dst, Value0, Imm, Op, Type, Size) \ |
| 1386 do { \ |
| 1387 static constexpr char TestString[] = \ |
| 1388 "(" #Inst ", " #Dst ", " #Value0 ", Imm(" #Imm "), " #Op ", " #Type \ |
| 1389 ", " #Size ")"; \ |
| 1390 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \ |
| 1391 const uint##Size##_t Expected = \ |
| 1392 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Imm) | \ |
| 1393 (!IsRol ? 0 : (Value0) >> (Size - Imm))); \ |
| 1394 \ |
| 1395 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1396 Immediate((Value0)&Mask##Size)); \ |
| 1397 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1398 Immediate((Imm)&Mask##Size)); \ |
| 1399 \ |
| 1400 AssembledTest test = assemble(); \ |
| 1401 test.run(); \ |
| 1402 \ |
| 1403 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \ |
| 1404 reset(); \ |
| 1405 } while (0) |
| 1406 |
| 1407 #define TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \ |
| 1408 Type, Size) \ |
| 1409 do { \ |
| 1410 static constexpr char TestString[] = \ |
| 1411 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 \ |
| 1412 ", Imm(" #Count "), " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \ |
| 1413 const uint##Size##_t Expected = \ |
| 1414 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \ |
| 1415 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \ |
| 1416 \ |
| 1417 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1418 Immediate((Value0)&Mask##Size)); \ |
| 1419 __ mov(IceType_i##Size, Encoded_GPR_##Src(), \ |
| 1420 Immediate((Value1)&Mask##Size)); \ |
| 1421 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_##Src(), \ |
| 1422 Immediate(Count)); \ |
| 1423 \ |
| 1424 AssembledTest test = assemble(); \ |
| 1425 test.run(); \ |
| 1426 \ |
| 1427 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \ |
| 1428 reset(); \ |
| 1429 } while (0) |
| 1430 |
| 1431 #define TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size) \ |
| 1432 do { \ |
| 1433 static constexpr char TestString[] = \ |
| 1434 "(" #Inst ", " #Dst ", " #Value0 ", " #Count ", " #Op ", " #Type \ |
| 1435 ", " #Size ")"; \ |
| 1436 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \ |
| 1437 const uint##Size##_t Expected = \ |
| 1438 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \ |
| 1439 (!IsRol ? 0 : Value0 >> (Size - Count))); \ |
| 1440 \ |
| 1441 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1442 Immediate((Value0)&Mask##Size)); \ |
| 1443 __ mov(IceType_i8, Encoded_GPR_ecx(), Immediate((Count)&Mask##Size)); \ |
| 1444 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_ecx()); \ |
| 1445 \ |
| 1446 AssembledTest test = assemble(); \ |
| 1447 test.run(); \ |
| 1448 \ |
| 1449 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \ |
| 1450 reset(); \ |
| 1451 } while (0) |
| 1452 |
| 1453 #define TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, \ |
| 1454 Type, Size) \ |
| 1455 do { \ |
| 1456 static constexpr char TestString[] = \ |
| 1457 "(" #Inst ", " #Dst ", " #Value0 ", " #Src ", " #Value1 ", " #Count \ |
| 1458 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \ |
| 1459 const uint##Size##_t Expected = \ |
| 1460 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \ |
| 1461 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \ |
| 1462 \ |
| 1463 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1464 Immediate((Value0)&Mask##Size)); \ |
| 1465 __ mov(IceType_i##Size, Encoded_GPR_##Src(), \ |
| 1466 Immediate((Value1)&Mask##Size)); \ |
| 1467 __ mov(IceType_i##Size, Encoded_GPR_ecx(), Immediate((Count)&0x7F)); \ |
| 1468 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_##Src()); \ |
| 1469 \ |
| 1470 AssembledTest test = assemble(); \ |
| 1471 test.run(); \ |
| 1472 \ |
| 1473 ASSERT_EQ(static_cast<uint32_t>(Expected), test.Dst()) << TestString; \ |
| 1474 reset(); \ |
| 1475 } while (0) |
| 1476 |
| 1477 #define TestImplAddrCl(Inst, Value0, Count, Op, Type, Size) \ |
| 1478 do { \ |
| 1479 static constexpr char TestString[] = \ |
| 1480 "(" #Inst ", Addr, " #Value0 ", " #Count ", " #Op ", " #Type \ |
| 1481 ", " #Size ")"; \ |
| 1482 const bool IsRol = std::string(#Inst).find("rol") != std::string::npos; \ |
| 1483 const uint##Size##_t Expected = \ |
| 1484 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op(Count) | \ |
| 1485 (!IsRol ? 0 : Value0 >> (Size - Count))); \ |
| 1486 const uint32_t T0 = allocateDword(); \ |
| 1487 const uint32_t V0 = Value0; \ |
| 1488 \ |
| 1489 __ mov(IceType_i8, Encoded_GPR_ecx(), Immediate((Count)&Mask##Size)); \ |
| 1490 __ Inst(IceType_i##Size, dwordAddress(T0), Encoded_GPR_ecx()); \ |
| 1491 \ |
| 1492 AssembledTest test = assemble(); \ |
| 1493 test.setDwordTo(T0, V0); \ |
| 1494 test.run(); \ |
| 1495 \ |
| 1496 ASSERT_EQ(static_cast<uint32_t>(Expected), \ |
| 1497 Mask##Size &test.contentsOfDword(T0)) \ |
| 1498 << TestString; \ |
| 1499 reset(); \ |
| 1500 } while (0) |
| 1501 |
| 1502 #define TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, \ |
| 1503 Size) \ |
| 1504 do { \ |
| 1505 static constexpr char TestString[] = \ |
| 1506 "(" #Inst ", Addr, " #Value0 ", " #Src ", " #Value1 ", " #Count \ |
| 1507 ", " #Op0 ", " #Op1 ", " #Type ", " #Size ")"; \ |
| 1508 const uint##Size##_t Expected = \ |
| 1509 Mask##Size & (static_cast<Type##Size##_t>(Value0) Op0(Count) | \ |
| 1510 (static_cast<Type##64_t>(Value1) Op1(Size - Count))); \ |
| 1511 const uint32_t T0 = allocateDword(); \ |
| 1512 \ |
| 1513 __ mov(IceType_i##Size, Encoded_GPR_##Src(), \ |
| 1514 Immediate((Value1)&Mask##Size)); \ |
| 1515 __ mov(IceType_i##Size, Encoded_GPR_ecx(), Immediate((Count)&0x7F)); \ |
| 1516 __ Inst(IceType_i##Size, dwordAddress(T0), Encoded_GPR_##Src()); \ |
| 1517 \ |
| 1518 AssembledTest test = assemble(); \ |
| 1519 test.setDwordTo(T0, static_cast<uint32_t>(Value0)); \ |
| 1520 test.run(); \ |
| 1521 \ |
| 1522 ASSERT_EQ(static_cast<uint32_t>(Expected), test.contentsOfDword(T0)) \ |
| 1523 << TestString; \ |
| 1524 reset(); \ |
| 1525 } while (0) |
| 1526 |
| 1527 #define TestImplOp(Inst, Dst, Value0, Count, Op, Type, Size) \ |
| 1528 do { \ |
| 1529 static_assert(Encoded_GPR_##Dst() != Encoded_GPR_ecx(), \ |
| 1530 "ecx should not be specified as Dst"); \ |
| 1531 TestImplRegImm(Inst, Dst, Value0, Count, Op, Type, Size); \ |
| 1532 TestImplRegImm(Inst, ecx, Value0, Count, Op, Type, Size); \ |
| 1533 TestImplRegCl(Inst, Dst, Value0, Count, Op, Type, Size); \ |
| 1534 TestImplAddrCl(Inst, Value0, Count, Op, Type, Size); \ |
| 1535 } while (0) |
| 1536 |
| 1537 #define TestImplThreeOperandOp(Inst, Dst, Value0, Src, Value1, Count, Op0, \ |
| 1538 Op1, Type, Size) \ |
| 1539 do { \ |
| 1540 static_assert(Encoded_GPR_##Dst() != Encoded_GPR_ecx(), \ |
| 1541 "ecx should not be specified as Dst"); \ |
| 1542 static_assert(Encoded_GPR_##Src() != Encoded_GPR_ecx(), \ |
| 1543 "ecx should not be specified as Src"); \ |
| 1544 TestImplRegRegImm(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \ |
| 1545 Size); \ |
| 1546 TestImplRegRegCl(Inst, Dst, Value0, Src, Value1, Count, Op0, Op1, Type, \ |
| 1547 Size); \ |
| 1548 TestImplAddrRegCl(Inst, Value0, Src, Value1, Count, Op0, Op1, Type, Size); \ |
| 1549 } while (0) |
| 1550 |
| 1551 #define TestImplValue(Dst, Value0, Count, Size) \ |
| 1552 do { \ |
| 1553 TestImplOp(rol, Dst, Value0, Count, <<, uint, Size); \ |
| 1554 TestImplOp(shl, Dst, Value0, Count, <<, uint, Size); \ |
| 1555 TestImplOp(shr, Dst, Value0, Count, >>, uint, Size); \ |
| 1556 TestImplOp(sar, Dst, Value0, Count, >>, int, Size); \ |
| 1557 } while (0) |
| 1558 |
| 1559 #define TestImplThreeOperandValue(Dst, Value0, Src, Value1, Count, Size) \ |
| 1560 do { \ |
| 1561 TestImplThreeOperandOp(shld, Dst, Value0, Src, Value1, Count, <<, >>, \ |
| 1562 uint, Size); \ |
| 1563 TestImplThreeOperandOp(shrd, Dst, Value0, Src, Value1, Count, >>, <<, \ |
| 1564 uint, Size); \ |
| 1565 } while (0) |
| 1566 |
| 1567 #define TestImplSize(Dst, Size) \ |
| 1568 do { \ |
| 1569 TestImplValue(Dst, 0x8F, 3, Size); \ |
| 1570 TestImplValue(Dst, 0x8FFF, 7, Size); \ |
| 1571 TestImplValue(Dst, 0x8FFFF, 7, Size); \ |
| 1572 } while (0) |
| 1573 |
| 1574 #define TestImplThreeOperandSize(Dst, Src, Size) \ |
| 1575 do { \ |
| 1576 TestImplThreeOperandValue(Dst, 0xFFF3, Src, 0xA000, 8, Size); \ |
| 1577 } while (0) |
| 1578 |
| 1579 #define TestImpl(Dst, Src) \ |
| 1580 do { \ |
| 1581 TestImplSize(Dst, 8); \ |
| 1582 TestImplSize(Dst, 16); \ |
| 1583 TestImplThreeOperandSize(Dst, Src, 16); \ |
| 1584 TestImplSize(Dst, 32); \ |
| 1585 TestImplThreeOperandSize(Dst, Src, 32); \ |
| 1586 } while (0) |
| 1587 |
| 1588 TestImpl(r1, r2); |
| 1589 TestImpl(r2, r4); |
| 1590 TestImpl(r4, r5); |
| 1591 TestImpl(r5, r6); |
| 1592 TestImpl(r6, r7); |
| 1593 TestImpl(r7, r8); |
| 1594 TestImpl(r8, r10); |
| 1595 TestImpl(r10, r11); |
| 1596 TestImpl(r11, r12); |
| 1597 TestImpl(r12, r13); |
| 1598 TestImpl(r13, r14); |
| 1599 TestImpl(r14, r15); |
| 1600 TestImpl(r15, r1); |
| 1601 |
| 1602 #undef TestImpl |
| 1603 #undef TestImplThreeOperandSize |
| 1604 #undef TestImplSize |
| 1605 #undef TestImplValue |
| 1606 #undef TestImplThreeOperandValue |
| 1607 #undef TestImplOp |
| 1608 #undef TestImplThreeOperandOp |
| 1609 #undef TestImplAddrCl |
| 1610 #undef TestImplRegRegCl |
| 1611 #undef TestImplRegCl |
| 1612 #undef TestImplRegRegImm |
| 1613 #undef TestImplRegImm |
| 1614 } |
| 1615 |
| 1616 TEST_F(AssemblerX8664Test, Neg) { |
| 1617 static constexpr uint32_t Mask8 = 0x000000ff; |
| 1618 static constexpr uint32_t Mask16 = 0x0000ffff; |
| 1619 static constexpr uint32_t Mask32 = 0xffffffff; |
| 1620 |
| 1621 #define TestImplReg(Dst, Size) \ |
| 1622 do { \ |
| 1623 static constexpr int32_t Value = 0xFF00A543; \ |
| 1624 __ mov(IceType_i##Size, Encoded_GPR_##Dst(), \ |
| 1625 Immediate(static_cast<int##Size##_t>(Value) & Mask##Size)); \ |
| 1626 __ neg(IceType_i##Size, Encoded_GPR_##Dst()); \ |
| 1627 __ mov(IceType_i##Size, Encoded_GPR_eax(), Encoded_GPR_##Dst()); \ |
| 1628 __ And(IceType_i32, Encoded_GPR_eax(), Immediate(Mask##Size)); \ |
| 1629 \ |
| 1630 AssembledTest test = assemble(); \ |
| 1631 test.run(); \ |
| 1632 \ |
| 1633 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \ |
| 1634 test.eax()) \ |
| 1635 << "(" #Dst ", " #Size ")"; \ |
| 1636 reset(); \ |
| 1637 } while (0) |
| 1638 |
| 1639 #define TestImplAddr(Size) \ |
| 1640 do { \ |
| 1641 static constexpr int32_t Value = 0xFF00A543; \ |
| 1642 const uint32_t T0 = allocateDword(); \ |
| 1643 __ neg(IceType_i##Size, dwordAddress(T0)); \ |
| 1644 \ |
| 1645 AssembledTest test = assemble(); \ |
| 1646 test.setDwordTo(T0, Value &Mask##Size); \ |
| 1647 test.run(); \ |
| 1648 \ |
| 1649 ASSERT_EQ(1 + (~static_cast<int##Size##_t>(Value) & Mask##Size), \ |
| 1650 test.contentsOfDword(T0)) \ |
| 1651 << "(Addr, " #Size ")"; \ |
| 1652 reset(); \ |
| 1653 } while (0) |
| 1654 |
| 1655 #define TestImpl(Size) \ |
| 1656 do { \ |
| 1657 TestImplAddr(Size); \ |
| 1658 TestImplReg(r1, Size); \ |
| 1659 TestImplReg(r2, Size); \ |
| 1660 TestImplReg(r3, Size); \ |
| 1661 TestImplReg(r4, Size); \ |
| 1662 TestImplReg(r5, Size); \ |
| 1663 TestImplReg(r6, Size); \ |
| 1664 TestImplReg(r7, Size); \ |
| 1665 TestImplReg(r8, Size); \ |
| 1666 TestImplReg(r10, Size); \ |
| 1667 TestImplReg(r11, Size); \ |
| 1668 TestImplReg(r12, Size); \ |
| 1669 TestImplReg(r13, Size); \ |
| 1670 TestImplReg(r14, Size); \ |
| 1671 TestImplReg(r15, Size); \ |
| 1672 } while (0) |
| 1673 |
| 1674 TestImpl(8); |
| 1675 TestImpl(16); |
| 1676 TestImpl(32); |
| 1677 |
| 1678 #undef TestImpl |
| 1679 #undef TestImplAddr |
| 1680 #undef TestImplReg |
| 1681 } |
| 1682 |
| 1683 TEST_F(AssemblerX8664Test, Not) { |
| 1684 #define TestImpl(Dst) \ |
| 1685 do { \ |
| 1686 static constexpr uint32_t Value = 0xFF00A543; \ |
| 1687 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(Value)); \ |
| 1688 __ notl(Encoded_GPR_##Dst()); \ |
| 1689 \ |
| 1690 AssembledTest test = assemble(); \ |
| 1691 test.run(); \ |
| 1692 \ |
| 1693 ASSERT_EQ(~Value, test.Dst()) << "(" #Dst ")"; \ |
| 1694 reset(); \ |
| 1695 } while (0) |
| 1696 |
| 1697 TestImpl(r1); |
| 1698 TestImpl(r2); |
| 1699 TestImpl(r3); |
| 1700 TestImpl(r4); |
| 1701 TestImpl(r5); |
| 1702 TestImpl(r6); |
| 1703 TestImpl(r7); |
| 1704 TestImpl(r8); |
| 1705 TestImpl(r10); |
| 1706 TestImpl(r11); |
| 1707 TestImpl(r12); |
| 1708 TestImpl(r13); |
| 1709 TestImpl(r14); |
| 1710 TestImpl(r15); |
| 1711 |
| 1712 #undef TestImpl |
| 1713 } |
| 1714 |
| 1715 TEST_F(AssemblerX8664Test, Bswap) { |
| 1716 #define TestImpl(Dst) \ |
| 1717 do { \ |
| 1718 static constexpr uint32_t Value = 0xFF00A543; \ |
| 1719 static constexpr uint32_t Expected = 0x43A500FF; \ |
| 1720 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(Value)); \ |
| 1721 __ bswap(IceType_i32, Encoded_GPR_##Dst()); \ |
| 1722 \ |
| 1723 AssembledTest test = assemble(); \ |
| 1724 test.run(); \ |
| 1725 \ |
| 1726 ASSERT_EQ(Expected, test.Dst()) << "(" #Dst ")"; \ |
| 1727 reset(); \ |
| 1728 } while (0) |
| 1729 |
| 1730 TestImpl(r1); |
| 1731 TestImpl(r2); |
| 1732 TestImpl(r3); |
| 1733 TestImpl(r4); |
| 1734 TestImpl(r5); |
| 1735 TestImpl(r6); |
| 1736 TestImpl(r7); |
| 1737 TestImpl(r8); |
| 1738 TestImpl(r10); |
| 1739 TestImpl(r11); |
| 1740 TestImpl(r12); |
| 1741 TestImpl(r13); |
| 1742 TestImpl(r14); |
| 1743 TestImpl(r15); |
| 1744 |
| 1745 #undef TestImpl |
| 1746 } |
| 1747 |
| 1748 TEST_F(AssemblerX8664Test, Bt) { |
| 1749 #define TestImpl(Dst, Value0, Src, Value1) \ |
| 1750 do { \ |
| 1751 static constexpr char TestString[] = \ |
| 1752 "(" #Dst ", " #Value0 ", " #Src ", " #Value1 ")"; \ |
| 1753 static constexpr uint32_t Expected = ((Value0) & (1u << (Value1))) != 0; \ |
| 1754 \ |
| 1755 __ mov(IceType_i32, Encoded_GPR_##Dst(), Immediate(Value0)); \ |
| 1756 __ mov(IceType_i32, Encoded_GPR_##Src(), Immediate(Value1)); \ |
| 1757 __ bt(Encoded_GPR_##Dst(), Encoded_GPR_##Src()); \ |
| 1758 __ setcc(Cond::Br_b, ByteRegister::Encoded_Reg_al); \ |
| 1759 __ And(IceType_i32, Encoded_GPR_eax(), Immediate(0xFFu)); \ |
| 1760 \ |
| 1761 AssembledTest test = assemble(); \ |
| 1762 test.run(); \ |
| 1763 \ |
| 1764 ASSERT_EQ(Expected, test.eax()) << TestString; \ |
| 1765 reset(); \ |
| 1766 } while (0) |
| 1767 |
| 1768 TestImpl(r1, 0x08000000, r2, 27u); |
| 1769 TestImpl(r2, 0x08000000, r3, 23u); |
| 1770 TestImpl(r3, 0x00000000, r4, 1u); |
| 1771 TestImpl(r4, 0x08000300, r5, 9u); |
| 1772 TestImpl(r5, 0x08000300, r6, 10u); |
| 1773 TestImpl(r6, 0x7FFFEFFF, r7, 13u); |
| 1774 TestImpl(r7, 0x08000000, r8, 27u); |
| 1775 TestImpl(r8, 0x08000000, r10, 23u); |
| 1776 TestImpl(r10, 0x00000000, r11, 1u); |
| 1777 TestImpl(r11, 0x08000300, r12, 9u); |
| 1778 TestImpl(r12, 0x08000300, r13, 10u); |
| 1779 TestImpl(r13, 0x7FFFEFFF, r14, 13u); |
| 1780 TestImpl(r14, 0x08000000, r15, 27u); |
| 1781 TestImpl(r15, 0x08000000, r1, 23u); |
| 1782 |
| 1783 #undef TestImpl |
| 1784 } |
| 1785 |
| 1786 template <uint32_t Value, uint32_t Bits> class BitScanHelper { |
| 1787 BitScanHelper() = delete; |
| 1788 |
| 1789 public: |
| 1790 static_assert(Bits == 16 || Bits == 32, "Bits must be 16 or 32"); |
| 1791 using ValueType = |
| 1792 typename std::conditional<Bits == 16, uint16_t, uint32_t>::type; |
| 1793 |
| 1794 private: |
| 1795 static constexpr ValueType BitIndex(bool Forward, ValueType Index) { |
| 1796 return (Value == 0) |
| 1797 ? BitScanHelper<Value, Bits>::NoBitSet |
| 1798 : (Value & (1u << Index) |
| 1799 ? Index |
| 1800 : BitIndex(Forward, (Forward ? Index + 1 : Index - 1))); |
| 1801 } |
| 1802 |
| 1803 public: |
| 1804 static constexpr ValueType NoBitSet = static_cast<ValueType>(-1); |
| 1805 static constexpr ValueType bsf = BitIndex(/*Forward*/ true, /*Index=*/0); |
| 1806 static constexpr ValueType bsr = |
| 1807 BitIndex(/*Forward*/ false, /*Index=*/Bits - 1); |
| 1808 }; |
| 1809 |
| 1810 TEST_F(AssemblerX8664Test, BitScanOperations) { |
| 1811 #define TestImplRegReg(Inst, Dst, Src, Value1, Size) \ |
| 1812 do { \ |
| 1813 static constexpr char TestString[] = \ |
| 1814 "(" #Inst ", " #Dst ", " #Src ", " #Value1 ", " #Size ")"; \ |
| 1815 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \ |
| 1816 const uint32_t ZeroFlag = allocateDword(); \ |
| 1817 __ mov(IceType_i##Size, Encoded_GPR_##Src(), Immediate(Value1)); \ |
| 1818 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), Encoded_GPR_##Src()); \ |
| 1819 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \ |
| 1820 \ |
| 1821 AssembledTest test = assemble(); \ |
| 1822 test.setDwordTo(ZeroFlag, 0u); \ |
| 1823 test.run(); \ |
| 1824 \ |
| 1825 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \ |
| 1826 test.contentsOfDword(ZeroFlag)) \ |
| 1827 << TestString; \ |
| 1828 if ((Expected != BitScanHelper<Value1, Size>::NoBitSet)) { \ |
| 1829 ASSERT_EQ(Expected, test.Dst()) << TestString; \ |
| 1830 } \ |
| 1831 reset(); \ |
| 1832 } while (0) |
| 1833 |
| 1834 #define TestImplRegAddr(Inst, Dst, Value1, Size) \ |
| 1835 do { \ |
| 1836 static constexpr char TestString[] = \ |
| 1837 "(" #Inst ", " #Dst ", Addr, " #Value1 ", " #Size ")"; \ |
| 1838 static constexpr uint32_t Expected = BitScanHelper<Value1, Size>::Inst; \ |
| 1839 const uint32_t T0 = allocateDword(); \ |
| 1840 const uint32_t ZeroFlag = allocateDword(); \ |
| 1841 __ Inst(IceType_i##Size, Encoded_GPR_##Dst(), dwordAddress(T0)); \ |
| 1842 __ setcc(Cond::Br_e, dwordAddress(ZeroFlag)); \ |
| 1843 \ |
| 1844 AssembledTest test = assemble(); \ |
| 1845 test.setDwordTo(T0, Value1); \ |
| 1846 test.setDwordTo(ZeroFlag, 0u); \ |
| 1847 test.run(); \ |
| 1848 \ |
| 1849 ASSERT_EQ((Expected == BitScanHelper<Value1, Size>::NoBitSet), \ |
| 1850 test.contentsOfDword(ZeroFlag)) \ |
| 1851 << TestString; \ |
| 1852 if (Expected != BitScanHelper<Value1, Size>::NoBitSet) { \ |
| 1853 ASSERT_EQ(Expected, test.Dst()) << TestString; \ |
| 1854 } \ |
| 1855 reset(); \ |
| 1856 } while (0) |
| 1857 |
| 1858 #define TestImplSize(Dst, Src, Value1, Size) \ |
| 1859 do { \ |
| 1860 TestImplRegReg(bsf, Dst, Src, Value1, Size); \ |
| 1861 TestImplRegAddr(bsf, Dst, Value1, Size); \ |
| 1862 TestImplRegReg(bsr, Dst, Src, Value1, Size); \ |
| 1863 TestImplRegAddr(bsf, Dst, Value1, Size); \ |
| 1864 } while (0) |
| 1865 |
| 1866 #define TestImplValue(Dst, Src, Value1) \ |
| 1867 do { \ |
| 1868 TestImplSize(Dst, Src, Value1, 16); \ |
| 1869 TestImplSize(Dst, Src, Value1, 32); \ |
| 1870 } while (0) |
| 1871 |
| 1872 #define TestImpl(Dst, Src) \ |
| 1873 do { \ |
| 1874 TestImplValue(Dst, Src, 0x80000001); \ |
| 1875 TestImplValue(Dst, Src, 0x00000000); \ |
| 1876 TestImplValue(Dst, Src, 0x80001000); \ |
| 1877 TestImplValue(Dst, Src, 0x00FFFF00); \ |
| 1878 } while (0) |
| 1879 |
| 1880 TestImpl(r1, r2); |
| 1881 TestImpl(r2, r3); |
| 1882 TestImpl(r3, r4); |
| 1883 TestImpl(r4, r5); |
| 1884 TestImpl(r5, r6); |
| 1885 TestImpl(r6, r7); |
| 1886 TestImpl(r7, r8); |
| 1887 TestImpl(r8, r10); |
| 1888 TestImpl(r10, r11); |
| 1889 TestImpl(r11, r12); |
| 1890 TestImpl(r12, r13); |
| 1891 TestImpl(r13, r14); |
| 1892 TestImpl(r14, r15); |
| 1893 TestImpl(r15, r1); |
| 1894 |
| 1895 #undef TestImpl |
| 1896 #undef TestImplValue |
| 1897 #undef TestImplSize |
| 1898 #undef TestImplRegAddr |
| 1899 #undef TestImplRegReg |
| 1900 } |
| 1901 |
| 1902 } // end of anonymous namespace |
| 1903 } // end of namespace Test |
| 1904 } // end of namespace X8664 |
| 1905 } // end of namespace Ice |
| OLD | NEW |