mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:30:12 +01:00
When the C++ function has a parameter that is not a pointer and not a
signed integer of 32 or 64 bits, generate a thunk.
Terminology:
* Callee function: The C++ function we actually want to call.
* Thunk function: The C++ function we generated that calls the callee
function.
* A simple ABI type, for now, is one of:
* A pointer
* signed integer with 32 bits
* signed integer with 64 bits
The thunk function is marked `always_inline` and uses the `asm`
attribute to set its mangled to the callee function mangled name
suffixed with `".carbon_thunk"`.
When importing a C++ function, we decide whether calling it requires a
thunk and if so we generate it and import it as well, which is currently
a recursive call.
When calling the thunk function, we initialize a temporary storage for
each non simple ABI parameter type and take its address. This can be
optimized when the variable is already in storage.
Not supported yet:
* Functions with non void return values.
* Member methods.
Moved unsigned int param test from `arithmetic_types_direct.carbon` to
`arithmetic_types_bridged.carbon`, since only signed integers aren't
bridged using a thunk.
C++ Interop Demo:
```c++
// hello_world.h
struct S {
S() {}
S(const S&) { x = 1; }
int x;
};
void hello_world(S s);
```
```c++
// hello_world.cpp
#include "hello_world.h"
#include <cstdio>
void hello_world2(S s) { printf("hello_world2: %d\n", s.x); }
void hello_world(S s) {
printf("hello_world: %d\n", s.x);
hello_world2(s);
}
```
```carbon
// main.carbon
library "Main";
import Cpp library "hello_world.h";
fn Run() -> i32 {
var s : Cpp.S;
Cpp.hello_world(s);
return 0;
}
```
```shell
$ clang -c hello_world.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo
$ ./demo
hello_world: 1
hello_world2: 1
```
Before this change (no thunk - copy constructor not called when calling
`hello_world()`):
```shell
$ ./demo
hello_world: -1219172304
hello_world2: 1
```
39 lines
1.7 KiB
C++
39 lines
1.7 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef CARBON_TOOLCHAIN_CHECK_CPP_THUNK_H_
|
|
#define CARBON_TOOLCHAIN_CHECK_CPP_THUNK_H_
|
|
|
|
#include "toolchain/check/context.h"
|
|
#include "toolchain/sem_ir/ids.h"
|
|
|
|
namespace Carbon::Check {
|
|
|
|
// Returns whether the given C++ imported function requires a C++ thunk to be
|
|
// used to call it. A C++ thunk is required for functions that use any type
|
|
// except void, pointer types and signed 32-bit and 64-bit integers.
|
|
auto IsCppThunkRequired(Context& context, const SemIR::Function& function)
|
|
-> bool;
|
|
|
|
// Given a function signature and a callee function, builds a C++ thunk with
|
|
// simple ABI (pointers, i32 and i64 types) that calls the specified callee.
|
|
// Assumes `IsCppThunkRequired()` return true for `callee_function`. Returns
|
|
// `nullptr` on failure.
|
|
auto BuildCppThunk(Context& context, const SemIR::Function& callee_function)
|
|
-> clang::FunctionDecl*;
|
|
|
|
// Builds a call to a thunk function that forwards a call argument list built
|
|
// for `callee_function_id` to a call to `thunk_callee_id`, for use when
|
|
// building a call from a C++ thunk to its target. This is like `PerformCall`,
|
|
// except that it takes a list of call arguments for `callee_function_id`, not a
|
|
// syntactic argument list.
|
|
auto PerformCppThunkCall(Context& context, SemIR::LocId loc_id,
|
|
SemIR::FunctionId callee_function_id,
|
|
llvm::ArrayRef<SemIR::InstId> callee_arg_ids,
|
|
SemIR::InstId thunk_callee_id) -> SemIR::InstId;
|
|
|
|
} // namespace Carbon::Check
|
|
|
|
#endif // CARBON_TOOLCHAIN_CHECK_CPP_THUNK_H_
|