diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -446,6 +446,7 @@ def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "BitCast", LLVM_AnyNonAggregate, LLVM_AnyNonAggregate> { let hasFolder = 1; + let hasVerifier = 1; } def LLVM_AddrSpaceCastOp : LLVM_CastOp<"addrspacecast", "AddrSpaceCast", LLVM_ScalarOrVectorOf, diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2307,7 +2307,7 @@ } //===----------------------------------------------------------------------===// -// Folder for LLVM::BitcastOp +// Folder and verifier for LLVM::BitcastOp //===----------------------------------------------------------------------===// OpFoldResult LLVM::BitcastOp::fold(FoldAdaptor adaptor) { @@ -2321,6 +2321,41 @@ return {}; } +LogicalResult LLVM::BitcastOp::verify() { + auto resultType = extractVectorElementType(getResult().getType()) + .dyn_cast(); + auto sourceType = + extractVectorElementType(getArg().getType()).dyn_cast(); + + // If one of the types is a pointer (or vector of pointers), then + // both source and result type have to be pointers. + if (static_cast(resultType) != static_cast(sourceType)) + return emitOpError("can only cast pointers from and to pointers"); + + if (!resultType) + return success(); + + auto isVector = [](Type type) { + return type.isa(); + }; + + // Due to bitcast requiring both operands to be of the same size, it is not + // possible for only one of the two to be a pointer of vectors. + if (isVector(getResult().getType()) && !isVector(getArg().getType())) + return emitOpError("cannot cast pointer to vector of pointers"); + + if (!isVector(getResult().getType()) && isVector(getArg().getType())) + return emitOpError("cannot cast vector of pointers to pointer"); + + // Bitcast cannot cast between pointers of different address spaces. + // 'llvm.addrspacecast' must be used for this purpose instead. + if (resultType.getAddressSpace() != sourceType.getAddressSpace()) + return emitOpError("cannot cast pointers of different address spaces, " + "use 'llvm.addrspacecast' instead"); + + return success(); +} + //===----------------------------------------------------------------------===// // Folder for LLVM::AddrSpaceCastOp //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -1292,3 +1292,46 @@ #void = #llvm.di_void_result_type // expected-error@below {{expected subroutine to have non-void argument types}} #void_argument_type = #llvm.di_subroutine_type + +// ----- + +func.func @invalid_bitcast_ptr_to_i64(%arg : !llvm.ptr) { + // expected-error@+1 {{can only cast pointers from and to pointers}} + %1 = llvm.bitcast %arg : !llvm.ptr to i64 +} + +// ----- + +func.func @invalid_bitcast_i64_to_ptr() { + %0 = llvm.mlir.constant(2 : i64) : i64 + // expected-error@+1 {{can only cast pointers from and to pointers}} + %1 = llvm.bitcast %0 : i64 to !llvm.ptr +} + +// ----- + +func.func @invalid_bitcast_vec_to_ptr(%arg : !llvm.vec<4 x ptr>) { + // expected-error@+1 {{cannot cast vector of pointers to pointer}} + %0 = llvm.bitcast %arg : !llvm.vec<4 x ptr> to !llvm.ptr +} + +// ----- + +func.func @invalid_bitcast_ptr_to_vec(%arg : !llvm.ptr) { + // expected-error@+1 {{cannot cast pointer to vector of pointers}} + %0 = llvm.bitcast %arg : !llvm.ptr to !llvm.vec<4 x ptr> +} + +// ----- + +func.func @invalid_bitcast_addr_cast(%arg : !llvm.ptr<1>) { + // expected-error@+1 {{cannot cast pointers of different address spaces, use 'llvm.addrspacecast' instead}} + %0 = llvm.bitcast %arg : !llvm.ptr<1> to !llvm.ptr +} + +// ----- + +func.func @invalid_bitcast_addr_cast_vec(%arg : !llvm.vec<4 x ptr<1>>) { + // expected-error@+1 {{cannot cast pointers of different address spaces, use 'llvm.addrspacecast' instead}} + %0 = llvm.bitcast %arg : !llvm.vec<4 x ptr<1>> to !llvm.vec<4 x ptr> +}