Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/IR/BuiltinOps.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/TypeSize.h"
Comment on lines +17 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all of these headers needed for your change?

https://llvm.org/docs/CodingStandards.html#include-as-little-as-possible


namespace cir {

Expand Down Expand Up @@ -81,6 +86,17 @@ class CIRDataLayout {
}

llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const;

llvm::TypeSize getPointerTypeSizeInBits(mlir::Type ty) const {
assert(mlir::isa<cir::PointerType>(Ty) &&
"This should only be called with a pointer type");
return layout.getTypeSizeInBits(Ty);
}

mlir::Type getIntPtrType(mlir::Type Ty) const {
assert(mlir::isa<cir::PointerType>(Ty) && "Expected pointer type");
return cir::IntType::get(ty.getContext(), getPointerTypeSizeInBits(ty), false);
}
};

} // namespace cir
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1889,6 +1889,27 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
}
return v;
}
case CK_IntegralToPointer: {
mlir:Type destCIRTy = cgf.convertType(destTy);
mlir::Value src = Visit(const_cast<Expr *>(subExpr));

// Properly resize by casting to an int of the same size as the pointer.
// Clang's IntegralToPointer includes 'bool' as the source, but in CIR
// 'bool' is not an integral type. So check the source type to get the
// correct CIR conversion.
mlirType middleTy = cgf.cgm.getDataLayout().getIntPtrType(destCIRTy);
cir::CastOp middleVal = builder.createCast(subExpr->getType()->isBooleanType()
? cir::CastKind::bool_to_int
: cir::CastKind::integral,
src, middleTy);

if (cgf.cgm.getCodeGenOpts().StrictVTablePointers) {
cgf.cgm.errorNYI(subExpr->getSourceRange(), "IntegralToPointer: strict vtable pointers");
return {};
}

return builder.createIntToPtr(middleVal, destCIRTy);
}

case CK_ArrayToPointerDecay:
return cgf.emitArrayToPointerDecay(subExpr).getPointer();
Expand Down
22 changes: 22 additions & 0 deletions clang/test/CIR/CodeGen/cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,25 @@ void bitcast() {

// LLVM: %[[D_VEC:.*]] = load <2 x double>, ptr {{.*}}, align 16
// LLVM: %[[I_VEC:.*]] = bitcast <2 x double> %[[D_VEC]] to <4 x i32>

void f(long int start) {
void *p = (void*)start;
}
// CIR: %[[L:.*]] = cir.load {{.*}} : !cir.ptr<!s64i>, !s64i
// CIR: %[[MID:.*]] = cir.cast integral %[[L]] : !s64i -> !u64i
// CIR: cir.cast int_to_ptr %[[MID]] : !u64i -> !cir.ptr<!void>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add LLVM checks here?


struct A { int x; };

void int_cast(long ptr) {
((A *)ptr)->x = 0;
}
// CIR: cir.cast int_to_ptr {{.*}} : !u64i -> !cir.ptr<!rec_A>
// LLVM: inttoptr {{.*}} to ptr

void null_cast(long) {
*(int *)0 = 0;
((A *)0)->x = 0;
}
// CIR: #cir.ptr<null> : !cir.ptr<!s32i>
// CIR: #cir.ptr<null> : !cir.ptr<!rec_A>
Comment on lines +154 to +155
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks need to be expanded. The CIR generated should look like this:

    %1 = cir.const #cir.int<0> : !s32i
    %2 = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
    cir.store align(4) %1, %2 : !s32i, !cir.ptr<!s32i>
    %3 = cir.const #cir.int<0> : !s32i
    %4 = cir.const #cir.ptr<null> : !cir.ptr<!rec_A>
    %5 = cir.get_member %4[0] {name = "x"} : !cir.ptr<!rec_A> -> !cir.ptr<!s32i>
    cir.store align(4) %3, %5 : !s32i, !cir.ptr<!s32i>

The point of the test is to verify that we're using a null pointer in the expected instructions, so I'd check at least that (and always use regex substitutions for SSA values):

// CIR:    %[[NULLPTR:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
// CIR:    cir.store{{.*}} %{{.*}}, %[[NULLPTR]] : !s32i, !cir.ptr<!s32i>
// CIR:    %[[NULLPTR_A:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_A>
// CIR:    %[[A_X:.*]] = cir.get_member %[[NULLPTR_A]][0] {name = "x"} : !cir.ptr<!rec_A> -> !cir.ptr<!s32i>

Note that I've used %{{.*}} for the value being stored in the second line, because we don't need to test that here. Also note, I used {{.*}} following cir.store so that this test will pass with or without an alignment specifier, because that's not relevant to this test and we wouldn't want to have to update this test if alignment behavior is changed in the future.

Nothing specific to casts is being lowered to LLVM IR, so I don't think LLVM checks are needed here.

Loading