Changeset 249747 in webkit
- Timestamp:
- Sep 10, 2019 5:46:32 PM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r249743 r249747 1 2019-09-10 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] 32bit bitwide operation with all-one (-1) is wrong in B3 4 https://bugs.webkit.org/show_bug.cgi?id=201634 5 6 Reviewed by Mark Lam and Robin Morisset. 7 8 This patch includes two things. One is fixing 32bit bitwise operation with allOne constants. Another is fixing the existing bug in BitAnd strength reduction. 9 10 1. 32bit bitwise operation with allOne constants 11 12 Accidentally, the B3::Value is ConstInt32(-1), `value->isInt(std::numeric_limits<uint32_t>::max())` returns `false`! 13 For example, in BitAnd strength reduction, 14 15 1034 // Turn this: BitAnd(value, all-ones) 16 1035 // Into this: value. 17 1036 if ((m_value->type() == Int64 && m_value->child(1)->isInt(std::numeric_limits<uint64_t>::max())) 18 1037 || (m_value->type() == Int32 && m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max()))) { 19 1038 replaceWithIdentity(m_value->child(0)); 20 1039 break; 21 1040 } 22 23 We use `m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max())`. However, Value::isInt is, 24 25 262 inline bool Value::isInt(int64_t value) const 26 263 { 27 264 return hasInt() && asInt() == value; 28 265 } 29 30 So, UINT32_MAX is expanded to int64_t, but it is not -1 since UINT32_MAX can be representable in int64_t. And Value::asInt implementation is, 31 32 257 inline int64_t Value::asInt() const 33 258 { 34 259 return hasInt32() ? asInt32() : asInt64(); 35 260 } 36 37 So, we perform `static_cast<int64_t>(-1) == static_cast<int64_t>(UINT32_MAX)`. This is false, but this comparison is not what we want! 38 We should use `isInt32` and `isInt64` for bit patterns (like, operands for Bitwise opcodes). 39 40 2. BitAnd and BitOr strength reduction bug 41 42 We also fix the following optimization. 43 44 // Turn this: BitAnd(Op(value, constant1), constant2) 45 // where !(constant1 & constant2) 46 // and Op is BitOr or BitXor 47 // into this: BitAnd(value, constant2) 48 49 Since we stop further optimization when we match `if (m_value->child(1)->hasInt())`, the following optimization is never taken. 50 51 // Turn this: BitAnd(BitXor(x, allOnes), c) 52 // Into this: BitXor(BitOr(x, ~c), allOnes) 53 54 And we also found that this not-used optimization has a bug not inserting a newly produced constant B3::Value. This patch also fixes it. 55 56 For both, this patch adds tests. And (2) fix can be ensured that the testb3 does not crash with validate-graph option. 57 58 * b3/B3LowerToAir.cpp: 59 * b3/B3ReduceStrength.cpp: 60 * b3/testb3.h: 61 * b3/testb3_2.cpp: 62 (testBitAndNotNot32): 63 (testBitAndNotImm): 64 (testBitAndNotImm32): 65 (testBitOrAndAndArgs32): 66 (testBitOrAndSameArgs32): 67 (testBitOrNotNot32): 68 (testBitOrNotImm32): 69 (addBitTests): 70 * b3/testb3_3.cpp: 71 (testBitXorAndAndArgs32): 72 (testBitXorAndSameArgs32): 73 1 74 2019-09-10 Commit Queue <commit-queue@webkit.org> 2 75 -
trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp
r249743 r249747 2750 2750 } 2751 2751 2752 if (m_value->child(1)->isInt (0xffffffff)) {2752 if (m_value->child(1)->isInt64(0xffffffff) || m_value->child(1)->isInt32(0xffffffff)) { 2753 2753 appendUnOp<Move32, Move32>(m_value->child(0)); 2754 2754 return; -
trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp
r249743 r249747 1034 1034 // Turn this: BitAnd(value, all-ones) 1035 1035 // Into this: value. 1036 if ((m_value->type() == Int64 && m_value->child(1)->isInt (std::numeric_limits<uint64_t>::max()))1037 || (m_value->type() == Int32 && m_value->child(1)->isInt (std::numeric_limits<uint32_t>::max()))) {1036 if ((m_value->type() == Int64 && m_value->child(1)->isInt64(std::numeric_limits<uint64_t>::max())) 1037 || (m_value->type() == Int32 && m_value->child(1)->isInt32(std::numeric_limits<uint32_t>::max()))) { 1038 1038 replaceWithIdentity(m_value->child(0)); 1039 1039 break; … … 1084 1084 // into this: BitAnd(value, constant2) 1085 1085 if (m_value->child(1)->hasInt()) { 1086 bool replaced = false; 1086 1087 int64_t constant2 = m_value->child(1)->asInt(); 1087 1088 switch (m_value->child(0)->opcode()) { … … 1092 1093 m_value->child(0) = m_value->child(0)->child(0); 1093 1094 m_changed = true; 1095 replaced = true; 1094 1096 break; 1095 1097 } … … 1098 1100 break; 1099 1101 } 1100 break; 1102 if (replaced) 1103 break; 1101 1104 } 1102 1105 … … 1107 1110 && m_value->child(1)->opcode() == BitXor 1108 1111 && ((m_value->type() == Int64 1109 && m_value->child(0)->child(1)->isInt (std::numeric_limits<uint64_t>::max())1110 && m_value->child(1)->child(1)->isInt (std::numeric_limits<uint64_t>::max()))1112 && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max()) 1113 && m_value->child(1)->child(1)->isInt64(std::numeric_limits<uint64_t>::max())) 1111 1114 || (m_value->type() == Int32 1112 && m_value->child(0)->child(1)->isInt (std::numeric_limits<uint32_t>::max())1113 && m_value->child(1)->child(1)->isInt (std::numeric_limits<uint32_t>::max())))) {1115 && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max()) 1116 && m_value->child(1)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) { 1114 1117 Value* bitOr = m_insertionSet.insert<Value>(m_index, BitOr, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->child(0)); 1115 1118 replaceWithNew<Value>(BitXor, m_value->origin(), bitOr, m_value->child(1)->child(1)); … … 1124 1127 && m_value->child(1)->hasInt() 1125 1128 && ((m_value->type() == Int64 1126 && m_value->child(0)->child(1)->isInt (std::numeric_limits<uint64_t>::max()))1129 && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max())) 1127 1130 || (m_value->type() == Int32 1128 && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint32_t>::max())))) { 1129 Value* bitOr = m_insertionSet.insert<Value>(m_index, BitOr, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1))); 1131 && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) { 1132 Value* newConstant = m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1)); 1133 ASSERT(newConstant); 1134 m_insertionSet.insertValue(m_index, newConstant); 1135 Value* bitOr = m_insertionSet.insert<Value>(m_index, BitOr, m_value->origin(), m_value->child(0)->child(0), newConstant); 1130 1136 replaceWithNew<Value>(BitXor, m_value->origin(), bitOr, m_value->child(0)->child(1)); 1131 1137 break; … … 1172 1178 // Turn this: BitOr(value, all-ones) 1173 1179 // Into this: all-ones. 1174 if ((m_value->type() == Int64 && m_value->child(1)->isInt (std::numeric_limits<uint64_t>::max()))1175 || (m_value->type() == Int32 && m_value->child(1)->isInt (std::numeric_limits<uint32_t>::max()))) {1180 if ((m_value->type() == Int64 && m_value->child(1)->isInt64(std::numeric_limits<uint64_t>::max())) 1181 || (m_value->type() == Int32 && m_value->child(1)->isInt32(std::numeric_limits<uint32_t>::max()))) { 1176 1182 replaceWithIdentity(m_value->child(1)); 1177 1183 break; … … 1184 1190 && m_value->child(1)->opcode() == BitXor 1185 1191 && ((m_value->type() == Int64 1186 && m_value->child(0)->child(1)->isInt (std::numeric_limits<uint64_t>::max())1187 && m_value->child(1)->child(1)->isInt (std::numeric_limits<uint64_t>::max()))1192 && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max()) 1193 && m_value->child(1)->child(1)->isInt64(std::numeric_limits<uint64_t>::max())) 1188 1194 || (m_value->type() == Int32 1189 && m_value->child(0)->child(1)->isInt (std::numeric_limits<uint32_t>::max())1190 && m_value->child(1)->child(1)->isInt (std::numeric_limits<uint32_t>::max())))) {1195 && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max()) 1196 && m_value->child(1)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) { 1191 1197 Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->child(0)); 1192 1198 replaceWithNew<Value>(BitXor, m_value->origin(), bitAnd, m_value->child(1)->child(1)); … … 1201 1207 && m_value->child(1)->hasInt() 1202 1208 && ((m_value->type() == Int64 1203 && m_value->child(0)->child(1)->isInt (std::numeric_limits<uint64_t>::max()))1209 && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max())) 1204 1210 || (m_value->type() == Int32 1205 && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint32_t>::max())))) { 1206 Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1))); 1211 && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) { 1212 Value* newConstant = m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1)); 1213 ASSERT(newConstant); 1214 m_insertionSet.insertValue(m_index, newConstant); 1215 Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(), m_value->child(0)->child(0), newConstant); 1207 1216 replaceWithNew<Value>(BitXor, m_value->origin(), bitAnd, m_value->child(0)->child(1)); 1208 1217 break; -
trunk/Source/JavaScriptCore/b3/testb3.h
r249743 r249747 460 460 void testBitXorSameArg(int64_t); 461 461 void testBitXorAndAndArgs(int64_t, int64_t, int64_t c); 462 void testBitXorAndAndArgs32(int32_t, int32_t, int32_t c); 462 463 void testBitXorAndSameArgs(int64_t, int64_t); 464 void testBitXorAndSameArgs32(int32_t, int32_t); 463 465 void testBitXorImms(int64_t, int64_t); 464 466 void testBitXorArgImm(int64_t, int64_t); -
trunk/Source/JavaScriptCore/b3/testb3_2.cpp
r249743 r249747 2566 2566 } 2567 2567 2568 static void testBitAndNotNot32(int32_t a, int32_t b) 2569 { 2570 Procedure proc; 2571 BasicBlock* root = proc.addBlock(); 2572 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 2573 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 2574 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1)); 2575 Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1)); 2576 root->appendNewControlValue( 2577 proc, Return, Origin(), 2578 root->appendNew<Value>( 2579 proc, BitAnd, Origin(), 2580 notA, 2581 notB)); 2582 2583 CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a & ~b)); 2584 } 2585 2568 2586 static void testBitAndNotImm(int64_t a, int64_t b) 2569 2587 { … … 2580 2598 cstB)); 2581 2599 2582 CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & b)); 2600 CHECK_EQ(compileAndRun<int64_t>(proc, a), (~a & b)); 2601 } 2602 2603 static void testBitAndNotImm32(int32_t a, int32_t b) 2604 { 2605 Procedure proc; 2606 BasicBlock* root = proc.addBlock(); 2607 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 2608 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1)); 2609 Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b); 2610 root->appendNewControlValue( 2611 proc, Return, Origin(), 2612 root->appendNew<Value>( 2613 proc, BitAnd, Origin(), 2614 notA, 2615 cstB)); 2616 2617 CHECK_EQ(compileAndRun<int32_t>(proc, a), (~a & b)); 2583 2618 } 2584 2619 … … 2995 3030 } 2996 3031 3032 static void testBitOrAndAndArgs32(int32_t a, int32_t b, int32_t c) 3033 { 3034 // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength): 3035 // ((a & b) | (a & c)) 3036 // ((a & b) | (c & a)) 3037 // ((b & a) | (a & c)) 3038 // ((b & a) | (c & a)) 3039 for (int i = 0; i < 4; ++i) { 3040 Procedure proc; 3041 BasicBlock* root = proc.addBlock(); 3042 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3043 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3044 Value* argC = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); 3045 Value* andAB = i & 2 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB) 3046 : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA); 3047 Value* andAC = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argC) 3048 : root->appendNew<Value>(proc, BitAnd, Origin(), argC, argA); 3049 root->appendNewControlValue( 3050 proc, Return, Origin(), 3051 root->appendNew<Value>( 3052 proc, BitOr, Origin(), 3053 andAB, 3054 andAC)); 3055 3056 CHECK_EQ(compileAndRun<int32_t>(proc, a, b, c), ((a & b) | (a & c))); 3057 } 3058 } 3059 2997 3060 static void testBitOrAndSameArgs(int64_t a, int64_t b) 2998 3061 { … … 3017 3080 } 3018 3081 3082 static void testBitOrAndSameArgs32(int32_t a, int32_t b) 3083 { 3084 // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength): 3085 // ((a & b) | a) 3086 // ((b & a) | a) 3087 // (a | (a & b)) 3088 // (a | (b & a)) 3089 for (int i = 0; i < 4; ++i) { 3090 Procedure proc; 3091 BasicBlock* root = proc.addBlock(); 3092 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3093 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3094 Value* andAB = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB) 3095 : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA); 3096 Value* result = i & 2 ? root->appendNew<Value>(proc, BitOr, Origin(), andAB, argA) 3097 : root->appendNew<Value>(proc, BitOr, Origin(), argA, andAB); 3098 root->appendNewControlValue(proc, Return, Origin(), result); 3099 3100 CHECK_EQ(compileAndRun<int32_t>(proc, a, b), ((a & b) | a)); 3101 } 3102 } 3103 3019 3104 static void testBitOrNotNot(int64_t a, int64_t b) 3020 3105 { … … 3035 3120 } 3036 3121 3122 static void testBitOrNotNot32(int32_t a, int32_t b) 3123 { 3124 Procedure proc; 3125 BasicBlock* root = proc.addBlock(); 3126 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3127 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 3128 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1)); 3129 Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1)); 3130 root->appendNewControlValue( 3131 proc, Return, Origin(), 3132 root->appendNew<Value>( 3133 proc, BitOr, Origin(), 3134 notA, 3135 notB)); 3136 3137 CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a | ~b)); 3138 } 3139 3037 3140 static void testBitOrNotImm(int64_t a, int64_t b) 3038 3141 { … … 3050 3153 3051 3154 CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | b)); 3155 } 3156 3157 static void testBitOrNotImm32(int32_t a, int32_t b) 3158 { 3159 Procedure proc; 3160 BasicBlock* root = proc.addBlock(); 3161 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 3162 Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1)); 3163 Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b); 3164 root->appendNewControlValue( 3165 proc, Return, Origin(), 3166 root->appendNew<Value>( 3167 proc, BitOr, Origin(), 3168 notA, 3169 cstB)); 3170 3171 CHECK_EQ(compileAndRun<int32_t>(proc, a), (~a | b)); 3052 3172 } 3053 3173 … … 3288 3408 RUN_BINARY(testBitAndArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); 3289 3409 RUN_BINARY(testBitAndNotNot, int64Operands(), int64Operands()); 3410 RUN_BINARY(testBitAndNotNot32, int32Operands(), int32Operands()); 3290 3411 RUN_BINARY(testBitAndNotImm, int64Operands(), int64Operands()); 3412 RUN_BINARY(testBitAndNotImm32, int32Operands(), int32Operands()); 3291 3413 3292 3414 RUN(testBitOrArgs(43, 43)); … … 3352 3474 RUN_BINARY(testBitOrArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); 3353 3475 RUN_TERNARY(testBitOrAndAndArgs, int64Operands(), int64Operands(), int64Operands()); 3476 RUN_TERNARY(testBitOrAndAndArgs32, int32Operands(), int32Operands(), int32Operands()); 3354 3477 RUN_BINARY(testBitOrAndSameArgs, int64Operands(), int64Operands()); 3478 RUN_BINARY(testBitOrAndSameArgs32, int32Operands(), int32Operands()); 3355 3479 RUN_BINARY(testBitOrNotNot, int64Operands(), int64Operands()); 3480 RUN_BINARY(testBitOrNotNot32, int32Operands(), int32Operands()); 3356 3481 RUN_BINARY(testBitOrNotImm, int64Operands(), int64Operands()); 3482 RUN_BINARY(testBitOrNotImm32, int32Operands(), int32Operands()); 3357 3483 3358 3484 RUN_BINARY(testBitXorArgs, int64Operands(), int64Operands()); … … 3394 3520 RUN(testBitXorImmBitXorArgImm32(24, 0xffff, 7)); 3395 3521 RUN_TERNARY(testBitXorAndAndArgs, int64Operands(), int64Operands(), int64Operands()); 3522 RUN_TERNARY(testBitXorAndAndArgs32, int32Operands(), int32Operands(), int32Operands()); 3396 3523 RUN_BINARY(testBitXorAndSameArgs, int64Operands(), int64Operands()); 3524 RUN_BINARY(testBitXorAndSameArgs32, int32Operands(), int32Operands()); 3397 3525 3398 3526 RUN_UNARY(testBitNotArg, int64Operands()); -
trunk/Source/JavaScriptCore/b3/testb3_3.cpp
r249743 r249747 260 260 } 261 261 262 void testBitXorAndAndArgs32(int32_t a, int32_t b, int32_t c) 263 { 264 // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength): 265 // ((a & b) ^ (a & c)) 266 // ((a & b) ^ (c & a)) 267 // ((b & a) ^ (a & c)) 268 // ((b & a) ^ (c & a)) 269 for (int i = 0; i < 4; ++i) { 270 Procedure proc; 271 BasicBlock* root = proc.addBlock(); 272 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 273 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 274 Value* argC = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)); 275 Value* andAB = i & 2 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB) 276 : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA); 277 Value* andAC = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argC) 278 : root->appendNew<Value>(proc, BitAnd, Origin(), argC, argA); 279 root->appendNewControlValue( 280 proc, Return, Origin(), 281 root->appendNew<Value>( 282 proc, BitXor, Origin(), 283 andAB, 284 andAC)); 285 286 CHECK_EQ(compileAndRun<int32_t>(proc, a, b, c), ((a & b) ^ (a & c))); 287 } 288 } 289 262 290 void testBitXorAndSameArgs(int64_t a, int64_t b) 263 291 { … … 279 307 280 308 CHECK_EQ(compileAndRun<int64_t>(proc, a, b), ((a & b) ^ a)); 309 } 310 } 311 312 void testBitXorAndSameArgs32(int32_t a, int32_t b) 313 { 314 // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength): 315 // ((a & b) ^ a) 316 // ((b & a) ^ a) 317 // (a ^ (a & b)) 318 // (a ^ (b & a)) 319 for (int i = 0; i < 4; ++i) { 320 Procedure proc; 321 BasicBlock* root = proc.addBlock(); 322 Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)); 323 Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)); 324 Value* andAB = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB) 325 : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA); 326 Value* result = i & 2 ? root->appendNew<Value>(proc, BitXor, Origin(), andAB, argA) 327 : root->appendNew<Value>(proc, BitXor, Origin(), argA, andAB); 328 root->appendNewControlValue(proc, Return, Origin(), result); 329 330 CHECK_EQ(compileAndRun<int32_t>(proc, a, b), ((a & b) ^ a)); 281 331 } 282 332 }
Note: See TracChangeset
for help on using the changeset viewer.