TEST(Simplifier, LdObjInvoke) { IRUnit unit{test_context}; Simplifier sim{unit}; auto const dummy = BCMarker::Dummy(); auto const taken = unit.defBlock(); // LdObjInvoke t1:Cls doesn't simplify { auto type = Type::Cls; auto cls = unit.gen(Conjure, dummy, type); auto load = unit.gen(LdObjInvoke, dummy, taken, cls->dst()); auto result = sim.simplify(load, false); EXPECT_NO_CHANGE(result); } // LdObjInvoke t1:Cls(C), where C is persistent but has no __invoke // doesn't simplify. { auto type = Type::cns(SystemLib::s_IteratorClass); auto cls = unit.gen(Conjure, dummy, type); auto load = unit.gen(LdObjInvoke, dummy, taken, cls->dst()); auto result = sim.simplify(load, false); EXPECT_NO_CHANGE(result); } }
TEST(Simplifier, LdObjClass) { IRUnit unit{test_context}; Simplifier sim{unit}; auto const dummy = BCMarker::Dummy(); auto const cls = SystemLib::s_IteratorClass; // LdObjClass t1:Obj<=C doesn't simplify { auto sub = Type::Obj.specialize(cls); auto obj = unit.gen(Conjure, dummy, sub); auto load = unit.gen(LdObjClass, dummy, obj->dst()); auto result = sim.simplify(load, false); EXPECT_NO_CHANGE(result); } // LdObjClass t1:Obj=C --> Cls(C) { auto exact = Type::Obj.specializeExact(cls); auto obj = unit.gen(Conjure, dummy, exact); auto load = unit.gen(LdObjClass, dummy, obj->dst()); auto result = sim.simplify(load, false); EXPECT_EQ(result.dst->clsVal(), cls); EXPECT_EQ(result.instrs.size(), 0); } }
TEST(Simplifier, Count) { IRUnit unit{test_context}; Simplifier sim{unit}; BCMarker dummy = BCMarker::Dummy(); // Count($null) --> 0 { auto null = unit.gen(Conjure, dummy, Type::Null); auto count = unit.gen(Count, dummy, null->dst()); auto result = sim.simplify(count, false); EXPECT_NE(nullptr, result.dst); EXPECT_EQ(0, result.instrs.size()); EXPECT_EQ(0, result.dst->intVal()); } // Count($bool_int_dbl_str) --> 1 { auto ty = Type::Bool | Type::Int | Type::Dbl | Type::Str | Type::Res; auto val = unit.gen(Conjure, dummy, ty); auto count = unit.gen(Count, dummy, val->dst()); auto result = sim.simplify(count, false); EXPECT_NE(nullptr, result.dst); EXPECT_EQ(0, result.instrs.size()); EXPECT_EQ(1, result.dst->intVal()); } // Count($array_no_kind) --> CountArray($array_no_kind) { auto arr = unit.gen(Conjure, dummy, Type::Arr); auto count = unit.gen(Count, dummy, arr->dst()); auto result = sim.simplify(count, false); EXPECT_NE(nullptr, result.dst); EXPECT_EQ(1, result.instrs.size()); EXPECT_MATCH(result.instrs[0], CountArray, arr->dst()); } // Count($array_not_nvtw) --> CountArrayFast($array_not_nvtw) { auto ty = Type::Arr.specialize(ArrayData::kPackedKind); auto arr = unit.gen(Conjure, dummy, ty); auto count = unit.gen(Count, dummy, arr->dst()); auto result = sim.simplify(count, false); EXPECT_NE(nullptr, result.dst); EXPECT_EQ(1, result.instrs.size()); EXPECT_MATCH(result.instrs[0], CountArrayFast, arr->dst()); } // Count($some_obj) --> Count($some_obj) { auto obj = unit.gen(Conjure, dummy, Type::Obj); auto count = unit.gen(Count, dummy, obj->dst()); auto result = sim.simplify(count, false); EXPECT_NO_CHANGE(result); } }
TEST(Simplifier, JumpConstFold) { BCMarker dummy = BCMarker::Dummy(); IRUnit unit(0); Simplifier sim(unit); OptionSetter<bool> r(RuntimeOption::EvalHHIRBytecodeControlFlow, false); // Folding JmpZero and JmpNZero. { auto tester = [&] (SSATmp* val, Opcode op) { auto jmp = unit.gen(op, dummy, unit.defBlock(), val); return sim.simplify(jmp, false); }; auto resultFalseZero = tester(unit.cns(false), JmpZero); auto resultFalseNZero = tester(unit.cns(false), JmpNZero); auto resultTrueZero = tester(unit.cns(true), JmpZero); auto resultTrueNZero = tester(unit.cns(true), JmpNZero); EXPECT_SINGLE_OP(resultFalseNZero, Nop); EXPECT_SINGLE_OP(resultTrueZero, Nop); EXPECT_SINGLE_OP(resultFalseZero, Jmp); EXPECT_SINGLE_OP(resultTrueNZero, Jmp); } // Don't do this if bytecode control flow is on. { OptionSetter<bool> r(RuntimeOption::EvalHHIRBytecodeControlFlow, true); auto jmp = unit.gen(JmpNZero, dummy, unit.defBlock(), unit.cns(false)); auto result = sim.simplify(jmp, false); EXPECT_NO_CHANGE(result); ASSERT_TRUE(RuntimeOption::EvalHHIRBytecodeControlFlow); } ASSERT_FALSE(RuntimeOption::EvalHHIRBytecodeControlFlow); // Folding query jumps. { auto jmpeqTaken = unit.gen(JmpEq, dummy, unit.cns(10), unit.cns(10)); auto result = sim.simplify(jmpeqTaken, false); EXPECT_SINGLE_OP(result, Jmp); auto jmpeqNTaken = unit.gen(JmpEq, dummy, unit.cns(10), unit.cns(400)); result = sim.simplify(jmpeqNTaken, false); EXPECT_SINGLE_OP(result, Nop); } }