diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 2c3e303f1c0f..cc8c40e0e1b0 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -48,12 +48,15 @@ def CK_BitCast : I32EnumAttrCase<"bitcast", 4>; def CK_FloatingCast : I32EnumAttrCase<"floating", 5>; def CK_PtrToBoolean : I32EnumAttrCase<"ptr_to_bool", 6>; def CK_FloatToIntegral : I32EnumAttrCase<"float_to_int", 7>; +def CK_IntegralToPointer : I32EnumAttrCase<"int_to_ptr", 8>; +def CK_PointerToIntegral : I32EnumAttrCase<"ptr_to_int", 9>; def CastKind : I32EnumAttr< "CastKind", "cast kind", [CK_IntegralToBoolean, CK_ArrayToPointerDecay, CK_IntegralCast, - CK_BitCast, CK_FloatingCast, CK_PtrToBoolean, CK_FloatToIntegral]> { + CK_BitCast, CK_FloatingCast, CK_PtrToBoolean, CK_FloatToIntegral, + CK_IntegralToPointer, CK_PointerToIntegral]> { let cppNamespace = "::mlir::cir"; } diff --git a/clang/lib/CIR/CodeGen/CIRDataLayout.h b/clang/lib/CIR/CodeGen/CIRDataLayout.h index b4c1c83995b6..92490b86daf3 100644 --- a/clang/lib/CIR/CodeGen/CIRDataLayout.h +++ b/clang/lib/CIR/CodeGen/CIRDataLayout.h @@ -14,6 +14,7 @@ #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/IR/BuiltinOps.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" namespace cir { @@ -60,6 +61,19 @@ class CIRDataLayout { // Round up to the next alignment boundary. return llvm::alignTo(getTypeStoreSize(Ty), layout.getTypeABIAlignment(Ty)); } + + unsigned getPointerTypeSizeInBits(mlir::Type Ty) const { + assert(Ty.isa() && + "This should only be called with a pointer type"); + return layout.getTypeSizeInBits(Ty); + } + + mlir::Type getIntPtrType(mlir::Type Ty) const { + assert(Ty.isa() && "Expected pointer type"); + auto IntTy = mlir::cir::IntType::get(Ty.getContext(), + getPointerTypeSizeInBits(Ty), false); + return IntTy; + } }; } // namespace cir diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 760ecd1d87c3..ee45c74b7392 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -15,6 +15,7 @@ #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/Dialect/IR/FPEnv.h" @@ -346,6 +347,32 @@ class CIRGenBuilderTy : public mlir::OpBuilder { mlir::cir::UnaryOpKind::Not, value); } + //===--------------------------------------------------------------------===// + // Cast/Conversion Operators + //===--------------------------------------------------------------------===// + + mlir::Value createCast(mlir::cir::CastKind kind, mlir::Value src, + mlir::Type newTy) { + if (newTy == src.getType()) + return src; + return create(src.getLoc(), newTy, kind, src); + } + + mlir::Value createIntCast(mlir::Value src, mlir::Type newTy) { + return create(src.getLoc(), newTy, + mlir::cir::CastKind::integral, src); + } + + mlir::Value createIntToPtr(mlir::Value src, mlir::Type newTy) { + return create(src.getLoc(), newTy, + mlir::cir::CastKind::int_to_ptr, src); + } + + mlir::Value createPtrToInt(mlir::Value src, mlir::Type newTy) { + return create(src.getLoc(), newTy, + mlir::cir::CastKind::ptr_to_int, src); + } + mlir::Value createZExtOrBitCast(mlir::Location loc, mlir::Value src, mlir::Type newTy) { if (src.getType() == newTy) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index ba2324950b41..b715a33bceb2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1102,10 +1102,25 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!"); return Visit(const_cast(E)); - case CK_IntegralToPointer: - llvm_unreachable("NYI"); - case CK_PointerToIntegral: - llvm_unreachable("NYI"); + case CK_IntegralToPointer: { + auto DestCIRTy = ConvertType(DestTy); + mlir::Value Src = Visit(const_cast(E)); + + // Properly resize by casting to an int of the same size as the pointer. + auto MiddleTy = CGF.CGM.getDataLayout().getIntPtrType(DestCIRTy); + auto MiddleVal = Builder.createIntCast(Src, MiddleTy); + + if (CGF.CGM.getCodeGenOpts().StrictVTablePointers) + llvm_unreachable("NYI"); + + return Builder.createIntToPtr(MiddleVal, DestCIRTy); + } + case CK_PointerToIntegral: { + assert(!DestTy->isBooleanType() && "bool should use PointerToBool"); + if (CGF.CGM.getCodeGenOpts().StrictVTablePointers) + llvm_unreachable("NYI"); + return Builder.createPtrToInt(Visit(E), ConvertType(DestTy)); + } case CK_ToVoid: { CGF.buildIgnoredExpr(E); return nullptr; diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 2c7a6f678d2b..7cf31f084e1c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_CIRGENMODULE_H #define LLVM_CLANG_LIB_CODEGEN_CIRGENMODULE_H +#include "CIRDataLayout.h" #include "CIRGenBuilder.h" #include "CIRGenTypeCache.h" #include "CIRGenTypes.h" @@ -125,6 +126,11 @@ class CIRGenModule : public CIRGenTypeCache { CIRGenTypes &getTypes() { return genTypes; } const clang::LangOptions &getLangOpts() const { return langOpts; } CIRGenFunction *getCurrCIRGenFun() const { return CurCGF; } + const CIRDataLayout getDataLayout() const { + // FIXME(cir): instead of creating a CIRDataLayout every time, set it as an + // attribute for the CIRModule class. + return {theModule}; + } CIRGenCXXABI &getCXXABI() const { return *ABI; } diff --git a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h index 4bf53ca7203a..72de44fd4bd4 100644 --- a/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h +++ b/clang/lib/CIR/CodeGen/UnimplementedFeatureGuarding.h @@ -31,6 +31,9 @@ struct UnimplementedFeature { static bool addressSpaceInGlobalVar() { return false; } static bool getASTAllocaAddressSpace() { return false; } + // Clang codegen options + static bool strictVTablePointers() { return false; } + // Unhandled global/linkage information. static bool unnamedAddr() { return false; } static bool setComdat() { return false; } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 747cb22647ab..2657a90033c3 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -301,6 +301,20 @@ LogicalResult CastOp::verify() { return emitOpError() << "requires !IntegerType for result"; return success(); } + case cir::CastKind::int_to_ptr: { + if (!srcType.dyn_cast()) + return emitOpError() << "requires integer for source"; + if (!resType.dyn_cast()) + return emitOpError() << "requires pointer for result"; + return success(); + } + case cir::CastKind::ptr_to_int: { + if (!srcType.dyn_cast()) + return emitOpError() << "requires pointer for source"; + if (!resType.dyn_cast()) + return emitOpError() << "requires integer for result"; + return success(); + } } llvm_unreachable("Unknown CastOp kind?"); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index ca825a43dcad..4c870693b648 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -250,6 +250,22 @@ class CIRCastOpLowering : public mlir::OpConversionPattern { return castOp.emitError() << "NYI cast from " << srcTy << " to " << dstTy; } + case mlir::cir::CastKind::int_to_ptr: { + auto dstTy = castOp.getType().cast(); + auto llvmSrcVal = adaptor.getOperands().front(); + auto llvmDstTy = getTypeConverter()->convertType(dstTy); + rewriter.replaceOpWithNewOp(castOp, llvmDstTy, + llvmSrcVal); + return mlir::success(); + } + case mlir::cir::CastKind::ptr_to_int: { + auto dstTy = castOp.getType().cast(); + auto llvmSrcVal = adaptor.getOperands().front(); + auto llvmDstTy = getTypeConverter()->convertType(dstTy); + rewriter.replaceOpWithNewOp(castOp, llvmDstTy, + llvmSrcVal); + return mlir::success(); + } default: llvm_unreachable("NYI"); } @@ -489,6 +505,14 @@ class CIRConstantLowering op.getValue().cast().getValue()); } else if (op.getType().isa()) { attr = op.getValue(); + } else if (op.getType().isa()) { + // Optimize with dedicated LLVM op for null pointers. + if (op.getValue().isa()) { + rewriter.replaceOpWithNewOp( + op, typeConverter->convertType(op.getType())); + return mlir::success(); + } + attr = op.getValue(); } else return op.emitError("unsupported constant type"); diff --git a/clang/test/CIR/CodeGen/cast.cpp b/clang/test/CIR/CodeGen/cast.cpp index 76fced2dc82b..9e5eed31fd2e 100644 --- a/clang/test/CIR/CodeGen/cast.cpp +++ b/clang/test/CIR/CodeGen/cast.cpp @@ -17,7 +17,7 @@ unsigned char cxxstaticcast_0(unsigned int x) { // CHECK: } -int cStyleCasts_0(unsigned x1, int x2, float x3) { +int cStyleCasts_0(unsigned x1, int x2, float x3, short x4) { // CHECK: cir.func @_{{.*}}cStyleCasts_0{{.*}} char a = (char)x1; // truncate @@ -42,6 +42,11 @@ int cStyleCasts_0(unsigned x1, int x2, float x3) { double g = (double)x3; // FP extension // %{{[0-9]+}} = cir.cast(floating, %{{[0-9]+}} : f32), f64 + long l = (long)(void*)x4; // Must sign extend before casting to pointer + // CHECK: %[[TMP:[0-9]+]] = cir.cast(integral, %{{[0-9]+}} : !s16i), !u64i + // CHECK: %[[TMP2:[0-9]+]] = cir.cast(int_to_ptr, %[[TMP]] : !u64i), !cir.ptr + // CHECK: %{{[0-9]+}} = cir.cast(ptr_to_int, %[[TMP2]] : !cir.ptr), !s64i + return 0; } diff --git a/clang/test/CIR/Lowering/cast.cir b/clang/test/CIR/Lowering/cast.cir index 88d3ce2de8bf..4f7a82b265d4 100644 --- a/clang/test/CIR/Lowering/cast.cir +++ b/clang/test/CIR/Lowering/cast.cir @@ -6,6 +6,7 @@ !s8i = !cir.int !u32i = !cir.int !u8i = !cir.int +!u64i = !cir.int module { cir.func @foo(%arg0: !s32i) -> !s32i { @@ -31,6 +32,7 @@ module { // MLIR: llvm.func @cStyleCasts(%arg0: i32, %arg1: i32) -> i32 { %0 = cir.alloca !u32i, cir.ptr , ["x1", init] {alignment = 4 : i64} %1 = cir.alloca !s32i, cir.ptr , ["x2", init] {alignment = 4 : i64} + %20 = cir.alloca !s16i, cir.ptr , ["x4", init] {alignment = 2 : i64} %2 = cir.alloca !s32i, cir.ptr , ["__retval"] {alignment = 4 : i64} %3 = cir.alloca !s8i, cir.ptr , ["a", init] {alignment = 1 : i64} %4 = cir.alloca !s16i, cir.ptr , ["b", init] {alignment = 2 : i64} @@ -59,6 +61,13 @@ module { %17 = cir.cast(array_to_ptrdecay, %7 : !cir.ptr>), !cir.ptr // MLIR: %{{[0-9]+}} = llvm.getelementptr %{{[0-9]+}}[0] : (!llvm.ptr>) -> !llvm.ptr cir.store %17, %8 : !cir.ptr, cir.ptr > + %21 = cir.load %20 : cir.ptr , !s16i + %22 = cir.cast(integral, %21 : !s16i), !u64i + // MLIR: %[[TMP:[0-9]+]] = llvm.sext %{{[0-9]+}} : i16 to i64 + %23 = cir.cast(int_to_ptr, %22 : !u64i), !cir.ptr + // MLIR: %[[TMP2:[0-9]+]] = llvm.inttoptr %[[TMP]] : i64 to !llvm.ptr + %24 = cir.cast(ptr_to_int, %23 : !cir.ptr), !s32i + // MLIR: %{{[0-9]+}} = llvm.ptrtoint %[[TMP2]] : !llvm.ptr to i32 %18 = cir.const(#cir.int<0> : !s32i) : !s32i cir.store %18, %2 : !s32i, cir.ptr %19 = cir.load %2 : cir.ptr , !s32i