diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -134,6 +134,10 @@ Changes to the C API -------------------- +* Add ``LLVMGetCastOpcode`` function to aid users of ``LLVMBuildCast`` in + resolving the best cast operation given a source value and destination type. + This function is a direct wrapper of ``CastInst::getCastOpcode``. + Changes to the Go bindings -------------------------- diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -3978,6 +3978,9 @@ LLVMValueRef LLVMBuildIntCast(LLVMBuilderRef, LLVMValueRef Val, /*Signed cast!*/ LLVMTypeRef DestTy, const char *Name); +LLVMOpcode LLVMGetCastOpcode(LLVMValueRef Src, LLVMBool SrcIsSigned, + LLVMTypeRef DestTy, LLVMBool DestIsSigned); + /* Comparisons */ LLVMValueRef LLVMBuildICmp(LLVMBuilderRef, LLVMIntPredicate Op, LLVMValueRef LHS, LLVMValueRef RHS, diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -3921,6 +3921,12 @@ return wrap(unwrap(B)->CreateFPCast(unwrap(Val), unwrap(DestTy), Name)); } +LLVMOpcode LLVMGetCastOpcode(LLVMValueRef Src, LLVMBool SrcIsSigned, + LLVMTypeRef DestTy, LLVMBool DestIsSigned) { + return map_to_llvmopcode(CastInst::getCastOpcode( + unwrap(Src), SrcIsSigned, unwrap(DestTy), DestIsSigned)); +} + /*--.. Comparisons .........................................................--*/ LLVMValueRef LLVMBuildICmp(LLVMBuilderRef B, LLVMIntPredicate Op, diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -26,6 +26,7 @@ #include "llvm/IR/NoFolder.h" #include "llvm/IR/Operator.h" #include "llvm/Support/SourceMgr.h" +#include "llvm-c/Core.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" #include @@ -391,6 +392,67 @@ delete BB; } +TEST(InstructionsTest, CastCAPI) { + LLVMContext C; + + Type *Int8Ty = Type::getInt8Ty(C); + Type *Int32Ty = Type::getInt32Ty(C); + Type *Int64Ty = Type::getInt64Ty(C); + + Type *FloatTy = Type::getFloatTy(C); + Type *DoubleTy = Type::getDoubleTy(C); + + Type *Int8PtrTy = PointerType::get(Int8Ty, 0); + Type *Int32PtrTy = PointerType::get(Int32Ty, 0); + + const Constant *C8 = Constant::getNullValue(Int8Ty); + const Constant *C64 = Constant::getNullValue(Int64Ty); + + EXPECT_EQ(LLVMBitCast, + LLVMGetCastOpcode(wrap(C64), true, wrap(Int64Ty), true)); + EXPECT_EQ(LLVMTrunc, LLVMGetCastOpcode(wrap(C64), true, wrap(Int8Ty), true)); + EXPECT_EQ(LLVMSExt, LLVMGetCastOpcode(wrap(C8), true, wrap(Int64Ty), true)); + EXPECT_EQ(LLVMZExt, LLVMGetCastOpcode(wrap(C8), false, wrap(Int64Ty), true)); + + const Constant *CF32 = Constant::getNullValue(FloatTy); + const Constant *CF64 = Constant::getNullValue(DoubleTy); + + EXPECT_EQ(LLVMFPToUI, + LLVMGetCastOpcode(wrap(CF32), true, wrap(Int8Ty), false)); + EXPECT_EQ(LLVMFPToSI, + LLVMGetCastOpcode(wrap(CF32), true, wrap(Int8Ty), true)); + EXPECT_EQ(LLVMUIToFP, + LLVMGetCastOpcode(wrap(C8), false, wrap(FloatTy), true)); + EXPECT_EQ(LLVMSIToFP, LLVMGetCastOpcode(wrap(C8), true, wrap(FloatTy), true)); + EXPECT_EQ(LLVMFPTrunc, + LLVMGetCastOpcode(wrap(CF64), true, wrap(FloatTy), true)); + EXPECT_EQ(LLVMFPExt, + LLVMGetCastOpcode(wrap(CF32), true, wrap(DoubleTy), true)); + + const Constant *CPtr8 = Constant::getNullValue(Int8PtrTy); + + EXPECT_EQ(LLVMPtrToInt, + LLVMGetCastOpcode(wrap(CPtr8), true, wrap(Int8Ty), true)); + EXPECT_EQ(LLVMIntToPtr, + LLVMGetCastOpcode(wrap(C8), true, wrap(Int8PtrTy), true)); + + Type *V8x8Ty = FixedVectorType::get(Int8Ty, 8); + Type *V8x64Ty = FixedVectorType::get(Int64Ty, 8); + const Constant *CV8 = Constant::getNullValue(V8x8Ty); + const Constant *CV64 = Constant::getNullValue(V8x64Ty); + + EXPECT_EQ(LLVMTrunc, LLVMGetCastOpcode(wrap(CV64), true, wrap(V8x8Ty), true)); + EXPECT_EQ(LLVMSExt, LLVMGetCastOpcode(wrap(CV8), true, wrap(V8x64Ty), true)); + + Type *Int32PtrAS1Ty = PointerType::get(Int32Ty, 1); + Type *V2Int32PtrAS1Ty = FixedVectorType::get(Int32PtrAS1Ty, 2); + Type *V2Int32PtrTy = FixedVectorType::get(Int32PtrTy, 2); + const Constant *CV2ptr32 = Constant::getNullValue(V2Int32PtrTy); + + EXPECT_EQ(LLVMAddrSpaceCast, LLVMGetCastOpcode(wrap(CV2ptr32), true, + wrap(V2Int32PtrAS1Ty), true)); +} + TEST(InstructionsTest, VectorGep) { LLVMContext C;