From b9478c2aef060aa6b0ede41c05859c34b1527bf8 Mon Sep 17 00:00:00 2001 From: James Molloy Date: Sat, 17 Nov 2012 17:56:30 +0000 Subject: Add a new function to ConstantExpr - getAsInstruction. This returns its Instruction* corollary, which may be useful if a user wishes to transform a ConstantExpr so that one of its operands is no longer constant. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168262 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Constants.h | 10 ++++ lib/VMCore/Constants.cpp | 63 ++++++++++++++++++++++ unittests/VMCore/ConstantsTest.cpp | 106 +++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) diff --git a/include/llvm/Constants.h b/include/llvm/Constants.h index b7d1a488f5..3308499192 100644 --- a/include/llvm/Constants.h +++ b/include/llvm/Constants.h @@ -1076,6 +1076,16 @@ public: /// current one. Constant *getWithOperands(ArrayRef Ops, Type *Ty) const; + /// getAsInstruction - Returns an Instruction which implements the same operation + /// as this ConstantExpr. The instruction is not linked to any basic block. + /// + /// A better approach to this could be to have a constructor for Instruction + /// which would take a ConstantExpr parameter, but that would have spread + /// implementation details of ConstantExpr outside of Constants.cpp, which + /// would make it harded to remove ConstantExprs altogether + /// (http://llvm.org/bugs/show_bug.cgi?id=10368). + Instruction *getAsInstruction(); + virtual void destroyConstant(); virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U); diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 935f6b2bc1..a4514309b2 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -2704,3 +2704,66 @@ void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV, // Delete the old constant! destroyConstant(); } + +Instruction *ConstantExpr::getAsInstruction() { + SmallVector ValueOperands; + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) + ValueOperands.push_back(cast(I)); + + ArrayRef Ops(ValueOperands); + + switch (getOpcode()) { + case Instruction::Trunc: + case Instruction::ZExt: + case Instruction::SExt: + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::UIToFP: + case Instruction::SIToFP: + case Instruction::FPToUI: + case Instruction::FPToSI: + case Instruction::PtrToInt: + case Instruction::IntToPtr: + case Instruction::BitCast: + return CastInst::Create((Instruction::CastOps)getOpcode(), + Ops[0], getType()); + case Instruction::Select: + return SelectInst::Create(Ops[0], Ops[1], Ops[2]); + case Instruction::InsertElement: + return InsertElementInst::Create(Ops[0], Ops[1], Ops[2]); + case Instruction::ExtractElement: + return ExtractElementInst::Create(Ops[0], Ops[1]); + case Instruction::InsertValue: + return InsertValueInst::Create(Ops[0], Ops[1], getIndices()); + case Instruction::ExtractValue: + return ExtractValueInst::Create(Ops[0], getIndices()); + case Instruction::ShuffleVector: + return new ShuffleVectorInst(Ops[0], Ops[1], Ops[2]); + + case Instruction::GetElementPtr: + if (cast(this)->isInBounds()) + return GetElementPtrInst::CreateInBounds(Ops[0], Ops.slice(1)); + else + return GetElementPtrInst::Create(Ops[0], Ops.slice(1)); + + case Instruction::ICmp: + case Instruction::FCmp: + return CmpInst::Create((Instruction::OtherOps)getOpcode(), + getPredicate(), Ops[0], Ops[1]); + + default: + assert(getNumOperands() == 2 && "Must be binary operator?"); + BinaryOperator *BO = + BinaryOperator::Create((Instruction::BinaryOps)getOpcode(), + Ops[0], Ops[1]); + if (isa(BO)) { + BO->setHasNoUnsignedWrap(SubclassOptionalData & + OverflowingBinaryOperator::NoUnsignedWrap); + BO->setHasNoSignedWrap(SubclassOptionalData & + OverflowingBinaryOperator::NoSignedWrap); + } + if (isa(BO)) + BO->setIsExact(SubclassOptionalData & PossiblyExactOperator::IsExact); + return BO; + } +} diff --git a/unittests/VMCore/ConstantsTest.cpp b/unittests/VMCore/ConstantsTest.cpp index 623ea0d102..25d61cc6ca 100644 --- a/unittests/VMCore/ConstantsTest.cpp +++ b/unittests/VMCore/ConstantsTest.cpp @@ -8,8 +8,11 @@ //===----------------------------------------------------------------------===// #include "llvm/Constants.h" +#include "llvm/Instruction.h" +#include "llvm/InstrTypes.h" #include "llvm/DerivedTypes.h" #include "llvm/LLVMContext.h" +#include "llvm/Module.h" #include "gtest/gtest.h" namespace llvm { @@ -118,5 +121,108 @@ TEST(ConstantsTest, FP128Test) { EXPECT_TRUE(isa(X)); } +#define CHECK(x, y) { \ + std::string __s; \ + raw_string_ostream __o(__s); \ + cast(x)->getAsInstruction()->print(__o); \ + __o.flush(); \ + EXPECT_EQ(std::string(" = " y), __s); \ + } + +TEST(ConstantsTest, AsInstructionsTest) { + Module *M = new Module("MyModule", getGlobalContext()); + + Type *Int64Ty = Type::getInt64Ty(getGlobalContext()); + Type *Int32Ty = Type::getInt32Ty(getGlobalContext()); + Type *Int16Ty = Type::getInt16Ty(getGlobalContext()); + Type *Int1Ty = Type::getInt1Ty(getGlobalContext()); + Type *FloatTy = Type::getFloatTy(getGlobalContext()); + Type *DoubleTy = Type::getDoubleTy(getGlobalContext()); + + Constant *Global = M->getOrInsertGlobal("dummy", + PointerType::getUnqual(Int32Ty)); + Constant *Global2 = M->getOrInsertGlobal("dummy2", + PointerType::getUnqual(Int32Ty)); + + Constant *P0 = ConstantExpr::getPtrToInt(Global, Int32Ty); + Constant *P1 = ConstantExpr::getUIToFP(P0, FloatTy); + Constant *P2 = ConstantExpr::getUIToFP(P0, DoubleTy); + Constant *P3 = ConstantExpr::getTrunc(P0, Int1Ty); + Constant *P4 = ConstantExpr::getPtrToInt(Global2, Int32Ty); + Constant *P5 = ConstantExpr::getUIToFP(P4, FloatTy); + Constant *P6 = ConstantExpr::getBitCast(P4, VectorType::get(Int16Ty, 2)); + + Constant *One = ConstantInt::get(Int32Ty, 1); + + #define P0STR "ptrtoint (i32** @dummy to i32)" + #define P1STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to float)" + #define P2STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to double)" + #define P3STR "ptrtoint (i32** @dummy to i1)" + #define P4STR "ptrtoint (i32** @dummy2 to i32)" + #define P5STR "uitofp (i32 ptrtoint (i32** @dummy2 to i32) to float)" + #define P6STR "bitcast (i32 ptrtoint (i32** @dummy2 to i32) to <2 x i16>)" + + CHECK(ConstantExpr::getNeg(P0), "sub i32 0, " P0STR); + CHECK(ConstantExpr::getFNeg(P1), "fsub float -0.000000e+00, " P1STR); + CHECK(ConstantExpr::getNot(P0), "xor i32 " P0STR ", -1"); + CHECK(ConstantExpr::getAdd(P0, P0), "add i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getAdd(P0, P0, false, true), "add nsw i32 " P0STR ", " + P0STR); + CHECK(ConstantExpr::getAdd(P0, P0, true, true), "add nuw nsw i32 " P0STR ", " + P0STR); + CHECK(ConstantExpr::getFAdd(P1, P1), "fadd float " P1STR ", " P1STR); + CHECK(ConstantExpr::getSub(P0, P0), "sub i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFSub(P1, P1), "fsub float " P1STR ", " P1STR); + CHECK(ConstantExpr::getMul(P0, P0), "mul i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFMul(P1, P1), "fmul float " P1STR ", " P1STR); + CHECK(ConstantExpr::getUDiv(P0, P0), "udiv i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getSDiv(P0, P0), "sdiv i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFDiv(P1, P1), "fdiv float " P1STR ", " P1STR); + CHECK(ConstantExpr::getURem(P0, P0), "urem i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getSRem(P0, P0), "srem i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFRem(P1, P1), "frem float " P1STR ", " P1STR); + CHECK(ConstantExpr::getAnd(P0, P0), "and i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getOr(P0, P0), "or i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getXor(P0, P0), "xor i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getShl(P0, P0), "shl i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getShl(P0, P0, true), "shl nuw i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getShl(P0, P0, false, true), "shl nsw i32 " P0STR ", " + P0STR); + CHECK(ConstantExpr::getLShr(P0, P0, false), "lshr i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getLShr(P0, P0, true), "lshr exact i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getAShr(P0, P0, false), "ashr i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getAShr(P0, P0, true), "ashr exact i32 " P0STR ", " P0STR); + + CHECK(ConstantExpr::getSExt(P0, Int64Ty), "sext i32 " P0STR " to i64"); + CHECK(ConstantExpr::getZExt(P0, Int64Ty), "zext i32 " P0STR " to i64"); + CHECK(ConstantExpr::getFPTrunc(P2, FloatTy), "fptrunc double " P2STR + " to float"); + CHECK(ConstantExpr::getFPExtend(P1, DoubleTy), "fpext float " P1STR + " to double"); + + CHECK(ConstantExpr::getExactUDiv(P0, P0), "udiv exact i32 " P0STR ", " P0STR); + + CHECK(ConstantExpr::getSelect(P3, P0, P4), "select i1 " P3STR ", i32 " P0STR + ", i32 " P4STR); + CHECK(ConstantExpr::getICmp(CmpInst::ICMP_EQ, P0, P4), "icmp eq i32 " P0STR + ", " P4STR); + CHECK(ConstantExpr::getFCmp(CmpInst::FCMP_ULT, P1, P5), "fcmp ult float " + P1STR ", " P5STR); + + std::vector V; + V.push_back(One); + // FIXME: getGetElementPtr() actually creates an inbounds ConstantGEP, + // not a normal one! + //CHECK(ConstantExpr::getGetElementPtr(Global, V, false), + // "getelementptr i32** @dummy, i32 1"); + CHECK(ConstantExpr::getInBoundsGetElementPtr(Global, V), + "getelementptr inbounds i32** @dummy, i32 1"); + + CHECK(ConstantExpr::getExtractElement(P6, One), "extractelement <2 x i16> " + P6STR ", i32 1"); +} + +#undef CHECK + } // end anonymous namespace } // end namespace llvm -- cgit v1.2.3