OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits> | 5 #include <limits> |
6 | 6 |
7 #include "test/unittests/compiler/instruction-selector-unittest.h" | 7 #include "test/unittests/compiler/instruction-selector-unittest.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
(...skipping 1986 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1997 Stream s = m.Build(); | 1997 Stream s = m.Build(); |
1998 ASSERT_EQ(1U, s.size()); | 1998 ASSERT_EQ(1U, s.size()); |
1999 EXPECT_EQ(kArmVsqrtF64, s[0]->arch_opcode()); | 1999 EXPECT_EQ(kArmVsqrtF64, s[0]->arch_opcode()); |
2000 ASSERT_EQ(1U, s[0]->InputCount()); | 2000 ASSERT_EQ(1U, s[0]->InputCount()); |
2001 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 2001 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
2002 ASSERT_EQ(1U, s[0]->OutputCount()); | 2002 ASSERT_EQ(1U, s[0]->OutputCount()); |
2003 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); | 2003 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); |
2004 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); | 2004 EXPECT_EQ(kFlags_none, s[0]->flags_mode()); |
2005 } | 2005 } |
2006 | 2006 |
| 2007 // ----------------------------------------------------------------------------- |
| 2008 // Flag-setting instructions. |
| 2009 |
| 2010 const Comparison kBinopCmpZeroRightInstructions[] = { |
| 2011 {&RawMachineAssembler::Word32Equal, "Word32Equal", kEqual, kNotEqual, |
| 2012 kEqual}, |
| 2013 {&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kNotEqual, kEqual, |
| 2014 kNotEqual}, |
| 2015 {&RawMachineAssembler::Int32LessThan, "Int32LessThan", kNegative, |
| 2016 kPositiveOrZero, kNegative}, |
| 2017 {&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual", |
| 2018 kPositiveOrZero, kNegative, kPositiveOrZero}, |
| 2019 {&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual", |
| 2020 kEqual, kNotEqual, kEqual}, |
| 2021 {&RawMachineAssembler::Uint32GreaterThan, "Uint32GreaterThan", kNotEqual, |
| 2022 kEqual, kNotEqual}}; |
| 2023 |
| 2024 const Comparison kBinopCmpZeroLeftInstructions[] = { |
| 2025 {&RawMachineAssembler::Word32Equal, "Word32Equal", kEqual, kNotEqual, |
| 2026 kEqual}, |
| 2027 {&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kNotEqual, kEqual, |
| 2028 kNotEqual}, |
| 2029 {&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kNegative, |
| 2030 kPositiveOrZero, kNegative}, |
| 2031 {&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual", |
| 2032 kPositiveOrZero, kNegative, kPositiveOrZero}, |
| 2033 {&RawMachineAssembler::Uint32GreaterThanOrEqual, "Uint32GreaterThanOrEqual", |
| 2034 kEqual, kNotEqual, kEqual}, |
| 2035 {&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kNotEqual, kEqual, |
| 2036 kNotEqual}}; |
| 2037 |
| 2038 struct FlagSettingInst { |
| 2039 Constructor constructor; |
| 2040 const char* constructor_name; |
| 2041 ArchOpcode arch_opcode; |
| 2042 ArchOpcode no_output_opcode; |
| 2043 }; |
| 2044 |
| 2045 std::ostream& operator<<(std::ostream& os, const FlagSettingInst& inst) { |
| 2046 return os << inst.constructor_name; |
| 2047 } |
| 2048 |
| 2049 const FlagSettingInst kFlagSettingInstructions[] = { |
| 2050 {&RawMachineAssembler::Int32Add, "Int32Add", kArmAdd, kArmCmn}, |
| 2051 {&RawMachineAssembler::Word32And, "Word32And", kArmAnd, kArmTst}, |
| 2052 {&RawMachineAssembler::Word32Or, "Word32Or", kArmOrr, kArmOrr}, |
| 2053 {&RawMachineAssembler::Word32Xor, "Word32Xor", kArmEor, kArmTeq}}; |
| 2054 |
| 2055 typedef InstructionSelectorTestWithParam<FlagSettingInst> |
| 2056 InstructionSelectorFlagSettingTest; |
| 2057 |
| 2058 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroRight) { |
| 2059 const FlagSettingInst inst = GetParam(); |
| 2060 // Binop with single user : a cmp instruction. |
| 2061 TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { |
| 2062 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
| 2063 MachineType::Int32()); |
| 2064 RawMachineLabel a, b; |
| 2065 Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1)); |
| 2066 Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0)); |
| 2067 m.Branch(comp, &a, &b); |
| 2068 m.Bind(&a); |
| 2069 m.Return(m.Int32Constant(1)); |
| 2070 m.Bind(&b); |
| 2071 m.Return(m.Int32Constant(0)); |
| 2072 Stream s = m.Build(); |
| 2073 ASSERT_EQ(1U, s.size()); |
| 2074 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. |
| 2075 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
| 2076 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
| 2077 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
| 2078 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); |
| 2079 EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition()); |
| 2080 } |
| 2081 } |
| 2082 |
| 2083 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroLeft) { |
| 2084 const FlagSettingInst inst = GetParam(); |
| 2085 // Test a cmp with zero on the left-hand side. |
| 2086 TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroLeftInstructions) { |
| 2087 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
| 2088 MachineType::Int32()); |
| 2089 RawMachineLabel a, b; |
| 2090 Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1)); |
| 2091 Node* comp = (m.*cmp.constructor)(m.Int32Constant(0), binop); |
| 2092 m.Branch(comp, &a, &b); |
| 2093 m.Bind(&a); |
| 2094 m.Return(m.Int32Constant(1)); |
| 2095 m.Bind(&b); |
| 2096 m.Return(m.Int32Constant(0)); |
| 2097 Stream s = m.Build(); |
| 2098 ASSERT_EQ(1U, s.size()); |
| 2099 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. |
| 2100 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
| 2101 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
| 2102 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
| 2103 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); |
| 2104 EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition()); |
| 2105 } |
| 2106 } |
| 2107 |
| 2108 TEST_P(InstructionSelectorFlagSettingTest, CmpZeroOnlyUserInBasicBlock) { |
| 2109 const FlagSettingInst inst = GetParam(); |
| 2110 // Binop with additional users, but in a different basic block. |
| 2111 TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { |
| 2112 // We don't optimise this case at the moment. |
| 2113 if (cmp.flags_condition == kEqual || cmp.flags_condition == kNotEqual) { |
| 2114 continue; |
| 2115 } |
| 2116 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
| 2117 MachineType::Int32()); |
| 2118 RawMachineLabel a, b; |
| 2119 Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1)); |
| 2120 Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0)); |
| 2121 m.Branch(comp, &a, &b); |
| 2122 m.Bind(&a); |
| 2123 m.Return(binop); |
| 2124 m.Bind(&b); |
| 2125 m.Return(m.Int32Constant(0)); |
| 2126 Stream s = m.Build(); |
| 2127 ASSERT_EQ(1U, s.size()); |
| 2128 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. |
| 2129 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); |
| 2130 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
| 2131 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
| 2132 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); |
| 2133 EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition()); |
| 2134 } |
| 2135 } |
| 2136 |
| 2137 TEST_P(InstructionSelectorFlagSettingTest, ShiftedOperand) { |
| 2138 const FlagSettingInst inst = GetParam(); |
| 2139 // Like the test above, but with a shifted input to the binary operator. |
| 2140 TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { |
| 2141 // We don't optimise this case at the moment. |
| 2142 if (cmp.flags_condition == kEqual || cmp.flags_condition == kNotEqual) { |
| 2143 continue; |
| 2144 } |
| 2145 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
| 2146 MachineType::Int32()); |
| 2147 RawMachineLabel a, b; |
| 2148 Node* imm = m.Int32Constant(5); |
| 2149 Node* shift = m.Word32Shl(m.Parameter(1), imm); |
| 2150 Node* binop = (m.*inst.constructor)(m.Parameter(0), shift); |
| 2151 Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0)); |
| 2152 m.Branch(comp, &a, &b); |
| 2153 m.Bind(&a); |
| 2154 m.Return(binop); |
| 2155 m.Bind(&b); |
| 2156 m.Return(m.Int32Constant(0)); |
| 2157 Stream s = m.Build(); |
| 2158 ASSERT_EQ(1U, s.size()); |
| 2159 ASSERT_EQ(5U, s[0]->InputCount()); // The labels are also inputs. |
| 2160 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); |
| 2161 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
| 2162 EXPECT_EQ(s.ToVreg(m.Parameter(1)), s.ToVreg(s[0]->InputAt(1))); |
| 2163 EXPECT_EQ(5, s.ToInt32(s[0]->InputAt(2))); |
| 2164 EXPECT_EQ(kMode_Operand2_R_LSL_I, s[0]->addressing_mode()); |
| 2165 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); |
| 2166 EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition()); |
| 2167 } |
| 2168 } |
| 2169 |
| 2170 TEST_P(InstructionSelectorFlagSettingTest, UsersInSameBasicBlock) { |
| 2171 const FlagSettingInst inst = GetParam(); |
| 2172 // Binop with additional users, in the same basic block. We need to make sure |
| 2173 // we don't try to optimise this case. |
| 2174 TRACED_FOREACH(Comparison, cmp, kComparisons) { |
| 2175 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
| 2176 MachineType::Int32()); |
| 2177 RawMachineLabel a, b; |
| 2178 Node* binop = (m.*inst.constructor)(m.Parameter(0), m.Parameter(1)); |
| 2179 Node* mul = m.Int32Mul(m.Parameter(0), binop); |
| 2180 Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0)); |
| 2181 m.Branch(comp, &a, &b); |
| 2182 m.Bind(&a); |
| 2183 m.Return(mul); |
| 2184 m.Bind(&b); |
| 2185 m.Return(m.Int32Constant(0)); |
| 2186 Stream s = m.Build(); |
| 2187 ASSERT_EQ(3U, s.size()); |
| 2188 EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode()); |
| 2189 EXPECT_NE(kFlags_branch, s[0]->flags_mode()); |
| 2190 EXPECT_EQ(kArmMul, s[1]->arch_opcode()); |
| 2191 EXPECT_EQ(cmp.flags_condition == kEqual ? kArmTst : kArmCmp, |
| 2192 s[2]->arch_opcode()); |
| 2193 EXPECT_EQ(kFlags_branch, s[2]->flags_mode()); |
| 2194 EXPECT_EQ(cmp.flags_condition, s[2]->flags_condition()); |
| 2195 } |
| 2196 } |
| 2197 |
| 2198 TEST_P(InstructionSelectorFlagSettingTest, CommuteImmediate) { |
| 2199 const FlagSettingInst inst = GetParam(); |
| 2200 // Immediate on left hand side of the binary operator. |
| 2201 TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { |
| 2202 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); |
| 2203 RawMachineLabel a, b; |
| 2204 Node* imm = m.Int32Constant(3); |
| 2205 Node* binop = (m.*inst.constructor)(imm, m.Parameter(0)); |
| 2206 Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0)); |
| 2207 m.Branch(comp, &a, &b); |
| 2208 m.Bind(&a); |
| 2209 m.Return(m.Int32Constant(1)); |
| 2210 m.Bind(&b); |
| 2211 m.Return(m.Int32Constant(0)); |
| 2212 Stream s = m.Build(); |
| 2213 ASSERT_EQ(1U, s.size()); |
| 2214 ASSERT_EQ(4U, s[0]->InputCount()); // The labels are also inputs. |
| 2215 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
| 2216 EXPECT_EQ(s.ToVreg(m.Parameter(0)), s.ToVreg(s[0]->InputAt(0))); |
| 2217 EXPECT_EQ(3, s.ToInt32(s[0]->InputAt(1))); |
| 2218 EXPECT_EQ(kFlags_branch, s[0]->flags_mode()); |
| 2219 EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition()); |
| 2220 } |
| 2221 } |
| 2222 |
| 2223 TEST_P(InstructionSelectorFlagSettingTest, CommuteShift) { |
| 2224 const FlagSettingInst inst = GetParam(); |
| 2225 // Left-hand side operand shifted by immediate. |
| 2226 TRACED_FOREACH(Comparison, cmp, kBinopCmpZeroRightInstructions) { |
| 2227 TRACED_FOREACH(Shift, shift, kShifts) { |
| 2228 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
| 2229 MachineType::Int32()); |
| 2230 Node* imm = m.Int32Constant(5); |
| 2231 Node* shifted_operand = (m.*shift.constructor)(m.Parameter(0), imm); |
| 2232 Node* binop = (m.*inst.constructor)(shifted_operand, m.Parameter(1)); |
| 2233 Node* comp = (m.*cmp.constructor)(binop, m.Int32Constant(0)); |
| 2234 m.Return(comp); |
| 2235 Stream s = m.Build(); |
| 2236 ASSERT_EQ(1U, s.size()); |
| 2237 EXPECT_EQ(inst.no_output_opcode, s[0]->arch_opcode()); |
| 2238 EXPECT_EQ(shift.i_mode, s[0]->addressing_mode()); |
| 2239 EXPECT_EQ(3U, s[0]->InputCount()); |
| 2240 EXPECT_EQ(5, s.ToInt64(s[0]->InputAt(2))); |
| 2241 EXPECT_EQ(inst.arch_opcode == kArmOrr ? 2U : 1U, s[0]->OutputCount()); |
| 2242 EXPECT_EQ(kFlags_set, s[0]->flags_mode()); |
| 2243 EXPECT_EQ(cmp.flags_condition, s[0]->flags_condition()); |
| 2244 } |
| 2245 } |
| 2246 } |
| 2247 |
| 2248 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, |
| 2249 InstructionSelectorFlagSettingTest, |
| 2250 ::testing::ValuesIn(kFlagSettingInstructions)); |
2007 | 2251 |
2008 // ----------------------------------------------------------------------------- | 2252 // ----------------------------------------------------------------------------- |
2009 // Miscellaneous. | 2253 // Miscellaneous. |
2010 | 2254 |
2011 | 2255 |
2012 TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) { | 2256 TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) { |
2013 { | 2257 { |
2014 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), | 2258 StreamBuilder m(this, MachineType::Int32(), MachineType::Int32(), |
2015 MachineType::Int32(), MachineType::Int32()); | 2259 MachineType::Int32(), MachineType::Int32()); |
2016 Node* const p0 = m.Parameter(0); | 2260 Node* const p0 = m.Parameter(0); |
(...skipping 1068 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3085 EXPECT_EQ(kArmVnegF64, s[0]->arch_opcode()); | 3329 EXPECT_EQ(kArmVnegF64, s[0]->arch_opcode()); |
3086 ASSERT_EQ(1U, s[0]->InputCount()); | 3330 ASSERT_EQ(1U, s[0]->InputCount()); |
3087 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); | 3331 EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); |
3088 ASSERT_EQ(1U, s[0]->OutputCount()); | 3332 ASSERT_EQ(1U, s[0]->OutputCount()); |
3089 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); | 3333 EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); |
3090 } | 3334 } |
3091 | 3335 |
3092 } // namespace compiler | 3336 } // namespace compiler |
3093 } // namespace internal | 3337 } // namespace internal |
3094 } // namespace v8 | 3338 } // namespace v8 |
OLD | NEW |