From 54d48d8f8144e5d7af71b3a726e1b62c603db4e2 Mon Sep 17 00:00:00 2001 From: Ronan Keryell Date: Fri, 10 Jan 2025 18:37:36 +0100 Subject: [PATCH] [CIR] Remove return !cir.void from IR and textual representation (#1249) C/C++ functions returning void had an explicit !cir.void return type while not having any returned value, which was breaking a lot of MLIR invariants when the CIR dialect is used in a greater context, for example with the inliner. Now, a C/C++ function returning void has no return type and no return values, which does not break the MLIR invariant about the same number of return types and returned values. This change does not keeps the same parsing/pretty-printed syntax as before for compatibility like in https://github.com/llvm/clangir/pull/1203 because it requires some new features from the MLIR parser infrastructure itself, which is not great. This uses an optional type for function return type. The default MLIR parser for optional parameters requires an optional anchor we do not have in the syntax, so use a custom FuncType parser to handle the optional return type. --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 13 ++- .../include/clang/CIR/Dialect/IR/CIRTypes.td | 25 +++-- clang/lib/CIR/CodeGen/CIRGenTypes.cpp | 2 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 14 +-- clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 94 ++++++++++++++++--- .../Transforms/TargetLowering/LowerTypes.cpp | 2 +- clang/test/CIR/CodeGen/fun-ptr.c | 6 +- clang/test/CIR/CodeGen/gnu-extension.c | 2 +- clang/test/CIR/CodeGen/member-init-struct.cpp | 8 +- clang/test/CIR/CodeGen/multi-vtable.cpp | 4 +- clang/test/CIR/CodeGen/no-proto-fun-ptr.c | 14 +-- clang/test/CIR/CodeGen/pointer-arith-ext.c | 8 +- .../CIR/CodeGen/pointer-to-member-func.cpp | 16 ++-- clang/test/CIR/CodeGen/static.cpp | 14 +-- clang/test/CIR/IR/being_and_nothingness.cir | 28 ++++++ 15 files changed, 182 insertions(+), 68 deletions(-) create mode 100644 clang/test/CIR/IR/being_and_nothingness.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index b84d5bab2eea..85493e17c915 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3474,8 +3474,6 @@ def FuncOp : CIR_Op<"func", [ /// Returns the results types that the callable region produces when /// executed. llvm::ArrayRef getCallableResults() { - if (::llvm::isa(getFunctionType().getReturnType())) - return {}; return getFunctionType().getReturnTypes(); } @@ -3492,10 +3490,15 @@ def FuncOp : CIR_Op<"func", [ } /// Returns the argument types of this function. - llvm::ArrayRef getArgumentTypes() { return getFunctionType().getInputs(); } + llvm::ArrayRef getArgumentTypes() { + return getFunctionType().getInputs(); + } - /// Returns the result types of this function. - llvm::ArrayRef getResultTypes() { return getFunctionType().getReturnTypes(); } + /// Returns 0 or 1 result type of this function (0 in the case of a function + /// returing void) + llvm::ArrayRef getResultTypes() { + return getFunctionType().getReturnTypes(); + } /// Hook for OpTrait::FunctionOpInterfaceTrait, called after verifying that /// the 'type' attribute is present and checks if it holds a function type. diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index c805b6887cf3..53ea393abe3f 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -372,29 +372,38 @@ def CIR_VectorType : CIR_Type<"Vector", "vector", def CIR_FuncType : CIR_Type<"Func", "func"> { let summary = "CIR function type"; let description = [{ - The `!cir.func` is a function type. It consists of a single return type, a - list of parameter types and can optionally be variadic. + The `!cir.func` is a function type. It consists of an optional return type, + a list of parameter types and can optionally be variadic. Example: ```mlir + !cir.func<()> !cir.func + !cir.func<(!s8i, !s8i)> !cir.func !cir.func ``` }]; - let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs, "mlir::Type":$returnType, + let parameters = (ins ArrayRefParameter<"mlir::Type">:$inputs, + "mlir::Type":$optionalReturnType, "bool":$varArg); + // Use a custom parser to handle the optional return and argument types + // without an optional anchor. let assemblyFormat = [{ - `<` $returnType ` ` `(` custom($inputs, $varArg) `>` + `<` custom($optionalReturnType, $inputs, $varArg) `>` }]; let builders = [ + // Construct with an actual return type or explicit !cir.void TypeBuilderWithInferredContext<(ins "llvm::ArrayRef":$inputs, "mlir::Type":$returnType, CArg<"bool", "false">:$isVarArg), [{ - return $_get(returnType.getContext(), inputs, returnType, isVarArg); + return $_get(returnType.getContext(), inputs, + mlir::isa(returnType) ? nullptr + : returnType, + isVarArg); }]> ]; @@ -408,11 +417,15 @@ def CIR_FuncType : CIR_Type<"Func", "func"> { /// Returns the number of arguments to the function. unsigned getNumInputs() const { return getInputs().size(); } + /// Returns the result type of the function as an actual return type or + /// explicit !cir.void + mlir::Type getReturnType() const; + /// Returns the result type of the function as an ArrayRef, enabling better /// integration with generic MLIR utilities. llvm::ArrayRef getReturnTypes() const; - /// Returns whether the function is returns void. + /// Returns whether the function returns void. bool isVoid() const; /// Returns a clone of this function type with the given argument diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 214b864e2bb7..916010a4f19c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -271,7 +271,7 @@ mlir::Type CIRGenTypes::convertFunctionTypeInternal(QualType QFT) { assert(QFT.isCanonical()); const Type *Ty = QFT.getTypePtr(); const FunctionType *FT = cast(QFT.getTypePtr()); - // First, check whether we can build the full fucntion type. If the function + // First, check whether we can build the full function type. If the function // type depends on an incomplete type (e.g. a struct or enum), we cannot lower // the function type. assert(isFuncTypeConvertible(FT) && "NYI"); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 5c0d01ed8fd9..a1eb11007261 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2490,13 +2490,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p.printSymbolName(getSymName()); auto fnType = getFunctionType(); llvm::SmallVector resultTypes; - if (!fnType.isVoid()) - function_interface_impl::printFunctionSignature( - p, *this, fnType.getInputs(), fnType.isVarArg(), - fnType.getReturnTypes()); - else - function_interface_impl::printFunctionSignature( - p, *this, fnType.getInputs(), fnType.isVarArg(), {}); + function_interface_impl::printFunctionSignature( + p, *this, fnType.getInputs(), fnType.isVarArg(), fnType.getReturnTypes()); if (mlir::ArrayAttr annotations = getAnnotationsAttr()) { p << ' '; @@ -2565,6 +2560,11 @@ LogicalResult cir::FuncOp::verifyType() { if (!getNoProto() && type.isVarArg() && type.getNumInputs() == 0) return emitError() << "prototyped function must have at least one non-variadic input"; + if (auto rt = type.getReturnTypes(); + !rt.empty() && mlir::isa(rt.front())) + return emitOpError("The return type for a function returning void should " + "be empty instead of an explicit !cir.void"); + return success(); } diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index df89584fd3a9..04ecf52a428d 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -33,6 +33,7 @@ #include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include #include using cir::MissingFeatures; @@ -41,12 +42,13 @@ using cir::MissingFeatures; // CIR Custom Parser/Printer Signatures //===----------------------------------------------------------------------===// -static mlir::ParseResult -parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector ¶ms, - bool &isVarArg); -static void printFuncTypeArgs(mlir::AsmPrinter &p, - mlir::ArrayRef params, bool isVarArg); +static mlir::ParseResult parseFuncType(mlir::AsmParser &p, + mlir::Type &optionalReturnTypes, + llvm::SmallVector ¶ms, + bool &isVarArg); +static void printFuncType(mlir::AsmPrinter &p, mlir::Type optionalReturnTypes, + mlir::ArrayRef params, bool isVarArg); static mlir::ParseResult parsePointerAddrSpace(mlir::AsmParser &p, mlir::Attribute &addrSpaceAttr); static void printPointerAddrSpace(mlir::AsmPrinter &p, @@ -913,9 +915,38 @@ FuncType FuncType::clone(TypeRange inputs, TypeRange results) const { return get(llvm::to_vector(inputs), results[0], isVarArg()); } -mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p, - llvm::SmallVector ¶ms, - bool &isVarArg) { +// A special parser is needed for function returning void to handle the missing +// type. +static mlir::ParseResult parseFuncTypeReturn(mlir::AsmParser &p, + mlir::Type &optionalReturnType) { + if (succeeded(p.parseOptionalLParen())) { + // If we have already a '(', the function has no return type + optionalReturnType = {}; + return mlir::success(); + } + mlir::Type type; + if (p.parseType(type)) + return mlir::failure(); + if (isa(type)) + // An explicit !cir.void means also no return type. + optionalReturnType = {}; + else + // Otherwise use the actual type. + optionalReturnType = type; + return p.parseLParen(); +} + +// A special pretty-printer for function returning or not a result. +static void printFuncTypeReturn(mlir::AsmPrinter &p, + mlir::Type optionalReturnType) { + if (optionalReturnType) + p << optionalReturnType << ' '; + p << '('; +} + +static mlir::ParseResult +parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector ¶ms, + bool &isVarArg) { isVarArg = false; // `(` `)` if (succeeded(p.parseOptionalRParen())) @@ -945,8 +976,9 @@ mlir::ParseResult parseFuncTypeArgs(mlir::AsmParser &p, return p.parseRParen(); } -void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef params, - bool isVarArg) { +static void printFuncTypeArgs(mlir::AsmPrinter &p, + mlir::ArrayRef params, + bool isVarArg) { llvm::interleaveComma(params, p, [&p](mlir::Type type) { p.printType(type); }); if (isVarArg) { @@ -957,11 +989,49 @@ void printFuncTypeArgs(mlir::AsmPrinter &p, mlir::ArrayRef params, p << ')'; } +// Use a custom parser to handle the optional return and argument types without +// an optional anchor. +static mlir::ParseResult parseFuncType(mlir::AsmParser &p, + mlir::Type &optionalReturnTypes, + llvm::SmallVector ¶ms, + bool &isVarArg) { + if (failed(parseFuncTypeReturn(p, optionalReturnTypes))) + return failure(); + return parseFuncTypeArgs(p, params, isVarArg); +} + +static void printFuncType(mlir::AsmPrinter &p, mlir::Type optionalReturnTypes, + mlir::ArrayRef params, bool isVarArg) { + printFuncTypeReturn(p, optionalReturnTypes); + printFuncTypeArgs(p, params, isVarArg); +} + +// Return the actual return type or an explicit !cir.void if the function does +// not return anything +mlir::Type FuncType::getReturnType() const { + if (isVoid()) + return cir::VoidType::get(getContext()); + return static_cast(getImpl())->optionalReturnType; +} + +/// Returns the result type of the function as an ArrayRef, enabling better +/// integration with generic MLIR utilities. llvm::ArrayRef FuncType::getReturnTypes() const { - return static_cast(getImpl())->returnType; + if (isVoid()) + return {}; + return static_cast(getImpl())->optionalReturnType; } -bool FuncType::isVoid() const { return mlir::isa(getReturnType()); } +// Whether the function returns void +bool FuncType::isVoid() const { + auto rt = + static_cast(getImpl())->optionalReturnType; + assert(!rt || + !mlir::isa(rt) && + "The return type for a function returning void should be empty " + "instead of a real !cir.void"); + return !rt; +} //===----------------------------------------------------------------------===// // MethodType Definitions diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp index 0c2233ef84c9..d655ae9023dd 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerTypes.cpp @@ -109,7 +109,7 @@ FuncType LowerTypes::getFunctionType(const LowerFunctionInfo &FI) { } } - return FuncType::get(getMLIRContext(), ArgTypes, resultType, FI.isVariadic()); + return FuncType::get(ArgTypes, resultType, FI.isVariadic()); } /// Convert a CIR type to its ABI-specific default form. diff --git a/clang/test/CIR/CodeGen/fun-ptr.c b/clang/test/CIR/CodeGen/fun-ptr.c index 7092c58e64d0..0f9a98300e32 100644 --- a/clang/test/CIR/CodeGen/fun-ptr.c +++ b/clang/test/CIR/CodeGen/fun-ptr.c @@ -55,10 +55,10 @@ int foo(Data* d) { return f(d); } -// CIR: cir.func private {{@.*test.*}}() -> !cir.ptr> +// CIR: cir.func private {{@.*test.*}}() -> !cir.ptr> // CIR: cir.func {{@.*bar.*}}() -// CIR: [[RET:%.*]] = cir.call {{@.*test.*}}() : () -> !cir.ptr> -// CIR: cir.call [[RET]]() : (!cir.ptr>) -> () +// CIR: [[RET:%.*]] = cir.call {{@.*test.*}}() : () -> !cir.ptr> +// CIR: cir.call [[RET]]() : (!cir.ptr>) -> () // CIR: cir.return // LLVM: declare ptr {{@.*test.*}}() diff --git a/clang/test/CIR/CodeGen/gnu-extension.c b/clang/test/CIR/CodeGen/gnu-extension.c index 7386de78176f..5a9f4b0b22b4 100644 --- a/clang/test/CIR/CodeGen/gnu-extension.c +++ b/clang/test/CIR/CodeGen/gnu-extension.c @@ -15,5 +15,5 @@ void bar(void) { } //CHECK: cir.func @bar() -//CHECK: {{.*}} = cir.get_global @bar : !cir.ptr> +//CHECK: {{.*}} = cir.get_global @bar : !cir.ptr> //CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/member-init-struct.cpp b/clang/test/CIR/CodeGen/member-init-struct.cpp index 8440526c1a1c..4c5161616475 100644 --- a/clang/test/CIR/CodeGen/member-init-struct.cpp +++ b/clang/test/CIR/CodeGen/member-init-struct.cpp @@ -34,7 +34,7 @@ C a, b(x), c(0, 2); // CHECK: %[[VAL_8:.*]] = cir.get_member %[[VAL_2]][2] {name = "d"} : !cir.ptr -> !cir.ptr> // CHECK: %[[VAL_9:.*]] = cir.const {{.*}} : !cir.array // CHECK: cir.store %[[VAL_9]], %[[VAL_8]] : !cir.array, !cir.ptr> -// CHECK: %[[VAL_10:.*]] = cir.get_member %[[VAL_2]][4] {name = "e"} : !cir.ptr -> !cir.ptr in !ty_C>> -// CHECK: %[[VAL_11:.*]] = cir.const #cir.method : !cir.method in !ty_C> -// CHECK: cir.store %[[VAL_11]], %[[VAL_10]] : !cir.method in !ty_C>, !cir.ptr in !ty_C>> -// CHECK: cir.return \ No newline at end of file +// CHECK: %[[VAL_10:.*]] = cir.get_member %[[VAL_2]][4] {name = "e"} : !cir.ptr -> !cir.ptr in !ty_C>> +// CHECK: %[[VAL_11:.*]] = cir.const #cir.method : !cir.method in !ty_C> +// CHECK: cir.store %[[VAL_11]], %[[VAL_10]] : !cir.method in !ty_C>, !cir.ptr in !ty_C>> +// CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/multi-vtable.cpp b/clang/test/CIR/CodeGen/multi-vtable.cpp index b887e78c8239..8b709a3ddeaf 100644 --- a/clang/test/CIR/CodeGen/multi-vtable.cpp +++ b/clang/test/CIR/CodeGen/multi-vtable.cpp @@ -74,9 +74,9 @@ int main() { // CIR: cir.func @main() -> !s32i extra(#fn_attr) { -// CIR: %{{[0-9]+}} = cir.vtable.address_point( %{{[0-9]+}} : !cir.ptr)>>>, vtable_index = 0, address_point_index = 0) : !cir.ptr)>>> +// CIR: %{{[0-9]+}} = cir.vtable.address_point( %{{[0-9]+}} : !cir.ptr)>>>, vtable_index = 0, address_point_index = 0) : !cir.ptr)>>> -// CIR: %{{[0-9]+}} = cir.vtable.address_point( %{{[0-9]+}} : !cir.ptr)>>>, vtable_index = 0, address_point_index = 0) : !cir.ptr)>>> +// CIR: %{{[0-9]+}} = cir.vtable.address_point( %{{[0-9]+}} : !cir.ptr)>>>, vtable_index = 0, address_point_index = 0) : !cir.ptr)>>> // CIR: } diff --git a/clang/test/CIR/CodeGen/no-proto-fun-ptr.c b/clang/test/CIR/CodeGen/no-proto-fun-ptr.c index b4d92db11963..92c3eb6516e1 100644 --- a/clang/test/CIR/CodeGen/no-proto-fun-ptr.c +++ b/clang/test/CIR/CodeGen/no-proto-fun-ptr.c @@ -7,9 +7,9 @@ void check_noproto_ptr() { } // CHECK: cir.func no_proto @check_noproto_ptr() -// CHECK: [[ALLOC:%.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["fun", init] {alignment = 8 : i64} -// CHECK: [[GGO:%.*]] = cir.get_global @empty : !cir.ptr> -// CHECK: cir.store [[GGO]], [[ALLOC]] : !cir.ptr>, !cir.ptr>> +// CHECK: [[ALLOC:%.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["fun", init] {alignment = 8 : i64} +// CHECK: [[GGO:%.*]] = cir.get_global @empty : !cir.ptr> +// CHECK: cir.store [[GGO]], [[ALLOC]] : !cir.ptr>, !cir.ptr>> // CHECK: cir.return void empty(void) {} @@ -20,8 +20,8 @@ void buz() { } // CHECK: cir.func no_proto @buz() -// CHECK: [[FNPTR_ALLOC:%.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["func"] {alignment = 8 : i64} -// CHECK: [[FNPTR:%.*]] = cir.load deref [[FNPTR_ALLOC]] : !cir.ptr>>, !cir.ptr> -// CHECK: [[CAST:%.*]] = cir.cast(bitcast, %1 : !cir.ptr>), !cir.ptr> -// CHECK: cir.call [[CAST]]() : (!cir.ptr>) -> () +// CHECK: [[FNPTR_ALLOC:%.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["func"] {alignment = 8 : i64} +// CHECK: [[FNPTR:%.*]] = cir.load deref [[FNPTR_ALLOC]] : !cir.ptr>>, !cir.ptr> +// CHECK: [[CAST:%.*]] = cir.cast(bitcast, %1 : !cir.ptr>), !cir.ptr> +// CHECK: cir.call [[CAST]]() : (!cir.ptr>) -> () // CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/pointer-arith-ext.c b/clang/test/CIR/CodeGen/pointer-arith-ext.c index 558ad823cae4..c1a3d374b44b 100644 --- a/clang/test/CIR/CodeGen/pointer-arith-ext.c +++ b/clang/test/CIR/CodeGen/pointer-arith-ext.c @@ -50,9 +50,9 @@ void *f4_1(void *a, int b) { return (a -= b); } FP f5(FP a, int b) { return a + b; } // CIR-LABEL: f5 -// CIR: %[[PTR:.*]] = cir.load {{.*}} : !cir.ptr>>, !cir.ptr> +// CIR: %[[PTR:.*]] = cir.load {{.*}} : !cir.ptr>>, !cir.ptr> // CIR: %[[STRIDE:.*]] = cir.load {{.*}} : !cir.ptr, !s32i -// CIR: cir.ptr_stride(%[[PTR]] : !cir.ptr>, %[[STRIDE]] : !s32i) +// CIR: cir.ptr_stride(%[[PTR]] : !cir.ptr>, %[[STRIDE]] : !s32i) // LLVM-LABEL: f5 // LLVM: %[[PTR:.*]] = load ptr, ptr {{.*}}, align 8 @@ -67,10 +67,10 @@ FP f6_1(int a, FP b) { return (a += b); } FP f7(FP a, int b) { return a - b; } // CIR-LABEL: f7 -// CIR: %[[PTR:.*]] = cir.load {{.*}} : !cir.ptr>>, !cir.ptr> +// CIR: %[[PTR:.*]] = cir.load {{.*}} : !cir.ptr>>, !cir.ptr> // CIR: %[[STRIDE:.*]] = cir.load {{.*}} : !cir.ptr, !s32i // CIR: %[[SUB:.*]] = cir.unary(minus, %[[STRIDE]]) : !s32i, !s32i -// CIR: cir.ptr_stride(%[[PTR]] : !cir.ptr>, %[[SUB]] : !s32i) +// CIR: cir.ptr_stride(%[[PTR]] : !cir.ptr>, %[[SUB]] : !s32i) // LLVM-LABEL: f7 // LLVM: %[[PTR:.*]] = load ptr, ptr {{.*}}, align 8 diff --git a/clang/test/CIR/CodeGen/pointer-to-member-func.cpp b/clang/test/CIR/CodeGen/pointer-to-member-func.cpp index 6f8b3363bfa3..f3c426c4b1ee 100644 --- a/clang/test/CIR/CodeGen/pointer-to-member-func.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-member-func.cpp @@ -11,24 +11,24 @@ auto make_non_virtual() -> void (Foo::*)(int) { return &Foo::m1; } -// CHECK-LABEL: cir.func @_Z16make_non_virtualv() -> !cir.method in !ty_Foo> -// CHECK: %{{.+}} = cir.const #cir.method<@_ZN3Foo2m1Ei> : !cir.method in !ty_Foo> +// CHECK-LABEL: cir.func @_Z16make_non_virtualv() -> !cir.method in !ty_Foo> +// CHECK: %{{.+}} = cir.const #cir.method<@_ZN3Foo2m1Ei> : !cir.method in !ty_Foo> // CHECK: } auto make_virtual() -> void (Foo::*)(int) { return &Foo::m3; } -// CHECK-LABEL: cir.func @_Z12make_virtualv() -> !cir.method in !ty_Foo> -// CHECK: %{{.+}} = cir.const #cir.method : !cir.method in !ty_Foo> +// CHECK-LABEL: cir.func @_Z12make_virtualv() -> !cir.method in !ty_Foo> +// CHECK: %{{.+}} = cir.const #cir.method : !cir.method in !ty_Foo> // CHECK: } auto make_null() -> void (Foo::*)(int) { return nullptr; } -// CHECK-LABEL: cir.func @_Z9make_nullv() -> !cir.method in !ty_Foo> -// CHECK: %{{.+}} = cir.const #cir.method : !cir.method in !ty_Foo> +// CHECK-LABEL: cir.func @_Z9make_nullv() -> !cir.method in !ty_Foo> +// CHECK: %{{.+}} = cir.const #cir.method : !cir.method in !ty_Foo> // CHECK: } void call(Foo *obj, void (Foo::*func)(int), int arg) { @@ -36,7 +36,7 @@ void call(Foo *obj, void (Foo::*func)(int), int arg) { } // CHECK-LABEL: cir.func @_Z4callP3FooMS_FviEi -// CHECK: %[[CALLEE:.+]], %[[THIS:.+]] = cir.get_method %{{.+}}, %{{.+}} : (!cir.method in !ty_Foo>, !cir.ptr) -> (!cir.ptr, !s32i)>>, !cir.ptr) +// CHECK: %[[CALLEE:.+]], %[[THIS:.+]] = cir.get_method %{{.+}}, %{{.+}} : (!cir.method in !ty_Foo>, !cir.ptr) -> (!cir.ptr, !s32i)>>, !cir.ptr) // CHECK-NEXT: %[[#ARG:]] = cir.load %{{.+}} : !cir.ptr, !s32i -// CHECK-NEXT: cir.call %[[CALLEE]](%[[THIS]], %[[#ARG]]) : (!cir.ptr, !s32i)>>, !cir.ptr, !s32i) -> () +// CHECK-NEXT: cir.call %[[CALLEE]](%[[THIS]], %[[#ARG]]) : (!cir.ptr, !s32i)>>, !cir.ptr, !s32i) -> () // CHECK: } diff --git a/clang/test/CIR/CodeGen/static.cpp b/clang/test/CIR/CodeGen/static.cpp index 88ff490c14ff..657396845e13 100644 --- a/clang/test/CIR/CodeGen/static.cpp +++ b/clang/test/CIR/CodeGen/static.cpp @@ -40,7 +40,7 @@ static Init __ioinit2(false); // AFTER: module {{.*}} attributes {{.*}}cir.global_ctors = [#cir.global_ctor<"__cxx_global_var_init", 65536>, #cir.global_ctor<"__cxx_global_var_init.1", 65536>] // AFTER-NEXT: cir.global "private" external @__dso_handle : i8 -// AFTER-NEXT: cir.func private @__cxa_atexit(!cir.ptr)>>, !cir.ptr, !cir.ptr) +// AFTER-NEXT: cir.func private @__cxa_atexit(!cir.ptr)>>, !cir.ptr, !cir.ptr) // AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) // AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) // AFTER-NEXT: cir.global "private" internal dsolocal @_ZL8__ioinit = #cir.zero : !ty_Init {alignment = 1 : i64, ast = #cir.var.decl.ast} @@ -49,11 +49,11 @@ static Init __ioinit2(false); // AFTER-NEXT: %1 = cir.const #true // AFTER-NEXT: cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr, !cir.bool) -> () // AFTER-NEXT: %2 = cir.get_global @_ZL8__ioinit : !cir.ptr -// AFTER-NEXT: %3 = cir.get_global @_ZN4InitD1Ev : !cir.ptr)>> -// AFTER-NEXT: %4 = cir.cast(bitcast, %3 : !cir.ptr)>>), !cir.ptr)>> +// AFTER-NEXT: %3 = cir.get_global @_ZN4InitD1Ev : !cir.ptr)>> +// AFTER-NEXT: %4 = cir.cast(bitcast, %3 : !cir.ptr)>>), !cir.ptr)>> // AFTER-NEXT: %5 = cir.cast(bitcast, %2 : !cir.ptr), !cir.ptr // AFTER-NEXT: %6 = cir.get_global @__dso_handle : !cir.ptr -// AFTER-NEXT: cir.call @__cxa_atexit(%4, %5, %6) : (!cir.ptr)>>, !cir.ptr, !cir.ptr) -> () +// AFTER-NEXT: cir.call @__cxa_atexit(%4, %5, %6) : (!cir.ptr)>>, !cir.ptr, !cir.ptr) -> () // AFTER-NEXT: cir.return // AFTER: cir.global "private" internal dsolocal @_ZL9__ioinit2 = #cir.zero : !ty_Init {alignment = 1 : i64, ast = #cir.var.decl.ast} // AFTER-NEXT: cir.func internal private @__cxx_global_var_init.1() @@ -61,11 +61,11 @@ static Init __ioinit2(false); // AFTER-NEXT: %1 = cir.const #false // AFTER-NEXT: cir.call @_ZN4InitC1Eb(%0, %1) : (!cir.ptr, !cir.bool) -> () // AFTER-NEXT: %2 = cir.get_global @_ZL9__ioinit2 : !cir.ptr -// AFTER-NEXT: %3 = cir.get_global @_ZN4InitD1Ev : !cir.ptr)>> -// AFTER-NEXT: %4 = cir.cast(bitcast, %3 : !cir.ptr)>>), !cir.ptr)>> +// AFTER-NEXT: %3 = cir.get_global @_ZN4InitD1Ev : !cir.ptr)>> +// AFTER-NEXT: %4 = cir.cast(bitcast, %3 : !cir.ptr)>>), !cir.ptr)>> // AFTER-NEXT: %5 = cir.cast(bitcast, %2 : !cir.ptr), !cir.ptr // AFTER-NEXT: %6 = cir.get_global @__dso_handle : !cir.ptr -// AFTER-NEXT: cir.call @__cxa_atexit(%4, %5, %6) : (!cir.ptr)>>, !cir.ptr, !cir.ptr) -> () +// AFTER-NEXT: cir.call @__cxa_atexit(%4, %5, %6) : (!cir.ptr)>>, !cir.ptr, !cir.ptr) -> () // AFTER-NEXT: cir.return // AFTER: cir.func private @_GLOBAL__sub_I_static.cpp() // AFTER-NEXT: cir.call @__cxx_global_var_init() : () -> () diff --git a/clang/test/CIR/IR/being_and_nothingness.cir b/clang/test/CIR/IR/being_and_nothingness.cir new file mode 100644 index 000000000000..076c75a5b192 --- /dev/null +++ b/clang/test/CIR/IR/being_and_nothingness.cir @@ -0,0 +1,28 @@ +// RUN: cir-opt %s | FileCheck %s +// Exercise different ways to encode a function returning void +!s32i = !cir.int +!f = !cir.func<()> +!f2 = !cir.func +!void = !cir.void +!fnptr2 = !cir.ptr> +// Try some useless !void +!fnptr3 = !cir.ptr> +module { + cir.func @ind2(%fnptr: !fnptr2, %a : !s32i) { + // CHECK: cir.func @ind2(%arg0: !cir.ptr>, %arg1: !s32i) { + cir.return + } + cir.func @f2() { + // CHECK: cir.func @f2() { + cir.return + } + // Try with a lot of useless !void + cir.func @ind3(%fnptr: !fnptr3, %a : !s32i) -> !void { + // CHECK: cir.func @ind3(%arg0: !cir.ptr>, %arg1: !s32i) { + cir.return + } + cir.func @f3() -> !cir.void { + // CHECK: cir.func @f3() { + cir.return + } +}