Author: Akimasa Watanuki Date: 2026-10-21T13:52:50-05:00 New Revision: a171e0d7dfca389be0f319fea7c8e66e86ac4be3
URL: https://github.com/llvm/llvm-project/commit/a171e0d7dfca389be0f319fea7c8e66e86ac4be3 DIFF: https://github.com/llvm/llvm-project/commit/a171e0d7dfca389be0f319fea7c8e66e86ac4be3.diff LOG: [CIR] Reject language address spaces in DirectToLLVM pointer conversion (#224239) Reject unlowered language address spaces in pointer types when bypassing TargetLowering. Guard pointer-producing lowerings, including generated patterns, so failed conversions report legalization failures instead of silently selecting address space zero or constructing invalid LLVM operations. Assisted-by: Codex / GPT-6 Added: clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir Modified: clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/test/CIR/Lowering/unlowered-address-spaces.cir clang/utils/TableGen/CIRLoweringEmitter.cpp Removed: ################################################################################ diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index df55be21762547..719ec9ac184ff6 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -359,6 +359,11 @@ convertFramePointerKindToLLVMIR(cir::FramePointerKind kind) { mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite( cir::CopyOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { + // Opaque pointer conversion does not validate the pointee's memory layout. + mlir::Type pointeeType = op.getType().getPointee(); + if (!convertTypeForMemory(*getTypeConverter(), dataLayout, pointeeType)) + return emitTypeConversionError(op, pointeeType); + mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); const mlir::Value length = mlir::LLVM::ConstantOp::create( rewriter, op.getLoc(), rewriter.getI64Type(), @@ -1932,6 +1937,8 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite( mlir::Type targetType = convertTy(ptrTy); mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout, ptrTy.getPointee()); + if (!elementTy) + return emitTypeConversionError(castOp, ptrTy.getPointee()); llvm::SmallVector<mlir::LLVM::GEPArg> offset{0}; rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>( castOp, targetType, elementTy, sourceValue, offset); @@ -2225,6 +2232,8 @@ mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite( mlir::Type elementTy = convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementType()); + if (!elementTy) + return emitTypeConversionError(ptrStrideOp, ptrStrideOp.getElementType()); // void and function types doesn't really have a layout to use in GEPs, // make it i8 instead. @@ -2251,6 +2260,8 @@ mlir::LogicalResult CIRToLLVMGetElementOpLowering::matchAndRewrite( mlir::dyn_cast<cir::ArrayType>(op.getBaseType().getPointee())) { const mlir::TypeConverter *converter = getTypeConverter(); const mlir::Type llArrayTy = converter->convertType(arrayTy); + if (!llArrayTy) + return emitTypeConversionError(op, arrayTy); const mlir::Type llResultTy = converter->convertType(op.getType()); mlir::Type elementTy = convertTypeForMemory(*converter, dataLayout, op.getElementType()); @@ -2285,6 +2296,8 @@ mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type resultType = getTypeConverter()->convertType(baseClassOp.getType()); + if (!resultType) + return emitTypeConversionError(baseClassOp, baseClassOp.getType()); mlir::Value derivedAddr = adaptor.getSrcAddr(); llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = { adaptor.getOffset().getZExtValue()}; @@ -2317,6 +2330,8 @@ mlir::LogicalResult CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type resultType = getTypeConverter()->convertType(derivedClassOp.getType()); + if (!resultType) + return emitTypeConversionError(derivedClassOp, derivedClassOp.getType()); mlir::Value baseAddr = adaptor.getSrcAddr(); // The offset is set in the operation as an unsigned value, but it must be // applied as a negative offset. @@ -2405,6 +2420,8 @@ mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite( << "NYI: lowering alloca of a type with no memory representation"; mlir::Type resultTy = convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType(), isForHLSL); + if (!resultTy) + return emitTypeConversionError(op, op.getType()); assert(!cir::MissingFeatures::addressSpace()); assert(!cir::MissingFeatures::opAllocaAnnotations()); @@ -2661,6 +2678,8 @@ mlir::LogicalResult CIRToLLVMFrameAddrOpLowering::matchAndRewrite( cir::FrameAddrOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type llvmPtrTy = getTypeConverter()->convertType(op.getType()); + if (!llvmPtrTy) + return emitTypeConversionError(op, op.getType()); replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.frameaddress", llvmPtrTy, adaptor.getOperands()); return mlir::success(); @@ -2683,6 +2702,8 @@ mlir::LogicalResult CIRToLLVMAddrOfReturnAddrOpLowering::matchAndRewrite( cir::AddrOfReturnAddrOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type llvmPtrTy = getTypeConverter()->convertType(op.getType()); + if (!llvmPtrTy) + return emitTypeConversionError(op, op.getType()); replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.addressofreturnaddress", llvmPtrTy, adaptor.getOperands()); return mlir::success(); @@ -2694,8 +2715,7 @@ mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite( const mlir::Type llvmTy = convertTypeForLoadStore(*getTypeConverter(), dataLayout, op.getType()); if (!llvmTy) - return op.emitError() - << "NYI: lowering load of a type with no memory representation"; + return emitTypeConversionError(op, op.getType()); mlir::LLVM::AtomicOrdering ordering = getLLVMMemOrder(op.getMemOrder()); std::optional<size_t> opAlign = op.getAlignment(); unsigned alignment = (unsigned)opAlign.value_or( @@ -2976,6 +2996,10 @@ mlir::LogicalResult CIRToLLVMPrefetchOpLowering::matchAndRewrite( mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( cir::PtrDiffOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type pointeeType = op.getLhs().getType().getPointee(); + if (!convertTypeForMemory(*getTypeConverter(), dataLayout, pointeeType)) + return emitTypeConversionError(op, pointeeType); + auto dstTy = mlir::cast<cir::IntType>(op.getType()); mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy); @@ -2987,9 +3011,8 @@ mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite( auto diff = mlir::LLVM::SubOp::create(rewriter, op.getLoc(), llvmDstTy, lhs, rhs); - cir::PointerType ptrTy = op.getLhs().getType(); assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee()); - uint64_t typeSize = getTypeAllocSize(ptrTy.getPointee(), *op); + uint64_t typeSize = getTypeAllocSize(pointeeType, *op); // Avoid silly division by 1. mlir::Value resultVal = diff .getResult(); @@ -3265,6 +3288,8 @@ mlir::LogicalResult CIRToLLVMGetGlobalOpLowering::matchAndRewrite( } mlir::Type type = getTypeConverter()->convertType(op.getType()); + if (!type) + return emitTypeConversionError(op, op.getType()); mlir::Operation *newop = mlir::LLVM::AddressOfOp::create( rewriter, op.getLoc(), type, op.getName()); @@ -4306,6 +4331,9 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, mlir::ptr::MemorySpaceAttrInterface addrSpaceAttr = type.getAddrSpace(); unsigned numericAS = 0; + if (mlir::isa_and_present<cir::LangAddressSpaceAttr>(addrSpaceAttr)) + return {}; + if (auto targetAsAttr = mlir::dyn_cast_if_present<cir::TargetAddressSpaceAttr>( addrSpaceAttr)) @@ -4341,6 +4369,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, intTy && intTy.isBitInt()) return {}; const mlir::Type ty = converter.convertType(type.getElementType()); + if (!ty) + return {}; return mlir::VectorType::get(type.getSize(), ty, {type.getIsScalable()}); }); converter.addConversion([&](cir::MatrixType type) -> mlir::Type { @@ -4943,6 +4973,8 @@ mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite( cir::GetMemberOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::Type llResTy = getTypeConverter()->convertType(op.getType()); + if (!llResTy) + return emitTypeConversionError(op, op.getType()); mlir::Type pointee = op.getAddrTy().getPointee(); if (mlir::isa<cir::UnionType>(pointee)) { @@ -4961,6 +4993,8 @@ mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite( llvm::SmallVector<mlir::LLVM::GEPArg, 2> offset{ 0, static_cast<int32_t>(structTy.getLLVMFieldIndex(op.getIndex()))}; const mlir::Type elementTy = getTypeConverter()->convertType(structTy); + if (!elementTy) + return emitTypeConversionError(op, structTy); // Struct member accesses are always inbounds and nuw: the base pointer // is valid and the member offset is a positive, constant offset within // the struct layout, so it cannot wrap. This matches LLVM's @@ -5335,6 +5369,8 @@ mlir::LogicalResult CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite( cir::VTableGetVirtualFnAddrOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::Type targetType = getTypeConverter()->convertType(op.getType()); + if (!targetType) + return emitTypeConversionError(op, op.getType()); auto eltType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); llvm::SmallVector<mlir::LLVM::GEPArg> offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{op.getIndex()}; @@ -5348,6 +5384,8 @@ mlir::LogicalResult CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite( cir::VTTAddrPointOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { const mlir::Type resultType = getTypeConverter()->convertType(op.getType()); + if (!resultType) + return emitTypeConversionError(op, op.getType()); llvm::SmallVector<mlir::LLVM::GEPArg> offsets; mlir::Type eltType; mlir::Value llvmAddr = adaptor.getSymAddr(); @@ -6107,6 +6145,8 @@ mlir::LogicalResult CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { cir::PointerType operandTy = op.getOperand().getType(); mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType()); + if (!resultLLVMTy) + return emitTypeConversionError(op, op.getType()); mlir::Type elementLLVMTy = getTypeConverter()->convertType(operandTy.getPointee()); @@ -6124,6 +6164,8 @@ mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { cir::PointerType operandTy = op.getOperand().getType(); mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType()); + if (!resultLLVMTy) + return emitTypeConversionError(op, op.getType()); mlir::Type elementLLVMTy = getTypeConverter()->convertType(operandTy.getPointee()); @@ -6222,8 +6264,11 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite( llvm::SmallVector<mlir::NamedAttribute, 1> attrs; cir::PointerType typ = mlir::cast<cir::PointerType>(cirOp.getType()); - mlir::TypeAttr typAttr = mlir::TypeAttr::get(convertTypeForMemory( - *getTypeConverter(), dataLayout, typ.getPointee())); + mlir::Type elementTy = + convertTypeForMemory(*getTypeConverter(), dataLayout, typ.getPointee()); + if (!elementTy) + return emitTypeConversionError(op, typ.getPointee()); + mlir::TypeAttr typAttr = mlir::TypeAttr::get(elementTy); attrs.push_back(rewriter.getNamedAttr(llvmAttrName, typAttr)); mlir::DictionaryAttr newDict = rewriter.getDictionaryAttr(attrs); diff --git a/clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir b/clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir new file mode 100644 index 00000000000000..90b6d229621582 --- /dev/null +++ b/clang/test/CIR/Lowering/opaque-pointer-address-spaces.cir @@ -0,0 +1,153 @@ +// RUN: cir-opt %s --split-input-file --cir-to-llvm | FileCheck %s + +// Only the pointer's own address space is needed for an opaque LLVM pointer. +// Language address spaces in its pointee do not prevent pointer conversion. + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @nested_language_address_space + // CHECK-SAME: !llvm.ptr + cir.func @nested_language_address_space(%arg0: !cir.ptr<!cir.ptr<!s32i, lang_address_space(offload_local)>>) { + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)> +!outer = !cir.ptr<!langptr, target_address_space(3)> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @outer_target_address_space + // CHECK-SAME: %[[ARG:.*]]: !llvm.ptr<3>) -> !llvm.ptr<3> + cir.func @outer_target_address_space(%ptr: !outer) -> !outer { + // CHECK: llvm.return %[[ARG]] : !llvm.ptr<3> + cir.return %ptr : !outer + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!rec_Node = !cir.struct<"Node" {data !cir.ptr<!cir.struct<"Node">>, data !cir.ptr<!s32i, lang_address_space(offload_global)>}> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @recursive_struct_language_address_space + // CHECK-SAME: !llvm.ptr + cir.func @recursive_struct_language_address_space(%arg0: !cir.ptr<!rec_Node>) { + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!rec_U = !cir.union<"U" {data !s32i, data !cir.ptr<!s32i, lang_address_space(offload_global)>}> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @union_language_address_space + // CHECK-SAME: !llvm.ptr + cir.func @union_language_address_space(%arg0: !cir.ptr<!rec_U>) { + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @function_and_array_language_address_space + // CHECK-SAME: !llvm.ptr + cir.func @function_and_array_language_address_space( + %arg0: !cir.ptr<!cir.func<(!cir.ptr<!cir.array<!cir.ptr<!s32i, lang_address_space(offload_constant)> x 4>>)>>) { + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!rec_Foo = !cir.struct<"Foo" {data !s32i}> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @data_member_language_address_space + // CHECK-SAME: !llvm.ptr + cir.func @data_member_language_address_space( + %arg0: !cir.ptr<!cir.data_member<!cir.ptr<!s32i, lang_address_space(offload_global)> in !rec_Foo>>) { + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!rec_Foo = !cir.struct<"Foo" {data !s32i}> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // CHECK-LABEL: llvm.func @method_language_address_space + // CHECK-SAME: !llvm.ptr + cir.func @method_language_address_space( + %arg0: !cir.ptr<!cir.method<!cir.func<(!cir.ptr<!s32i, lang_address_space(offload_global)>)> in !rec_Foo>>) { + cir.return + } +} + +// ----- + +!s64i = !cir.int<s, 64> +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)> +!ptr = !cir.ptr<!langptr> + +module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = "e-p:64:64-p3:32:32"} { + // The stored pointer has a known layout even though its pointee does not. + // CHECK-LABEL: llvm.func @copy_opaque_pointers + cir.func @copy_opaque_pointers(%src: !cir.ptr<!ptr>, %dst: !cir.ptr<!ptr>) { + // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(8 : i64) + // CHECK: "llvm.intr.memcpy"(%{{.*}}, %{{.*}}, %[[SIZE]]) + cir.copy %src to %dst : !cir.ptr<!ptr> + cir.return + } + + // CHECK-LABEL: llvm.func @ diff _opaque_pointers + cir.func @ diff _opaque_pointers(%lhs: !cir.ptr<!ptr>, %rhs: !cir.ptr<!ptr>) -> !s64i { + // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(8 : i64) + // CHECK: llvm.sdiv exact %{{.*}}, %[[SIZE]] : i64 + % diff = cir.ptr_ diff %lhs, %rhs : !cir.ptr<!ptr> -> !s64i + cir.return % diff : !s64i + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!rec_Base = !cir.struct<"Base" {data !s32i}> +!rec_Derived = !cir.struct<"Derived" {data !cir.ptr<!s32i, lang_address_space(offload_global)>, data !rec_Base}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // CHECK-LABEL: llvm.func @derived_class_addr_language_address_space + cir.func @derived_class_addr_language_address_space() { + %base = cir.alloca "base" align(4) : !cir.ptr<!rec_Base> + // CHECK: llvm.getelementptr inbounds {{.*}}[-4] : (!llvm.ptr) -> !llvm.ptr, i8 + %derived = cir.derived_class_addr nonnull %base [4] : !cir.ptr<!rec_Base> -> !cir.ptr<!rec_Derived> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> +!fn = !cir.func<() -> !langptr> +!fnptr = !cir.ptr<!fn> +!fnptrptr = !cir.ptr<!fnptr> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // CHECK-LABEL: llvm.func @virtual_fn_addr_language_address_space + cir.func @virtual_fn_addr_language_address_space(%vptr: !cir.vptr) { + // CHECK: llvm.getelementptr {{.*}}[0] : (!llvm.ptr) -> !llvm.ptr, !llvm.ptr + %0 = cir.vtable.get_virtual_fn_addr %vptr[0] : !cir.vptr -> !fnptrptr + cir.return + } +} diff --git a/clang/test/CIR/Lowering/unlowered-address-spaces.cir b/clang/test/CIR/Lowering/unlowered-address-spaces.cir index 0faf18e5d0067c..32a80f537d503b 100644 --- a/clang/test/CIR/Lowering/unlowered-address-spaces.cir +++ b/clang/test/CIR/Lowering/unlowered-address-spaces.cir @@ -2,8 +2,567 @@ !s32i = !cir.int<s, 32> +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.func'}} + cir.func @language_address_space(%arg0: !cir.ptr<!s32i, lang_address_space(offload_global)>) { + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.func'}} + cir.func private @language_address_space_return() -> !cir.ptr<!s32i, lang_address_space(offload_global)> +} + +// ----- + +!s32i = !cir.int<s, 32> + module attributes {cir.triple = "spirv64-unknown-unknown"} { // expected-error @below {{cannot lower a global with a language address space}} // expected-error @below {{failed to legalize operation 'cir.global'}} cir.global external lang_address_space(offload_global) @global = #cir.int<1> : !s32i } + +// ----- + +!s64i = !cir.int<s, 64> +!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)> +!rec_U = !cir.union<"U" {data !s64i, data !langptr}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // The union's integer storage converts, but its active initializer does not. + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @union_active_initializer_language_address_space = #cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // Unlike direct cir.func lowering, a global view can request FuncType + // conversion before its referenced function is lowered. + cir.global external @function_pointer = #cir.global_view<@global_view_callee> : !cir.ptr<!cir.void> + + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.func'}} + cir.func private @global_view_callee() -> !cir.ptr<!s32i, lang_address_space(offload_global)> +} + +// ----- + +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Keep the view before its target so the initializer is lowered first. + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @view = #cir.global_view<@target, [0 : i32]> : !cir.ptr<!cir.void> + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> +!ptrarray = !cir.array<!ptr x 1> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @view = #cir.const_array<[#cir.global_view<@target, [0 : i32]> : !ptr]> : !ptrarray + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> +!record = !cir.struct<{data !ptr}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @view = #cir.const_record<{#cir.global_view<@target, [0 : i32]> : !ptr}> : !record + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> +!record = !cir.struct<{data !ptr}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @view = #cir.typeinfo<{#cir.global_view<@target, [0 : i32]> : !ptr}> : !record + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> +!ptrarray = !cir.array<!ptr x 1> +!vtable = !cir.struct<{data !ptrarray}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @view = #cir.vtable<{#cir.const_array<[#cir.global_view<@target, [0 : i32]> : !ptr]> : !ptrarray}> : !vtable + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // Keep the function before the global so get_global is lowered first. + cir.func @get_global_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.get_global'}} + %0 = cir.get_global @global : !cir.ptr<!s32i, lang_address_space(offload_global)> + %1 = cir.load %0 : !cir.ptr<!s32i, lang_address_space(offload_global)>, !s32i + cir.return + } + + cir.global external lang_address_space(offload_global) @global = #cir.int<1> : !s32i +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + cir.func @alloca_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_private)>'}} + // expected-error @below {{failed to legalize operation 'cir.alloca'}} + %0 = cir.alloca "x" align(4) : !cir.ptr<!s32i, lang_address_space(offload_private)> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + // The argument lowers to an opaque pointer, but the load needs the inner type. + cir.func @load_language_address_space(%ptr: !cir.ptr<!langptr>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.load'}} + %0 = cir.load %ptr : !cir.ptr<!langptr>, !langptr + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)> + +module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = "e-p:64:64-p3:32:32"} { + // The copy needs the local pointer's layout, not the outer opaque pointer's. + // The default pointer layout would incorrectly copy 8 bytes with alignment 8. + cir.func @copy_language_address_space(%src: !cir.ptr<!langptr>, %dst: !cir.ptr<!langptr>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>'}} + // expected-error @below {{failed to legalize operation 'cir.copy'}} + cir.copy %src to %dst : !cir.ptr<!langptr> + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)> +!record = !cir.struct<{data !langptr}> + +module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = "e-p:64:64-p3:32:32"} { + // Validate the copied layout through aggregate members as well. + cir.func @copy_record_language_address_space(%src: !cir.ptr<!record>, %dst: !cir.ptr<!record>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.struct<{data !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>}>'}} + // expected-error @below {{failed to legalize operation 'cir.copy'}} + cir.copy %src to %dst : !cir.ptr<!record> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + cir.func @null_constant_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.ptr<null> : !cir.ptr<!s32i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + cir.func @constant_global_view_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.global_view<@target, [0 : i32]> : !ptr + cir.return + } + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + cir.func @constant_array_global_view_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.const_array<[#cir.global_view<@target, [0 : i32]> : !ptr]> : !cir.array<!ptr x 1> + cir.return + } + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the view before its target, including through enclosing attributes. + cir.func @constant_record_global_view_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.const_record<{#cir.global_view<@target, [0 : i32]> : !ptr}> : !cir.struct<{data !ptr}> + cir.return + } + + cir.global external @target = #cir.zero : !array +} + +// ----- + +!s64i = !cir.int<s, 64> +!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)> +!rec_U = !cir.union<"U" {data !s64i, data !langptr}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @constant_union_active_initializer_language_address_space() { + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U + cir.return + } +} + +// ----- + +!s64i = !cir.int<s, 64> +!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)> +!rec_U = !cir.union<"U" {data !s64i, data !langptr}> +!rec_Outer = !cir.union<"Outer" {data !s64i, data !rec_U}> +!rec_S = !cir.struct<"S" {data !rec_Outer}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Propagate adjustment failure through both the enclosing union and struct. + cir.func @constant_nested_union_initializer_language_address_space() { + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.const_record<{#cir.const_record<{#cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U}> : !rec_Outer}> : !rec_S + cir.return + } +} + +// ----- + +!s64i = !cir.int<s, 64> +!langptr = !cir.ptr<!cir.void, lang_address_space(offload_global)> +!rec_U = !cir.union<"U" {data !s64i, data !langptr}> +!array = !cir.array<!rec_U x 1> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @constant_union_array_initializer_language_address_space() { + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.const_array<[#cir.const_record<{#cir.ptr<null> : !langptr}> : !rec_U]> : !array + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + cir.func @int_to_ptr_language_address_space(%arg0: !s32i) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.cast'}} + %0 = cir.cast int_to_ptr %arg0 : !s32i -> !cir.ptr<!s32i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "spirv64-unknown-unknown"} { + cir.func @address_space_cast_language_address_space(%arg0: !cir.ptr<!s32i>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.cast'}} + %0 = cir.cast address_space %arg0 : !cir.ptr<!s32i> -> !cir.ptr<!s32i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +// These operations need the pointee layout to build a GEP. +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 4> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @array_decay_language_address_space(%ptr: !cir.ptr<!array>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.cast'}} + %0 = cir.cast array_to_ptrdecay %ptr : !cir.ptr<!array> -> !cir.ptr<!langptr> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @ptr_stride_language_address_space(%ptr: !cir.ptr<!langptr>, %idx: !s32i) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.ptr_stride'}} + %0 = cir.ptr_stride %ptr, %idx : (!cir.ptr<!langptr>, !s32i) -> !cir.ptr<!langptr> + cir.return + } +} + +// ----- + +!s64i = !cir.int<s, 64> +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)> + +module attributes {cir.triple = "amdgcn-amd-amdhsa", llvm.data_layout = "e-p:64:64-p3:32:32"} { + // Pointer diff erences must not divide by the default 8-byte pointer size. + cir.func @ptr_ diff _language_address_space(%lhs: !cir.ptr<!langptr>, %rhs: !cir.ptr<!langptr>) -> !s64i { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_local)>'}} + // expected-error @below {{failed to legalize operation 'cir.ptr_ diff '}} + % diff = cir.ptr_ diff %lhs, %rhs : !cir.ptr<!langptr> -> !s64i + cir.return % diff : !s64i + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 4> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @get_element_language_address_space(%ptr: !cir.ptr<!array>, %idx: !s32i) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 4>'}} + // expected-error @below {{failed to legalize operation 'cir.get_element'}} + %0 = cir.get_element %ptr[%idx : !s32i] : !cir.ptr<!array> -> !cir.ptr<!langptr> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> +!langptr = !cir.ptr<!s32i, lang_address_space(offload_global)> +!record = !cir.struct<{data !langptr}> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @get_member_language_address_space(%ptr: !cir.ptr<!record>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.struct<{data !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>}>'}} + // expected-error @below {{failed to legalize operation 'cir.get_member'}} + %0 = cir.get_member %ptr[0] {name = "p"} : !cir.ptr<!record> -> !cir.ptr<!langptr> + cir.return + } +} + +// ----- + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @complex_real_ptr_language_address_space(%ptr: !cir.ptr<!cir.complex<!cir.double>>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.double, lang_address_space(offload_private)>'}} + // expected-error @below {{failed to legalize operation 'cir.complex.real_ptr'}} + %real = cir.complex.real_ptr %ptr : !cir.ptr<!cir.complex<!cir.double>> -> !cir.ptr<!cir.double, lang_address_space(offload_private)> + cir.return + } +} + +// ----- + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @complex_imag_ptr_language_address_space(%ptr: !cir.ptr<!cir.complex<!cir.double>>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.double, lang_address_space(offload_private)>'}} + // expected-error @below {{failed to legalize operation 'cir.complex.imag_ptr'}} + %imag = cir.complex.imag_ptr %ptr : !cir.ptr<!cir.complex<!cir.double>> -> !cir.ptr<!cir.double, lang_address_space(offload_private)> + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the address point before its referenced global. + cir.func @vtable_symbol_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.struct<{data !cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>}>' for vtable symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.vtable.address_point'}} + %0 = cir.vtable.address_point(@target, address_point = <index = 0, offset = 0>) : !cir.vptr + cir.return + } + + cir.global "private" external @target : !cir.struct<{data !array}> +} + +// ----- + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @vtt_address_point_language_address_space( + %vtt: !cir.ptr<!cir.ptr<!cir.void>>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.ptr<!cir.void>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.vtt.address_point'}} + %0 = cir.vtt.address_point %vtt : !cir.ptr<!cir.ptr<!cir.void>>, offset = 1 -> !cir.ptr<!cir.ptr<!cir.void>, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> +!array = !cir.array<!langptr x 1> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the address point before its referenced global. + cir.func @vtt_symbol_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.array<!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> x 1>' for vtable symbol @target}} + // expected-error @below {{failed to legalize operation 'cir.vtt.address_point'}} + %0 = cir.vtt.address_point @target, offset = 0 -> !cir.ptr<!ptr> + cir.return + } + + cir.global "private" external @target : !array +} + +// ----- + +!u8i = !cir.int<u, 8> +!u32i = !cir.int<u, 32> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @frame_address_language_address_space() { + %level = cir.const #cir.int<0> : !u32i + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<u, 8>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.frame_address'}} + %0 = cir.frame_address(%level) : !cir.ptr<!u8i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!u8i = !cir.int<u, 8> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @address_of_return_address_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<u, 8>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.address_of_return_address'}} + %0 = cir.address_of_return_address : !cir.ptr<!u8i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!u8i = !cir.int<u, 8> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @stacksave_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<u, 8>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.stacksave'}} + %0 = cir.stacksave : !cir.ptr<!u8i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!s32i = !cir.int<s, 32> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @inline_asm_language_address_space() { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.asm'}} + %0 = cir.asm(x86_att, + out = [], + in = [], + in_out = [], + {"" "=r"}) -> !cir.ptr<!s32i, lang_address_space(offload_global)> + cir.return + } +} + +// ----- + +!langptr = !cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Memory operands require an LLVM elementtype attribute for the pointee. + cir.func @inline_asm_memory_language_address_space(%ptr: !cir.ptr<!langptr>) { + // expected-error @below {{ClangIR lowering NYI: cannot convert '!cir.ptr<!cir.int<s, 32>, lang_address_space(offload_global)>'}} + // expected-error @below {{failed to legalize operation 'cir.asm'}} + cir.asm(x86_att, out = [], in = [%ptr : !cir.ptr<!langptr> (maybe_memory)], + in_out = [], {"" "*m"}) side_effects + cir.return + } +} diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp index b533c239635a61..46a8dd8bd6ba0d 100644 --- a/clang/utils/TableGen/CIRLoweringEmitter.cpp +++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp @@ -239,6 +239,9 @@ void GenerateLLVMLoweringPattern(llvm::StringRef OpName, } else { Code << " mlir::Type resTy = " "typeConverter->convertType(op.getType());\n"; + Code << " if (!resTy)\n"; + Code << " return op.emitError() << \"ClangIR lowering NYI: cannot " + "convert \" << op.getType();\n"; Code << " rewriter.replaceOpWithNewOp<mlir::LLVM::" << LLVMOp << ">(op, mlir::TypeRange{resTy}, adaptor.getOperands(), " << Properties << ");\n"; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
