Skip to content
Merged
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
27 changes: 26 additions & 1 deletion clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,9 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {

mlir::Value createPtrBitcast(mlir::Value src, mlir::Type newPointeeTy) {
assert(mlir::isa<cir::PointerType>(src.getType()) && "expected ptr src");
return createBitcast(src, getPointerTo(newPointeeTy));
auto srcPtrTy = mlir::cast<cir::PointerType>(src.getType());
mlir::Type newPtrTy = getPointerTo(newPointeeTy, srcPtrTy.getAddrSpace());
return createBitcast(src, newPtrTy);
}

mlir::Value createAddrSpaceCast(mlir::Location loc, mlir::Value src,
Expand All @@ -586,6 +588,29 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
return createAddrSpaceCast(src.getLoc(), src, newTy);
}

mlir::Value createPointerBitCastOrAddrSpaceCast(mlir::Location loc,
mlir::Value src,
mlir::Type newPointerTy) {
assert(mlir::isa<cir::PointerType>(src.getType()) &&
"expected source pointer");
assert(mlir::isa<cir::PointerType>(newPointerTy) &&
"expected destination pointer type");

auto srcPtrTy = mlir::cast<cir::PointerType>(src.getType());
auto dstPtrTy = mlir::cast<cir::PointerType>(newPointerTy);

mlir::Value addrSpaceCasted = src;
if (srcPtrTy.getAddrSpace() != dstPtrTy.getAddrSpace())
addrSpaceCasted = createAddrSpaceCast(loc, src, dstPtrTy);

return createPtrBitcast(addrSpaceCasted, dstPtrTy.getPointee());
}

mlir::Value createPointerBitCastOrAddrSpaceCast(mlir::Value src,
mlir::Type newPointerTy) {
return createPointerBitCastOrAddrSpaceCast(src.getLoc(), src, newPointerTy);
}

mlir::Value createPtrIsNull(mlir::Value ptr) {
return createNot(createPtrToBoolCast(ptr));
}
Expand Down
76 changes: 75 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,81 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
mlir::Value VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
llvm_unreachable("NYI");
}
mlir::Value VisitAsTypeExpr(AsTypeExpr *E) { llvm_unreachable("NYI"); }

// Create cast instructions for converting LLVM value Src to MLIR type DstTy.
// Src has the same size as DstTy. Both are single value types
// but could be scalar or vectors of different lengths, and either can be
// pointer.
mlir::Value createCastsForTypeOfSameSize(mlir::Value Src, mlir::Type DstTy) {
auto SrcTy = Src.getType();

// Case 1.
if (!isa<cir::PointerType>(SrcTy) && !isa<cir::PointerType>(DstTy))
return Builder.createBitcast(Src, DstTy);

// Case 2.
if (isa<cir::PointerType>(SrcTy) && isa<cir::PointerType>(DstTy))
return Builder.createPointerBitCastOrAddrSpaceCast(Src, DstTy);

// Case 3.
if (isa<cir::PointerType>(SrcTy) && !isa<cir::PointerType>(DstTy)) {
// Case 3b.
if (!Builder.isInt(DstTy))
llvm_unreachable("NYI");
// Cases 3a and 3b.
llvm_unreachable("NYI");
}

// Case 4b.
if (!Builder.isInt(SrcTy))
llvm_unreachable("NYI");

// Cases 4a and 4b.
llvm_unreachable("NYI");
}

mlir::Value VisitAsTypeExpr(AsTypeExpr *E) {
unsigned numSrcElems = 0;
QualType qualSrcTy = E->getSrcExpr()->getType();
mlir::Type srcTy = CGF.convertType(qualSrcTy);
if (auto v = dyn_cast<cir::VectorType>(srcTy)) {
assert(!cir::MissingFeatures::scalableVectors() &&
"NYI: non-fixed (scalable) vector src");
numSrcElems = v.getSize();
}

unsigned numDstElems = 0;
QualType qualDstTy = E->getType();
mlir::Type dstTy = CGF.convertType(qualDstTy);
if (auto v = dyn_cast<cir::VectorType>(dstTy)) {
assert(!cir::MissingFeatures::scalableVectors() &&
"NYI: non-fixed (scalable) vector dst");
numDstElems = v.getSize();
}

// Use bit vector expansion for ext_vector_type boolean vectors.
if (qualDstTy->isExtVectorBoolType()) {
llvm_unreachable("NYI");
}

// Going from vec3 to non-vec3 is a special case and requires a shuffle
// vector to get a vec4, then a bitcast if the target type is different.
if (numSrcElems == 3 && numDstElems != 3) {
llvm_unreachable("NYI");
}

// Going from non-vec3 to vec3 is a special case and requires a bitcast
// to vec4 if the original type is not vec4, then a shuffle vector to
// get a vec3.
if (numSrcElems != 3 && numDstElems == 3) {
llvm_unreachable("NYI");
}

// Otherwise, fallback to bitcast of same size
mlir::Value src = CGF.emitScalarExpr(E->getSrcExpr());
return createCastsForTypeOfSameSize(src, dstTy);
}

mlir::Value VisitAtomicExpr(AtomicExpr *E) {
return CGF.emitAtomicExpr(E).getScalarVal();
}
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,10 @@ LogicalResult cir::CastOp::verify() {
auto resPtrTy = mlir::dyn_cast<cir::PointerType>(resType);
if (!srcPtrTy || !resPtrTy)
return emitOpError() << "requires !cir.ptr type for source and result";
if (srcPtrTy.getPointee() != resPtrTy.getPointee())
return emitOpError() << "requires two types differ in addrspace only";
// Address space verification is sufficient here. The pointee types need not
// be verified as they are handled by bitcast verification logic, which
// ensures address space compatibility. Verifying pointee types would create
// a circular dependency between address space and pointee type casting.
return success();
}
case cir::CastKind::float_to_complex: {
Expand Down
55 changes: 55 additions & 0 deletions clang/test/CIR/CodeGen/OpenCL/as_type.cl
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// RUN: %clang_cc1 %s -cl-std=CL2.0 -fclangir -emit-cir -triple spirv64-unknown-unknown -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll --check-prefix=CIR

// RUN: %clang_cc1 %s -cl-std=CL2.0 -fclangir -emit-llvm -triple spirv64-unknown-unknown -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll --check-prefix=LLVM

// RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -triple spirv64-unknown-unknown -o %t.ll
// RUN: FileCheck %s --input-file=%t.ll --check-prefix=OG-LLVM

typedef __attribute__(( ext_vector_type(4) )) char char4;

// CIR: cir.func @f4(%{{.*}}: !s32i loc({{.*}})) -> !cir.vector<!s8i x 4>
// CIR: %[[x:.*]] = cir.load align(4) %{{.*}} : !cir.ptr<!s32i, addrspace(offload_private)>
// CIR: cir.cast bitcast %[[x]] : !s32i -> !cir.vector<!s8i x 4>
// LLVM: define spir_func <4 x i8> @f4(i32 %[[x:.*]])
// LLVM: %[[astype:.*]] = bitcast i32 %[[x]] to <4 x i8>
// LLVM-NOT: shufflevector
// LLVM: ret <4 x i8> %[[astype]]
// OG-LLVM: define spir_func noundef <4 x i8> @f4(i32 noundef %[[x:.*]])
// OG-LLVM: %[[astype:.*]] = bitcast i32 %[[x]] to <4 x i8>
// OG-LLVM-NOT: shufflevector
// OG-LLVM: ret <4 x i8> %[[astype]]
char4 f4(int x) {
return __builtin_astype(x, char4);
}

// CIR: cir.func @f6(%{{.*}}: !cir.vector<!s8i x 4> loc({{.*}})) -> !s32i
// CIR: %[[x:.*]] = cir.load align(4) %{{.*}} : !cir.ptr<!cir.vector<!s8i x 4>, addrspace(offload_private)>, !cir.vector<!s8i x 4>
// CIR: cir.cast bitcast %[[x]] : !cir.vector<!s8i x 4> -> !s32i
// LLVM: define{{.*}} spir_func i32 @f6(<4 x i8> %[[x:.*]])
// LLVM: %[[astype:.*]] = bitcast <4 x i8> %[[x]] to i32
// LLVM-NOT: shufflevector
// LLVM: ret i32 %[[astype]]
// OG-LLVM: define{{.*}} spir_func noundef i32 @f6(<4 x i8> noundef %[[x:.*]])
// OG-LLVM: %[[astype:.*]] = bitcast <4 x i8> %[[x]] to i32
// OG-LLVM-NOT: shufflevector
// OG-LLVM: ret i32 %[[astype]]
int f6(char4 x) {
return __builtin_astype(x, int);
}

// CIR: cir.func @f4_ptr(%{{.*}}: !cir.ptr<!s32i, addrspace(offload_global)> loc({{.*}})) -> !cir.ptr<!cir.vector<!s8i x 4>, addrspace(offload_local)>
// CIR: %[[x:.*]] = cir.load align(8) %{{.*}} : !cir.ptr<!cir.ptr<!s32i, addrspace(offload_global)>, addrspace(offload_private)>, !cir.ptr<!s32i, addrspace(offload_global)>
// CIR: cir.cast address_space %[[x]] : !cir.ptr<!s32i, addrspace(offload_global)> -> !cir.ptr<!cir.vector<!s8i x 4>, addrspace(offload_local)>
// LLVM: define spir_func ptr addrspace(3) @f4_ptr(ptr addrspace(1) readnone captures(ret: address, provenance) %[[x:.*]])
// LLVM: %[[astype:.*]] = addrspacecast ptr addrspace(1) %[[x]] to ptr addrspace(3)
// LLVM-NOT: shufflevector
// LLVM: ret ptr addrspace(3) %[[astype]]
// OG-LLVM: define spir_func ptr addrspace(3) @f4_ptr(ptr addrspace(1) noundef readnone captures(ret: address, provenance) %[[x:.*]])
// OG-LLVM: %[[astype:.*]] = addrspacecast ptr addrspace(1) %[[x]] to ptr addrspace(3)
// OG-LLVM-NOT: shufflevector
// OG-LLVM: ret ptr addrspace(3) %[[astype]]
__local char4* f4_ptr(__global int* x) {
return __builtin_astype(x, __local char4*);
}
9 changes: 0 additions & 9 deletions clang/test/CIR/IR/invalid.cir
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,6 @@ cir.func @cast24(%p : !u32i) {

// -----

!u32i = !cir.int<u, 32>
!u64i = !cir.int<u, 64>
cir.func @cast25(%p : !cir.ptr<!u32i, addrspace(target<1>)>) {
%0 = cir.cast address_space %p : !cir.ptr<!u32i, addrspace(target<1>)> -> !cir.ptr<!u64i, addrspace(target<2>)> // expected-error {{requires two types differ in addrspace only}}
cir.return
}

// -----

!u64i = !cir.int<u, 64>
cir.func @cast26(%p : !cir.ptr<!u64i, addrspace(target<1>)>) {
%0 = cir.cast address_space %p : !cir.ptr<!u64i, addrspace(target<1>)> -> !u64i // expected-error {{requires !cir.ptr type for source and result}}
Expand Down