diff --git a/include/llvm/Intrinsics.h b/include/llvm/Intrinsics.h index d59121be51a..a0e01dddcf4 100644 --- a/include/llvm/Intrinsics.h +++ b/include/llvm/Intrinsics.h @@ -58,19 +58,21 @@ namespace Intrinsic { dbg_func_start, // Start of a function dbg_declare, // Declare a local object - - // Standard libc functions. + // Standard C library intrinsics. memcpy, // Copy non-overlapping memory blocks memmove, // Copy potentially overlapping memory blocks memset, // Fill memory with a byte value - - // libm related functions. isunordered, // Return true if either argument is a NaN - ctpop, //count population - ctlz, //count leading zeros - cttz, //count trailing zeros - sqrt, //square root + sqrt, // Square root + // Bit manipulation instrinsics. + bswap_i16, // Byteswap 16 bits + bswap_i32, // Byteswap 32 bits + bswap_i64, // Byteswap 64 bits + ctpop, // Count population + ctlz, // Count leading zeros + cttz, // Count trailing zeros + // Input/Output intrinsics. readport, writeport, diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index 32cc473022f..1935f77b49a 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -79,6 +79,32 @@ inline bool isPowerOf2_64(uint64_t Value) { return Value && !(Value & (Value - 1LL)); } +// ByteSwap_16 - This function returns a byte-swapped representation of the +// 16-bit argument, Value. +inline unsigned short ByteSwap_16(unsigned short Value) { + unsigned short Hi = Value << 8; + unsigned short Lo = Value >> 8; + return Hi | Lo; +} + +// ByteSwap_32 - This function returns a byte-swapped representation of the +// 32-bit argument, Value. +inline unsigned ByteSwap_32(unsigned Value) { + unsigned Byte0 = Value & 0x000000FF; + unsigned Byte1 = Value & 0x0000FF00; + unsigned Byte2 = Value & 0x00FF0000; + unsigned Byte3 = Value & 0xFF000000; + return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); +} + +// ByteSwap_64 - This function returns a byte-swapped representation of the +// 64-bit argument, Value. +inline uint64_t ByteSwap_64(uint64_t Value) { + uint64_t Hi = ByteSwap_32(Value); + uint64_t Lo = ByteSwap_32(Value >> 32); + return (Hi << 32) | Lo; +} + // CountLeadingZeros_32 - this function performs the platform optimal form of // counting the number of zeros from the most significant bit to the first one // bit. Ex. CountLeadingZeros_32(0x00F000FF) == 8. diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index 86cc5646be6..71bcbd2cf09 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -708,7 +708,8 @@ namespace { static const char *DoesntAccessMemoryTable[] = { // LLVM intrinsics: "llvm.frameaddress", "llvm.returnaddress", "llvm.readport", - "llvm.isunordered", "llvm.sqrt", "llvm.ctpop", "llvm.ctlz", "llvm.cttz", + "llvm.isunordered", "llvm.sqrt", "llvm.bswap.i16", "llvm.bswap.i32", + "llvm.bswap.i64", "llvm.ctpop", "llvm.ctlz", "llvm.cttz", "abs", "labs", "llabs", "imaxabs", "fabs", "fabsf", "fabsl", "trunc", "truncf", "truncl", "ldexp", diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 4022bdda1de..915a7cb734f 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -37,6 +37,13 @@ llvm::canConstantFoldCallTo(Function *F) { switch (F->getIntrinsicID()) { case Intrinsic::isunordered: case Intrinsic::sqrt: + case Intrinsic::bswap_i16: + case Intrinsic::bswap_i32: + case Intrinsic::bswap_i64: + // FIXME: these should be constant folded as well + //case Intrinsic::ctpop: + //case Intrinsic::ctlz: + //case Intrinsic::cttz: return true; default: break; } @@ -142,6 +149,14 @@ llvm::ConstantFoldCall(Function *F, const std::vector &Operands) { default: break; } + } else if (ConstantUInt *Op = dyn_cast(Operands[0])) { + uint64_t V = Op->getValue(); + if (Name == "llvm.bswap.i16") + return ConstantUInt::get(Ty, ByteSwap_16(V)); + else if (Name == "llvm.bswap.i32") + return ConstantUInt::get(Ty, ByteSwap_32(V)); + else if (Name == "llvm.bswap.i64") + return ConstantUInt::get(Ty, ByteSwap_64(V)); } } else if (Operands.size() == 2) { if (ConstantFP *Op1 = dyn_cast(Operands[0])) { diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 4e3b3e972e2..c4b69a40d4c 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -298,6 +298,9 @@ bool llvm::isInstructionTriviallyDead(Instruction *I) { case Intrinsic::frameaddress: case Intrinsic::stacksave: case Intrinsic::isunordered: + case Intrinsic::bswap_i16: + case Intrinsic::bswap_i32: + case Intrinsic::bswap_i64: case Intrinsic::ctpop: case Intrinsic::ctlz: case Intrinsic::cttz: diff --git a/lib/VMCore/Function.cpp b/lib/VMCore/Function.cpp index 0cbe14ce041..3abfef9c2d5 100644 --- a/lib/VMCore/Function.cpp +++ b/lib/VMCore/Function.cpp @@ -207,6 +207,11 @@ unsigned Function::getIntrinsicID() const { assert(getName().size() != 5 && "'llvm.' is an invalid intrinsic name!"); switch (getName()[5]) { + case 'b': + if (getName() == "llvm.bswap.i16") return Intrinsic::bswap_i16; + if (getName() == "llvm.bswap.i32") return Intrinsic::bswap_i32; + if (getName() == "llvm.bswap.i64") return Intrinsic::bswap_i64; + break; case 'c': if (getName() == "llvm.ctpop") return Intrinsic::ctpop; if (getName() == "llvm.cttz") return Intrinsic::cttz; diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index 9dd7184b1d7..f67a49702c0 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -749,6 +749,36 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { NumArgs = 0; break; + case Intrinsic::bswap_i16: + Assert1(FT->getNumParams() == 1, + "Illegal # arguments for intrinsic function!", IF); + Assert1(FT->getReturnType() == FT->getParamType(0), + "Return type does not match source type", IF); + Assert1(FT->getReturnType() == Type::UShortTy, + "Return type is not ushort!", IF); + NumArgs = 1; + break; + + case Intrinsic::bswap_i32: + Assert1(FT->getNumParams() == 1, + "Illegal # arguments for intrinsic function!", IF); + Assert1(FT->getReturnType() == FT->getParamType(0), + "Return type does not match source type", IF); + Assert1(FT->getReturnType() == Type::UIntTy, + "Return type is not uint!", IF); + NumArgs = 1; + break; + + case Intrinsic::bswap_i64: + Assert1(FT->getNumParams() == 1, + "Illegal # arguments for intrinsic function!", IF); + Assert1(FT->getReturnType() == FT->getParamType(0), + "Return type does not match source type", IF); + Assert1(FT->getReturnType() == Type::ULongTy, + "Return type is not ulong!", IF); + NumArgs = 1; + break; + case Intrinsic::ctpop: case Intrinsic::ctlz: case Intrinsic::cttz: diff --git a/test/Transforms/ConstProp/bswap.ll b/test/Transforms/ConstProp/bswap.ll new file mode 100644 index 00000000000..2d7f96449fa --- /dev/null +++ b/test/Transforms/ConstProp/bswap.ll @@ -0,0 +1,22 @@ +; bswap should be constant folded when it is passed a constant argument + +; RUN: llvm-as < %s | opt -constprop | llvm-dis | not grep call + +declare ushort %llvm.bswap.i16(ushort) +declare uint %llvm.bswap.i32(uint) +declare ulong %llvm.bswap.i64(ulong) + +ushort %W() { + %Z = call ushort %llvm.bswap.i16(ushort 1) + ret ushort %Z +} + +uint %X() { + %Z = call uint %llvm.bswap.i32(uint 1) + ret uint %Z +} + +ulong %Y() { + %Z = call ulong %llvm.bswap.i64(ulong 1) + ret ulong %Z +}