https://github.com/Men-cotton created https://github.com/llvm/llvm-project/pull/224237
Propagate failed type and constant conversions through DirectToLLVM so unsupported types produce legalization failures instead of invalid LLVM operations or a void function result. Assisted-by: Codex / GPT-6 >From d3cc1d7440fb9e544a93e95131a23f2ba398fbf9 Mon Sep 17 00:00:00 2001 From: mencotton <[email protected]> Date: Tue, 15 Sep 2026 20:47:50 +0900 Subject: [PATCH] [CIR] Propagate type conversion failures in DirectToLLVM Propagate failed type and constant conversions through DirectToLLVM so unsupported types produce legalization failures instead of invalid LLVM operations or a void function result. Assisted-by: Codex / GPT-6 --- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 62 ++++-- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 7 +- .../Lowering/unsupported-type-conversions.cir | 178 ++++++++++++++++++ 3 files changed, 231 insertions(+), 16 deletions(-) create mode 100644 clang/test/CIR/Lowering/unsupported-type-conversions.cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 596c0d72264a0..6280b853d6e79 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -424,10 +424,7 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, LLVMBlockAddressInfo *blockInfoAddr) { CIRAttrToValue valueConverter(parentOp, rewriter, symbolTables, converter, blockInfoAddr); - mlir::Value value = valueConverter.visit(attr); - if (!value) - llvm_unreachable("unhandled attribute type"); - return value; + return valueConverter.visit(attr); } void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow, @@ -783,6 +780,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) { if (auto arrayAttr = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts())) { for (auto [idx, elt] : llvm::enumerate(arrayAttr)) { mlir::Value init = visit(elt); + if (!init) + return {}; result = mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx); } @@ -827,8 +826,11 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstRecordAttr constRecord) { ++paddingItr; } - result = mlir::LLVM::InsertValueOp::create(rewriter, loc, result, - visit(elt), insertIdx); + mlir::Value init = visit(elt); + if (!init) + return {}; + result = mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, + insertIdx); ++insertIdx; } @@ -957,6 +959,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) { mlir::Type sourceType = lowered.sourceType; if (globalAttr.getIndices()) { + if (!sourceType) + return {}; llvm::SmallVector<mlir::LLVM::GEPArg> indices; if (mlir::isa<mlir::LLVM::LLVMArrayType, mlir::LLVM::LLVMStructType>( @@ -1004,6 +1008,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeInfoAttr) { for (auto [idx, elt] : llvm::enumerate(typeInfoAttr.getData())) { mlir::Value init = visit(elt); + if (!init) + return {}; result = mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx); } @@ -1037,6 +1043,8 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) { for (auto [idx, elt] : llvm::enumerate(vtableArr.getData())) { mlir::Value init = visit(elt); + if (!init) + return {}; result = mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx); } @@ -1618,6 +1626,9 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite( // both individual scalars and entire vectors. This lowering pass handles // both situations. + if (!getTypeConverter()->convertType(castOp.getType())) + return mlir::failure(); + switch (castOp.getKind()) { case cir::CastKind::array_to_ptrdecay: { const auto ptrTy = mlir::cast<cir::PointerType>(castOp.getType()); @@ -2459,6 +2470,8 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( cir::ConstantOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::Attribute attr = op.getValue(); + if (!getTypeConverter()->convertType(op.getType())) + return mlir::failure(); if (mlir::isa<cir::PoisonAttr>(attr)) { rewriter.replaceOpWithNewOp<mlir::LLVM::PoisonOp>( @@ -2511,6 +2524,8 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( if (mlir::isa<cir::GlobalViewAttr, cir::GlobalOffsetAttr>(op.getValue())) { auto newOp = lowerCirAttrAsValue(op, op.getValue(), rewriter, symbolTables, getTypeConverter()); + if (!newOp) + return mlir::failure(); rewriter.replaceOp(op, newOp); return mlir::success(); } @@ -2527,6 +2542,8 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( } else { const mlir::Value initVal = lowerCirAttrAsValue( op, op.getValue(), rewriter, symbolTables, typeConverter); + if (!initVal) + return mlir::failure(); rewriter.replaceOp(op, initVal); return mlir::success(); } @@ -2534,17 +2551,23 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( mlir::dyn_cast<cir::ConstRecordAttr>(op.getValue())) { auto initVal = lowerCirAttrAsValue(op, recordAttr, rewriter, symbolTables, typeConverter); + if (!initVal) + return mlir::failure(); rewriter.replaceOp(op, initVal); return mlir::success(); } else if (const auto vecTy = mlir::dyn_cast<cir::VectorType>(op.getType())) { - rewriter.replaceOp(op, - lowerCirAttrAsValue(op, op.getValue(), rewriter, - symbolTables, getTypeConverter())); + mlir::Value initVal = lowerCirAttrAsValue(op, op.getValue(), rewriter, + symbolTables, getTypeConverter()); + if (!initVal) + return mlir::failure(); + rewriter.replaceOp(op, initVal); return mlir::success(); } else if (mlir::isa<cir::RecordType>(op.getType())) { if (mlir::isa<cir::ZeroAttr, cir::UndefAttr>(attr)) { mlir::Value initVal = lowerCirAttrAsValue(op, attr, rewriter, symbolTables, typeConverter); + if (!initVal) + return mlir::failure(); rewriter.replaceOp(op, initVal); return mlir::success(); } @@ -2777,11 +2800,12 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( mlir::Type resultType = getTypeConverter()->convertType(fnType.getReturnType()); + if (!resultType) + return mlir::failure(); // Create the LLVM function operation. mlir::Type llvmFnTy = mlir::LLVM::LLVMFunctionType::get( - resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()), - signatureConversion.getConvertedTypes(), + resultType, signatureConversion.getConvertedTypes(), /*isVarArg=*/fnType.isVarArg()); // If this is an alias, it needs to be lowered to llvm::AliasOp. @@ -3000,6 +3024,8 @@ CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal( CIRAttrToValue valueConverter(op, rewriter, symbolTables, typeConverter, &blockInfoAddr); mlir::Value value = valueConverter.visit(init); + if (!value) + return mlir::failure(); mlir::LLVM::ReturnOp::create(rewriter, loc, value); return mlir::success(); } @@ -3958,6 +3984,8 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, }); converter.addConversion([&](cir::FuncType type) -> std::optional<mlir::Type> { auto result = converter.convertType(type.getReturnType()); + if (!result) + return std::nullopt; llvm::SmallVector<mlir::Type> arguments; arguments.reserve(type.getNumInputs()); if (converter.convertTypes(type.getInputs(), arguments).failed()) @@ -4801,6 +4829,9 @@ getValueForVTableSymbol(mlir::Operation *op, return {}; } + if (!eltType) + return {}; + return mlir::LLVM::AddressOfOp::create( rewriter, op->getLoc(), mlir::LLVM::LLVMPointerType::get(op->getContext()), nameAttr.getValue()); @@ -4816,7 +4847,7 @@ mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite( mlir::Value symAddr = getValueForVTableSymbol( op, rewriter, symbolTables, converter, op.getNameAttr(), eltType); if (!symAddr) - return op.emitError() << "Unable to get value for vtable symbol"; + return mlir::failure(); offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{ 0, op.getAddressPointAttr().getIndex(), @@ -4874,6 +4905,8 @@ mlir::LogicalResult CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite( llvmAddr = getValueForVTableSymbol(op, rewriter, symbolTables, getTypeConverter(), op.getNameAttr(), eltType); + if (!llvmAddr) + return mlir::failure(); assert(eltType && "Shouldn't ever be missing an eltType here"); offsets.push_back(0); offsets.push_back(adaptor.getOffset()); @@ -5421,8 +5454,11 @@ mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite( cir::InlineAsmOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::Type llResTy; - if (op.getNumResults()) + if (op.getNumResults()) { llResTy = getTypeConverter()->convertType(op.getType(0)); + if (!llResTy) + return mlir::failure(); + } cir::AsmFlavor dialect = op.getAsmFlavor(); mlir::LLVM::AsmDialect llDialect = dialect == cir::AsmFlavor::x86_att diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 146b31b907fcc..c48722fec38fc 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -24,9 +24,10 @@ namespace direct { struct LLVMBlockAddressInfo; -/// Convert a CIR attribute to an LLVM attribute. May use the datalayout for -/// lowering attributes to-be-stored in memory. When the attribute may contain -/// block address attributes, `blockInfoAddr` is used to resolve them. +/// Convert a CIR attribute to an LLVM value, or return null on failure. +/// May use the datalayout for lowering attributes to-be-stored in memory. When +/// the attribute may contain block address attributes, `blockInfoAddr` is used +/// to resolve them. mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr, mlir::ConversionPatternRewriter &rewriter, mlir::SymbolTableCollection &symbolTables, diff --git a/clang/test/CIR/Lowering/unsupported-type-conversions.cir b/clang/test/CIR/Lowering/unsupported-type-conversions.cir new file mode 100644 index 0000000000000..d4d43bf49919e --- /dev/null +++ b/clang/test/CIR/Lowering/unsupported-type-conversions.cir @@ -0,0 +1,178 @@ +// RUN: cir-opt %s --split-input-file --cir-to-llvm -verify-diagnostics + +// Vector-of-_BitInt conversion is unsupported; propagate its failure to the +// enclosing operation instead of constructing invalid LLVM operations. + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // expected-error @below {{failed to legalize operation 'cir.func'}} + cir.func private @function_result() -> !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // The initializer requests FuncType conversion before the function lowers. + cir.global external @function_view = #cir.global_view<@callee> : !cir.ptr<!cir.void> + + // expected-error @below {{failed to legalize operation 'cir.func'}} + cir.func private @callee() -> !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @constant_result() { + // expected-error @below {{failed to legalize operation 'cir.const'}} + %0 = cir.const #cir.zero : !vec + cir.return + } +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @cast_result() { + %0 = cir.const #cir.zero : !cir.vector<4 x !cir.int<s, 7>> + // expected-error @below {{failed to legalize operation 'cir.cast'}} + %1 = cir.cast bitcast %0 : !cir.vector<4 x !cir.int<s, 7>> -> !vec + cir.return + } +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.func @asm_result() { + // expected-error @below {{failed to legalize operation 'cir.asm'}} + %0 = cir.asm(x86_att, out = [], in = [], in_out = [], {"" "=r"}) -> !vec + cir.return + } +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the constant before its target to exercise symbol-type failure. + cir.func @constant_global_view() { + // 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 : !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the constant before its target to exercise symbol-type failure. + cir.func @constant_array_view() { + // 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 : !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Lower the constant before its target to exercise symbol-type failure. + cir.func @constant_record_view() { + // 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 : !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Propagate initializer failure before lowering the referenced global. + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @global_view = #cir.global_view<@target, [0 : i32]> : !ptr + + cir.global external @target = #cir.zero : !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Propagate initializer failure before lowering the referenced global. + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @typeinfo_view = #cir.typeinfo<{#cir.global_view<@target, [0 : i32]> : !ptr}> : !cir.struct<{data !ptr}> + + cir.global external @target = #cir.zero : !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // Propagate initializer failure before lowering the referenced global. + // expected-error @below {{failed to legalize operation 'cir.global'}} + cir.global external @vtable_view = #cir.vtable<{#cir.const_array<[#cir.global_view<@target, [0 : i32]> : !ptr]> : !cir.array<!ptr x 1>}> : !cir.struct<{data !cir.array<!ptr x 1>}> + + cir.global external @target = #cir.zero : !vec +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // The address point requests the symbol type before the global lowers. + cir.func @vtable_symbol() { + // 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 !cir.array<!vec x 1>}> +} + +// ----- + +!vec = !cir.vector<4 x !cir.int<s, 7, bitint>> +!ptr = !cir.ptr<!cir.void> + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + // The address point requests the symbol type before the global lowers. + cir.func @vtt_symbol() { + // 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 : !cir.array<!vec x 1> +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
