@@ -50,106 +50,30 @@ static auto GenerateThunkMangledName(
5050 return mangled_name_stream.TakeStr ();
5151}
5252
53- // Returns true if a C++ thunk is required for the given type. A C++ thunk is
54- // required for any type except for void, pointer types and signed 32-bit and
55- // 64-bit integers.
56- static auto IsThunkRequiredForType (Context& context, SemIR::TypeId type_id)
57- -> bool {
58- if (!type_id.has_value () || type_id == SemIR::ErrorInst::TypeId) {
59- return false ;
60- }
61-
62- type_id = context.types ().GetUnqualifiedType (type_id);
63-
64- switch (context.types ().GetAsInst (type_id).kind ()) {
65- case SemIR::PointerType::Kind: {
66- return false ;
67- }
68-
69- case SemIR::ClassType::Kind: {
70- if (!context.types ().IsComplete (type_id)) {
71- // Signed integers of 32 or 64 bits should be completed when imported.
72- return true ;
73- }
74-
75- auto int_info = context.types ().TryGetIntTypeInfo (type_id);
76- if (!int_info || !int_info->bit_width .has_value ()) {
77- return true ;
78- }
79-
80- llvm::APInt bit_width = context.ints ().Get (int_info->bit_width );
81- return bit_width != 32 && bit_width != 64 ;
82- }
83-
84- default :
85- return true ;
86- }
87- }
88-
89- auto IsCppThunkRequired (Context& context, const SemIR::Function& function)
90- -> bool {
91- if (!function.clang_decl_id .has_value ()) {
92- return false ;
93- }
94-
95- // A thunk is required if any parameter or return type requires it. However,
96- // we don't generate a thunk if any relevant type is erroneous.
97- bool thunk_required = false ;
98-
99- const auto & decl_info = context.clang_decls ().Get (function.clang_decl_id );
100- const auto * decl = cast<clang::FunctionDecl>(decl_info.key .decl );
101- if (decl_info.key .num_params !=
102- static_cast <int >(decl->getNumNonObjectParams ())) {
103- // We require a thunk if the number of parameters we want isn't all of them.
104- // This happens if default arguments are in use, or (eventually) when
105- // calling a varargs function.
106- thunk_required = true ;
107- } else {
108- // We require a thunk if any parameter is of reference type, even if the
109- // corresponding SemIR function has an acceptable parameter type.
110- // TODO: We should be able to avoid thunks for reference parameters.
111- for (auto * param : decl->parameters ()) {
112- if (param->getType ()->isReferenceType ()) {
113- thunk_required = true ;
114- break ;
115- }
116- }
53+ // Returns whether the Carbon lowering for a parameter or return of this type is
54+ // known to match the C++ lowering.
55+ static auto IsSimpleAbiType (clang::ASTContext& ast_context,
56+ clang::QualType type, bool for_parameter) -> bool {
57+ if (type->isVoidType () || type->isPointerType ()) {
58+ return true ;
11759 }
11860
119- SemIR::TypeId return_type_id =
120- function.GetDeclaredReturnType (context.sem_ir ());
121- if (return_type_id.has_value ()) {
122- if (return_type_id == SemIR::ErrorInst::TypeId) {
123- return false ;
124- }
125- thunk_required =
126- thunk_required || IsThunkRequiredForType (context, return_type_id);
61+ if (!for_parameter && type->isLValueReferenceType ()) {
62+ // An lvalue reference return type maps to a pointer, which uses the same
63+ // lowering rule.
64+ return true ;
12765 }
12866
129- for (auto param_id :
130- context.inst_blocks ().GetOrEmpty (function.call_params_id )) {
131- if (param_id == SemIR::ErrorInst::InstId) {
67+ if (const auto * enum_decl = type->getAsEnumDecl ()) {
68+ // An enum type has a simple ABI if its underlying type does.
69+ type = enum_decl->getIntegerType ();
70+ if (type.isNull ()) {
13271 return false ;
13372 }
134- thunk_required =
135- thunk_required ||
136- IsThunkRequiredForType (
137- context, context.insts ().GetAs <SemIR::AnyParam>(param_id).type_id );
138- }
139-
140- return thunk_required;
141- }
142-
143- // Returns whether the type is void, a pointer, or a signed int of 32 or 64
144- // bits.
145- static auto IsSimpleAbiType (clang::ASTContext& ast_context,
146- clang::QualType type) -> bool {
147- if (type->isVoidType () || type->isPointerType ()) {
148- return true ;
14973 }
15074
15175 if (const auto * builtin_type = type->getAs <clang::BuiltinType>()) {
152- if (builtin_type->isSignedInteger ()) {
76+ if (builtin_type->isIntegerType ()) {
15377 uint64_t type_size = ast_context.getIntWidth (type);
15478 return type_size == 32 || type_size == 64 ;
15579 }
@@ -174,8 +98,8 @@ struct CalleeFunctionInfo {
17498 effective_return_type =
17599 is_ctor ? ast_context.getCanonicalTagType (method_decl->getParent ())
176100 : decl->getReturnType ();
177- has_simple_return_type =
178- IsSimpleAbiType (ast_context, effective_return_type );
101+ has_simple_return_type = IsSimpleAbiType (ast_context, effective_return_type,
102+ /* for_parameter= */ false );
179103 }
180104
181105 // Returns whether this callee has an implicit `this` parameter.
@@ -234,6 +158,52 @@ struct CalleeFunctionInfo {
234158};
235159} // namespace
236160
161+ auto IsCppThunkRequired (Context& context, const SemIR::Function& function)
162+ -> bool {
163+ if (!function.clang_decl_id .has_value ()) {
164+ return false ;
165+ }
166+
167+ const auto & decl_info = context.clang_decls ().Get (function.clang_decl_id );
168+ auto * decl = cast<clang::FunctionDecl>(decl_info.key .decl );
169+ if (decl_info.key .num_params !=
170+ static_cast <int >(decl->getNumNonObjectParams ())) {
171+ // We require a thunk if the number of parameters we want isn't all of them.
172+ // This happens if default arguments are in use, or (eventually) when
173+ // calling a varargs function.
174+ return true ;
175+ }
176+
177+ CalleeFunctionInfo callee_info (decl, decl_info.key .num_params );
178+ if (!callee_info.has_simple_return_type ) {
179+ return true ;
180+ }
181+
182+ auto & ast_context = context.ast_context ();
183+ if (callee_info.has_implicit_object_parameter ()) {
184+ // TODO: The object parameter is a reference parameter, but we don't force a
185+ // thunk here like we do for explicit reference parameters in the case where
186+ // we would map the parameter to an `addr` parameter. We should make this
187+ // behavior consistent.
188+ auto * method_decl = cast<clang::CXXMethodDecl>(decl);
189+ if (method_decl->getRefQualifier () == clang::RQ_RValue ||
190+ method_decl->getMethodQualifiers ().hasConst ()) {
191+ return true ;
192+ }
193+ }
194+
195+ const auto * function_type =
196+ decl->getType ()->castAs <clang::FunctionProtoType>();
197+ for (int i : llvm::seq (decl->getNumParams ())) {
198+ if (!IsSimpleAbiType (ast_context, function_type->getParamType (i),
199+ /* for_parameter=*/ true )) {
200+ return true ;
201+ }
202+ }
203+
204+ return false ;
205+ }
206+
237207// Given a pointer type, returns the corresponding _Nonnull-qualified pointer
238208// type.
239209static auto GetNonnullType (clang::ASTContext& ast_context,
@@ -255,7 +225,7 @@ static auto GetNonNullablePointerType(clang::ASTContext& ast_context,
255225static auto GetThunkParameterType (clang::ASTContext& ast_context,
256226 clang::QualType callee_type)
257227 -> clang::QualType {
258- if (IsSimpleAbiType (ast_context, callee_type)) {
228+ if (IsSimpleAbiType (ast_context, callee_type, /* for_parameter= */ true )) {
259229 return callee_type;
260230 }
261231 return GetNonNullablePointerType (ast_context, callee_type);
0 commit comments