TEST(InstTest, Fold) { InstContext IC; Inst *I1 = IC.getConst(llvm::APInt(64, 0)); Inst *I2 = IC.getConst(llvm::APInt(64, 0)); ASSERT_EQ(I2, I1); Inst *I3 = IC.getConst(llvm::APInt(64, 1)); Inst *I4 = IC.getConst(llvm::APInt(32, 0)); ASSERT_NE(I3, I1); ASSERT_NE(I4, I1); ASSERT_NE(I4, I3); Inst *I1AI3 = IC.getInst(Inst::Add, 64, {I1, I3}); Inst *I3AI1 = IC.getInst(Inst::Add, 64, {I3, I1}); ASSERT_EQ(I1AI3, I3AI1); Inst *I1SI3 = IC.getInst(Inst::Sub, 64, {I1, I3}); Inst *I3SI1 = IC.getInst(Inst::Sub, 64, {I3, I1}); ASSERT_NE(I1SI3, I3SI1); }
TEST(InterpreterTests, KnownBits) { InstContext IC; Inst *I1 = IC.getConst(llvm::APInt(64, 5)); souper::ValueCache C; auto KB = souper::findKnownBits(I1, C); ASSERT_EQ(KB.One, 5); ASSERT_EQ(KB.Zero, ~5); Inst *I2 = IC.getInst(Inst::Var, 64, {}); Inst *I3 = IC.getConst(llvm::APInt(64, 0xFF)); Inst *I4 = IC.getInst(Inst::And, 64, {I2, I3}); KB = souper::findKnownBits(I4, C, /*PartialEval=*/false); ASSERT_EQ(KB.One, 0); ASSERT_EQ(KB.Zero, ~0xFF); Inst *I5 = IC.getInst(Inst::Or, 64, {I2, I1}); KB = souper::findKnownBits(I5, C, /*PartialEval=*/false); ASSERT_EQ(KB.One, 5); ASSERT_EQ(KB.Zero, 0); Inst *I6 = IC.getInst(Inst::Shl, 64, {I2, I1}); KB = souper::findKnownBits(I6, C, /*PartialEval=*/false); ASSERT_EQ(KB.One, 0); ASSERT_EQ(KB.Zero, 31); }
TEST(InterpreterTests, KnownBits) { InstContext IC; Inst *I1 = IC.getConst(llvm::APInt(64, 5)); souper::ConcreteInterpreter CI; auto KB = souper::KnownBitsAnalysis().findKnownBits(I1, CI); ASSERT_EQ(KB.One, 5); ASSERT_EQ(KB.Zero, ~5); Inst *I2 = IC.getInst(Inst::ReservedConst, 64, {}); Inst *I3 = IC.getConst(llvm::APInt(64, 0xFF)); Inst *I4 = IC.getInst(Inst::And, 64, {I2, I3}); KB = souper::KnownBitsAnalysis().findKnownBits(I4, CI); ASSERT_EQ(KB.One, 0); ASSERT_EQ(KB.Zero, ~0xFF); Inst *I5 = IC.getInst(Inst::Or, 64, {I2, I1}); KB = souper::KnownBitsAnalysis().findKnownBits(I5, CI); ASSERT_EQ(KB.One, 5); ASSERT_EQ(KB.Zero, 0); Inst *I6 = IC.getInst(Inst::Shl, 64, {I2, I1}); KB = souper::KnownBitsAnalysis().findKnownBits(I6, CI); ASSERT_EQ(KB.One, 0); ASSERT_EQ(KB.Zero, 31); }
TEST(InstTest, Print) { InstContext IC; std::string Str; llvm::raw_string_ostream SS(Str); Inst *I1 = IC.getConst(llvm::APInt(64, 1)); Inst *I2 = IC.getConst(llvm::APInt(64, 2)); Inst *I3 = IC.getConst(llvm::APInt(64, 3)); Inst *I1AI2 = IC.getInst(Inst::Add, 64, {I1, I2}); Inst *I1AI2MI3 = IC.getInst(Inst::Mul, 64, {I1AI2, I3}); ReplacementContext Context; EXPECT_EQ("%1", Context.printInst(I1AI2MI3, SS, /*printNames=*/false)); EXPECT_EQ("%0:i64 = add 1:i64, 2:i64\n" "%1:i64 = mul 3:i64, %0\n", SS.str()); }
// Checks that ConcreteInterpreter only caches during construction, otherwise not TEST(InterpreterTests, ConcreteCache) { InstContext IC; Inst *I1 = IC.getConst(llvm::APInt(8, 0xFF)); Inst *I2 = IC.getInst(Inst::Var, 8, {}); Inst *I3 = IC.getInst(Inst::Or, 8, {I1, I2}); ValueCache InputValues = {{I2, APInt(8, 0x00)}}; souper::ConcreteInterpreter CI(InputValues); auto Val = CI.evaluateInst(I3); ASSERT_TRUE(Val.hasValue()); ASSERT_EQ(Val.getValue(), APInt(8, 0xFF)); // We want to ensure that evaluateInst call is *really* being evaluated // instead of just returning the result from the cache; so let's change what // I1 was pointing to, to see that. *I1 = *IC.getConst(llvm::APInt(8, 0x0F)); Val = CI.evaluateInst(I3); ASSERT_TRUE(Val.hasValue()); // We would have got 0xFF if evaluateInst had returned result from cache. ASSERT_EQ(Val.getValue(), APInt(8, 0x0F, true)); }
TEST(InterpreterTests, ConstantRange) { InstContext IC; Inst *I1 = IC.getConst(llvm::APInt(64, 5)); souper::ValueCache C; auto CR = souper::findConstantRange(I1, C, /*PartialEval=*/false); ASSERT_EQ(CR.getLower(), 5); ASSERT_EQ(CR.getUpper(), 6); Inst *I2 = IC.getInst(Inst::Var, 64, {}); Inst *I3 = IC.getConst(llvm::APInt(64, 0xFF)); Inst *I4 = IC.getInst(Inst::And, 64, {I2, I3}); CR = souper::findConstantRange(I4, C, /*PartialEval=*/false); ASSERT_EQ(CR.getLower(), 0); ASSERT_EQ(CR.getUpper(), 0xFF + 1); Inst *I5 = IC.getInst(Inst::Add, 64, {I4, I1}); CR = souper::findConstantRange(I5, C, /*PartialEval=*/false); ASSERT_EQ(CR.getLower(), 5); ASSERT_EQ(CR.getUpper(), 0xFF + 5 + 1); }
TEST(InterpreterTests, ConstantRange) { InstContext IC; Inst *I1 = IC.getConst(llvm::APInt(64, 5)); souper::ConcreteInterpreter CI; auto CR = souper::ConstantRangeAnalysis().findConstantRange(I1, CI); ASSERT_EQ(CR.getLower(), 5); ASSERT_EQ(CR.getUpper(), 6); Inst *I2 = IC.getInst(Inst::ReservedConst, 64, {}); Inst *I3 = IC.getConst(llvm::APInt(64, 0xFF)); Inst *I4 = IC.getInst(Inst::And, 64, {I2, I3}); CR = souper::ConstantRangeAnalysis().findConstantRange(I4, CI); ASSERT_EQ(CR.getLower(), 0); ASSERT_EQ(CR.getUpper(), 0xFF + 1); Inst *I5 = IC.getInst(Inst::Add, 64, {I4, I1}); CR = souper::ConstantRangeAnalysis().findConstantRange(I5, CI); ASSERT_EQ(CR.getLower(), 5); ASSERT_EQ(CR.getUpper(), 0xFF + 5 + 1); }