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