Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR] New assembly format for function type return #1391

Merged
merged 2 commits into from
Feb 24, 2025
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
4 changes: 2 additions & 2 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -3857,7 +3857,7 @@ def CallOp : CIR_CallOp<"call", [NoRegionArguments]> {
CArg<"mlir::UnitAttr", "{}">:$exception), [{
$_state.addOperands(ValueRange{ind_target});
$_state.addOperands(operands);
if (!fn_type.isVoid())
if (!fn_type.hasVoidReturn())
$_state.addTypes(fn_type.getReturnType());
$_state.addAttribute("calling_conv",
CallingConvAttr::get($_builder.getContext(), callingConv));
Expand Down Expand Up @@ -3943,7 +3943,7 @@ def TryCallOp : CIR_CallOp<"try_call",
finalCallOperands.append(operands.begin(), operands.end());
$_state.addOperands(finalCallOperands);

if (!fn_type.isVoid())
if (!fn_type.hasVoidReturn())
$_state.addTypes(fn_type.getReturnType());

$_state.addAttribute("calling_conv",
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class StructType
case RecordKind::Struct:
return "struct";
}
llvm_unreachable("Invalid value for StructType::getKind()");
}
std::string getPrefixedName() {
return getKindAsStr() + "." + getName().getValue().str();
Expand Down
35 changes: 20 additions & 15 deletions clang/include/clang/CIR/Dialect/IR/CIRTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -379,34 +379,38 @@ def CIR_FuncType : CIR_Type<"Func", "func"> {

```mlir
!cir.func<()>
!cir.func<!bool ()>
!cir.func<() -> !bool>
!cir.func<(!s8i, !s8i)>
!cir.func<!s32i (!s8i, !s8i)>
!cir.func<!s32i (!s32i, ...)>
!cir.func<(!s8i, !s8i) -> !s32i>
!cir.func<(!s32i, ...) -> !s32i>
```
}];

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 = [{
`<` custom<FuncType>($optionalReturnType, $inputs, $varArg) `>`
}];

let builders = [
// Construct with an actual return type or explicit !cir.void
// Create a FuncType, converting the return type from C-style to
// MLIR-style. If the given return type is `cir::VoidType`, ignore it
// and create the FuncType with no return type, which is how MLIR
// represents function types.
TypeBuilderWithInferredContext<(ins
"llvm::ArrayRef<mlir::Type>":$inputs, "mlir::Type":$returnType,
CArg<"bool", "false">:$isVarArg), [{
return $_get(returnType.getContext(), inputs,
mlir::isa<cir::VoidType>(returnType) ? nullptr
: returnType,
isVarArg);
return $_get(returnType.getContext(), inputs,
mlir::isa<cir::VoidType>(returnType) ? nullptr
: returnType,
isVarArg);
}]>
];

let genVerifyDecl = 1;

let extraClassDeclaration = [{
/// Returns whether the function is variadic.
bool isVarArg() const { return getVarArg(); }
Expand All @@ -417,16 +421,17 @@ 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
/// Get the C-style return type of the function, which is !cir.void if the
/// function returns nothing and the actual return type otherwise.
mlir::Type getReturnType() const;

/// Returns the result type of the function as an ArrayRef, enabling better
/// integration with generic MLIR utilities.
/// Get the MLIR-style return type of the function, which is an empty
/// ArrayRef if the function returns nothing and a single-element ArrayRef
/// with the actual return type otherwise.
llvm::ArrayRef<mlir::Type> getReturnTypes() const;

/// Returns whether the function returns void.
bool isVoid() const;
/// Does the fuction type return nothing?
Copy link
Collaborator

Choose a reason for hiding this comment

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

s/fuction/function/ for the next PR.

bool hasVoidReturn() const;

/// Returns a clone of this function type with the given argument
/// and result types.
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2739,15 +2739,15 @@ verifyCallCommInSymbolUses(Operation *op, SymbolTableCollection &symbolTable) {
<< stringifyCallingConv(callIf.getCallingConv());

// Void function must not return any results.
if (fnType.isVoid() && op->getNumResults() != 0)
if (fnType.hasVoidReturn() && op->getNumResults() != 0)
return op->emitOpError("callee returns void but call has results");

// Non-void function calls must return exactly one result.
if (!fnType.isVoid() && op->getNumResults() != 1)
if (!fnType.hasVoidReturn() && op->getNumResults() != 1)
return op->emitOpError("incorrect number of results for callee");

// Parent function and return value types must match.
if (!fnType.isVoid() &&
if (!fnType.hasVoidReturn() &&
op->getResultTypes().front() != fnType.getReturnType()) {
return op->emitOpError("result type mismatch: expected ")
<< fnType.getReturnType() << ", but provided "
Expand Down
112 changes: 52 additions & 60 deletions clang/lib/CIR/Dialect/IR/CIRTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,66 +937,51 @@ FuncType FuncType::clone(TypeRange inputs, TypeRange results) const {
// 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();
if (succeeded(p.parseOptionalArrow())) {
// `->` found. It must be followed by the return type.
return p.parseType(optionalReturnType);
}
mlir::Type type;
if (p.parseType(type))
return mlir::failure();
if (isa<cir::VoidType>(type))
// An explicit !cir.void means also no return type.
optionalReturnType = {};
else
// Otherwise use the actual type.
optionalReturnType = type;
return p.parseLParen();
// Function has `void` return in C++, no return in MLIR.
optionalReturnType = {};
return success();
}

// 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 << '(';
p << " -> " << optionalReturnType;
}

static mlir::ParseResult
parseFuncTypeArgs(mlir::AsmParser &p, llvm::SmallVector<mlir::Type> &params,
bool &isVarArg) {
isVarArg = false;
// `(` `)`
if (succeeded(p.parseOptionalRParen()))
if (failed(p.parseLParen()))
return failure();
if (succeeded(p.parseOptionalRParen())) {
// `()` empty argument list
return mlir::success();

// `(` `...` `)`
if (succeeded(p.parseOptionalEllipsis())) {
isVarArg = true;
return p.parseRParen();
}

// type (`,` type)* (`,` `...`)?
mlir::Type type;
if (p.parseType(type))
return mlir::failure();
params.push_back(type);
while (succeeded(p.parseOptionalComma())) {
do {
if (succeeded(p.parseOptionalEllipsis())) {
// `...`, which must be the last thing in the list.
isVarArg = true;
return p.parseRParen();
break;
} else {
mlir::Type argType;
if (failed(p.parseType(argType)))
return failure();
params.push_back(argType);
}
if (p.parseType(type))
return mlir::failure();
params.push_back(type);
}

} while (succeeded(p.parseOptionalComma()));
return p.parseRParen();
}

static void printFuncTypeArgs(mlir::AsmPrinter &p,
mlir::ArrayRef<mlir::Type> params,
bool isVarArg) {
p << '(';
llvm::interleaveComma(params, p,
[&p](mlir::Type type) { p.printType(type); });
if (isVarArg) {
Expand All @@ -1010,45 +995,52 @@ static void printFuncTypeArgs(mlir::AsmPrinter &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,
mlir::Type &optionalReturnType,
llvm::SmallVector<mlir::Type> &params,
bool &isVarArg) {
if (failed(parseFuncTypeReturn(p, optionalReturnTypes)))
if (failed(parseFuncTypeArgs(p, params, isVarArg)))
return failure();
return parseFuncTypeArgs(p, params, isVarArg);
return parseFuncTypeReturn(p, optionalReturnType);
}

static void printFuncType(mlir::AsmPrinter &p, mlir::Type optionalReturnTypes,
static void printFuncType(mlir::AsmPrinter &p, mlir::Type optionalReturnType,
mlir::ArrayRef<mlir::Type> params, bool isVarArg) {
printFuncTypeReturn(p, optionalReturnTypes);
printFuncTypeArgs(p, params, isVarArg);
printFuncTypeReturn(p, optionalReturnType);
}

// Return the actual return type or an explicit !cir.void if the function does
// not return anything
/// Get the C-style return type of the function, which is !cir.void if the
/// function returns nothing and the actual return type otherwise.
mlir::Type FuncType::getReturnType() const {
if (isVoid())
if (hasVoidReturn())
return cir::VoidType::get(getContext());
return static_cast<detail::FuncTypeStorage *>(getImpl())->optionalReturnType;
return getOptionalReturnType();
}

/// Returns the result type of the function as an ArrayRef, enabling better
/// integration with generic MLIR utilities.
/// Get the MLIR-style return type of the function, which is an empty
/// ArrayRef if the function returns nothing and a single-element ArrayRef
/// with the actual return type otherwise.
llvm::ArrayRef<mlir::Type> FuncType::getReturnTypes() const {
if (isVoid())
if (hasVoidReturn())
return {};
return static_cast<detail::FuncTypeStorage *>(getImpl())->optionalReturnType;
}

// Whether the function returns void
bool FuncType::isVoid() const {
auto rt =
static_cast<detail::FuncTypeStorage *>(getImpl())->optionalReturnType;
assert(!rt ||
!mlir::isa<cir::VoidType>(rt) &&
"The return type for a function returning void should be empty "
"instead of a real !cir.void");
return !rt;
// Can't use getOptionalReturnType() here because llvm::ArrayRef hold a
// pointer to its elements and doesn't do lifetime extension. That would
// result in returning a pointer to a temporary that has gone out of scope.
return getImpl()->optionalReturnType;
}

// Does the fuction type return nothing?
bool FuncType::hasVoidReturn() const { return !getOptionalReturnType(); }

mlir::LogicalResult
FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
bool isVarArg) {
if (returnType && mlir::isa<cir::VoidType>(returnType)) {
emitError() << "!cir.func cannot have an explicit 'void' return type";
return mlir::failure();
}
return mlir::success();
}

//===----------------------------------------------------------------------===//
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CIR/CallConvLowering/AArch64/ptr-fields.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ int foo(int x) { return x; }
// CIR: %[[#V0:]] = cir.alloca !ty_A, !cir.ptr<!ty_A>, [""] {alignment = 4 : i64}
// CIR: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_A>), !cir.ptr<!u64i>
// CIR: cir.store %arg0, %[[#V1]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[#V2:]] = cir.get_global @foo : !cir.ptr<!cir.func<!s32i (!s32i)>>
// CIR: %[[#V3:]] = cir.get_member %[[#V0]][0] {name = "f"} : !cir.ptr<!ty_A> -> !cir.ptr<!cir.ptr<!cir.func<!s32i (!s32i)>>>
// CIR: cir.store %[[#V2]], %[[#V3]] : !cir.ptr<!cir.func<!s32i (!s32i)>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!s32i)>>>
// CIR: %[[#V2:]] = cir.get_global @foo : !cir.ptr<!cir.func<(!s32i) -> !s32i>>
// CIR: %[[#V3:]] = cir.get_member %[[#V0]][0] {name = "f"} : !cir.ptr<!ty_A> -> !cir.ptr<!cir.ptr<!cir.func<(!s32i) -> !s32i>>>
// CIR: cir.store %[[#V2]], %[[#V3]] : !cir.ptr<!cir.func<(!s32i) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!s32i) -> !s32i>>>
// CIR: cir.return

// LLVM: void @passA(i64 %[[#V0:]])
Expand Down
22 changes: 11 additions & 11 deletions clang/test/CIR/CallConvLowering/x86_64/fptrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ typedef int (*myfptr)(S);
int foo(S s) { return 42 + s.a; }

// CHECK: cir.func {{.*@bar}}
// CHECK: %[[#V0:]] = cir.alloca !cir.ptr<!cir.func<!s32i (!ty_S)>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!ty_S)>>>, ["a", init]
// CHECK: %[[#V1:]] = cir.get_global @foo : !cir.ptr<!cir.func<!s32i (!s32i)>>
// CHECK: %[[#V2:]] = cir.cast(bitcast, %[[#V1]] : !cir.ptr<!cir.func<!s32i (!s32i)>>), !cir.ptr<!cir.func<!s32i (!ty_S)>>
// CHECK: cir.store %[[#V2]], %[[#V0]] : !cir.ptr<!cir.func<!s32i (!ty_S)>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!ty_S)>>>
// CHECK: %[[#V0:]] = cir.alloca !cir.ptr<!cir.func<(!ty_S) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!ty_S) -> !s32i>>>, ["a", init]
// CHECK: %[[#V1:]] = cir.get_global @foo : !cir.ptr<!cir.func<(!s32i) -> !s32i>>
// CHECK: %[[#V2:]] = cir.cast(bitcast, %[[#V1]] : !cir.ptr<!cir.func<(!s32i) -> !s32i>>), !cir.ptr<!cir.func<(!ty_S) -> !s32i>>
// CHECK: cir.store %[[#V2]], %[[#V0]] : !cir.ptr<!cir.func<(!ty_S) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!ty_S) -> !s32i>>>
void bar() {
myfptr a = foo;
}
Expand All @@ -22,15 +22,15 @@ void bar() {
// CHECK: %[[#V0:]] = cir.alloca !ty_S, !cir.ptr<!ty_S>, [""] {alignment = 4 : i64}
// CHECK: %[[#V1:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S>), !cir.ptr<!s32i>
// CHECK: cir.store %arg0, %[[#V1]] : !s32i, !cir.ptr<!s32i>
// CHECK: %[[#V2:]] = cir.alloca !cir.ptr<!cir.func<!s32i (!ty_S)>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!ty_S)>>>, ["a", init]
// CHECK: %[[#V3:]] = cir.get_global @foo : !cir.ptr<!cir.func<!s32i (!s32i)>>
// CHECK: %[[#V4:]] = cir.cast(bitcast, %[[#V3]] : !cir.ptr<!cir.func<!s32i (!s32i)>>), !cir.ptr<!cir.func<!s32i (!ty_S)>>
// CHECK: cir.store %[[#V4]], %[[#V2]] : !cir.ptr<!cir.func<!s32i (!ty_S)>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!ty_S)>>>
// CHECK: %[[#V5:]] = cir.load %[[#V2]] : !cir.ptr<!cir.ptr<!cir.func<!s32i (!ty_S)>>>, !cir.ptr<!cir.func<!s32i (!ty_S)>>
// CHECK: %[[#V2:]] = cir.alloca !cir.ptr<!cir.func<(!ty_S) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!ty_S) -> !s32i>>>, ["a", init]
// CHECK: %[[#V3:]] = cir.get_global @foo : !cir.ptr<!cir.func<(!s32i) -> !s32i>>
// CHECK: %[[#V4:]] = cir.cast(bitcast, %[[#V3]] : !cir.ptr<!cir.func<(!s32i) -> !s32i>>), !cir.ptr<!cir.func<(!ty_S) -> !s32i>>
// CHECK: cir.store %[[#V4]], %[[#V2]] : !cir.ptr<!cir.func<(!ty_S) -> !s32i>>, !cir.ptr<!cir.ptr<!cir.func<(!ty_S) -> !s32i>>>
// CHECK: %[[#V5:]] = cir.load %[[#V2]] : !cir.ptr<!cir.ptr<!cir.func<(!ty_S) -> !s32i>>>, !cir.ptr<!cir.func<(!ty_S) -> !s32i>>
// CHECK: %[[#V6:]] = cir.cast(bitcast, %[[#V0]] : !cir.ptr<!ty_S>), !cir.ptr<!s32i>
// CHECK: %[[#V7:]] = cir.load %[[#V6]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[#V8:]] = cir.cast(bitcast, %[[#V5]] : !cir.ptr<!cir.func<!s32i (!ty_S)>>), !cir.ptr<!cir.func<!s32i (!s32i)>>
// CHECK: %[[#V9:]] = cir.call %[[#V8]](%[[#V7]]) : (!cir.ptr<!cir.func<!s32i (!s32i)>>, !s32i) -> !s32i
// CHECK: %[[#V8:]] = cir.cast(bitcast, %[[#V5]] : !cir.ptr<!cir.func<(!ty_S) -> !s32i>>), !cir.ptr<!cir.func<(!s32i) -> !s32i>>
// CHECK: %[[#V9:]] = cir.call %[[#V8]](%[[#V7]]) : (!cir.ptr<!cir.func<(!s32i) -> !s32i>>, !s32i) -> !s32i

// LLVM: define dso_local void @baz(i32 %0)
// LLVM: %[[#V1:]] = alloca %struct.S, i64 1
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CIR/CodeGen/coro-task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,19 +359,19 @@ folly::coro::Task<int> go4() {
// CHECK: %17 = cir.alloca !ty_anon2E2_, !cir.ptr<!ty_anon2E2_>, ["ref.tmp1"] {alignment = 1 : i64}

// Get the lambda invoker ptr via `lambda operator folly::coro::Task<int> (*)(int const&)()`
// CHECK: %18 = cir.call @_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%17) : (!cir.ptr<!ty_anon2E2_>) -> !cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>
// CHECK: %19 = cir.unary(plus, %18) : !cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>, !cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>
// CHECK: cir.yield %19 : !cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>
// CHECK: %18 = cir.call @_ZZ3go4vENK3$_0cvPFN5folly4coro4TaskIiEERKiEEv(%17) : (!cir.ptr<!ty_anon2E2_>) -> !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>
// CHECK: %19 = cir.unary(plus, %18) : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>
// CHECK: cir.yield %19 : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>
// CHECK: }
// CHECK: cir.store %12, %3 : !cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>, !cir.ptr<!cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>>
// CHECK: cir.store %12, %3 : !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>
// CHECK: cir.scope {
// CHECK: %17 = cir.alloca !s32i, !cir.ptr<!s32i>, ["ref.tmp2", init] {alignment = 4 : i64}
// CHECK: %18 = cir.load %3 : !cir.ptr<!cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>>, !cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>
// CHECK: %18 = cir.load %3 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>>, !cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>
// CHECK: %19 = cir.const #cir.int<3> : !s32i
// CHECK: cir.store %19, %17 : !s32i, !cir.ptr<!s32i>

// Call invoker, which calls operator() indirectly.
// CHECK: %20 = cir.call %18(%17) : (!cir.ptr<!cir.func<![[IntTask]] (!cir.ptr<!s32i>)>>, !cir.ptr<!s32i>) -> ![[IntTask]]
// CHECK: %20 = cir.call %18(%17) : (!cir.ptr<!cir.func<(!cir.ptr<!s32i>) -> ![[IntTask]]>>, !cir.ptr<!s32i>) -> ![[IntTask]]
// CHECK: cir.store %20, %4 : ![[IntTask]], !cir.ptr<![[IntTask]]>
// CHECK: }

Expand Down
10 changes: 5 additions & 5 deletions clang/test/CIR/CodeGen/derived-to-base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ void vcall(C1 &c1) {
// CHECK: %5 = cir.load %2 : !cir.ptr<!s32i>, !s32i
// CHECK: cir.call @_ZN5buffyC2ERKS_(%3, %1) : (!cir.ptr<!ty_buffy>, !cir.ptr<!ty_buffy>) -> ()
// CHECK: %6 = cir.load %3 : !cir.ptr<!ty_buffy>, !ty_buffy
// CHECK: %7 = cir.cast(bitcast, %4 : !cir.ptr<!ty_C1_>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>>>
// CHECK: %8 = cir.load %7 : !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>>>, !cir.ptr<!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>>
// CHECK: %9 = cir.vtable.address_point( %8 : !cir.ptr<!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>>, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>>
// CHECK: %10 = cir.load align(8) %9 : !cir.ptr<!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>>, !cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>
// CHECK: %11 = cir.call %10(%4, %5, %6) : (!cir.ptr<!cir.func<!s32i (!cir.ptr<!ty_C1_>, !s32i, !ty_buffy)>>, !cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i
// CHECK: %7 = cir.cast(bitcast, %4 : !cir.ptr<!ty_C1_>), !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>>
// CHECK: %8 = cir.load %7 : !cir.ptr<!cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>>, !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>
// CHECK: %9 = cir.vtable.address_point( %8 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>, vtable_index = 0, address_point_index = 2) : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>
// CHECK: %10 = cir.load align(8) %9 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>>, !cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>
// CHECK: %11 = cir.call %10(%4, %5, %6) : (!cir.ptr<!cir.func<(!cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i>>, !cir.ptr<!ty_C1_>, !s32i, !ty_buffy) -> !s32i
// CHECK: cir.return
// CHECK: }

Expand Down
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/dtors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class B : public A
};

// Class A
// CHECK: ![[ClassA:ty_.*]] = !cir.struct<class "A" {!cir.ptr<!cir.ptr<!cir.func<!u32i ()>>>} #cir.record.decl.ast>
// CHECK: ![[ClassA:ty_.*]] = !cir.struct<class "A" {!cir.ptr<!cir.ptr<!cir.func<() -> !u32i>>>} #cir.record.decl.ast>

// Class B
// CHECK: ![[ClassB:ty_.*]] = !cir.struct<class "B" {![[ClassA]]}>
Expand Down
Loading
Loading