-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Carbon is a simple language embedded in C++. The syntax is a subset of Boost.Phoenix. Carbon has been implemented with Thrust in mind. Therefore its main purpose is to act as a lambda library for Thrust. Carbon makes it more convenient to specify simple functors as arguments to Thrust functions like thrust::transform
and thrust::reduce
. Here is an example :
SAXPY in Thrust without Carbon
struct saxpy_functor : public thrust::binary_function<float,float,float>
{
const float a;
saxpy_functor(float _a) : a(_a) {}
__host__ __device__
float operator()(const float& x, const float& y) const {
return a * x + y;
}
};
void saxpy_fast(float A, thrust::device_vector<float>& X, thrust::device_vector<float>& Y)
{
// Y <- A * X + Y
thrust::transform(X.begin(), X.end(), Y.begin(), Y.begin(), saxpy_functor(A));
}
struct saxpy_functor : public thrust::binary_function<float,float,float>
{
const float a;
saxpy_functor(float _a) : a(_a) {}
__host__ __device__
float operator()(const float& x, const float& y) const {
return a * x + y;
}
};
void saxpy_fast(float A, thrust::device_vector<float>& X, thrust::device_vector<float>& Y)
{
// Y <- A * X + Y
thrust::transform(X.begin(), X.end(), Y.begin(), Y.begin(), saxpy_functor(A));
}
using namespace carbon::lambda;
void saxpy_fast(float A, thrust::device_vector<float>& X, thrust::device_vector<float>& Y)
{
// Y <- A * X + Y
thrust::transform(X.begin(), X.end(), Y.begin(), Y.begin(), A*_1+_2);
}
Here is a somewhat complex example of a program that you can write in Carbon.
int i=0, j=41;
let_(_a=_2) [
while_(_a >= 0) [
_1 = _1 + 1,
_a = _a-1
]
] (i, j);
cout << i << "\n";
The above code should print
42
Carbon defines a set of predefined symbols (like _1, _2, _a, _b
, etc) and overloads most operators for these symbols. You can form C++ expressions using these symbols and operators. Let’s call these expressions Carbon programs. For example,
_1+_2
and
_2 = _1 + 42
are Carbon programs. Carbon programs have the function call operator (
operator()
) overloaded. Therefore you can use Carbon programs as regular C++ functions, or pass them around as function objects. (As of this writing, Carbon programs can take only 2 parameters). In Thrust context, you can pass a Carbon program as an argument to, say, thrust::transform
. That Carbon program gets pass down to the GPU, and executes on the device! There are 2 kinds of Carbon programs, as described below.
These are programs that look like C++ r-values, i.e., they don’t have assignments. In other words, they are pure functions. For example,
_1 + _2
is a functional Carbon program, and calling it like this
(_1+_2)(1, 41)
returns
42
.
These are programs that have assignment statements, sequence of statements, if-then-else constructs, etc. They return void, and to get back result from them, you have to pass an l-value as one of the arguments to the call. For example,
int i;
(_1 = _2+1)(i, 41)
cout << i << "\n";
prints out
42
.
Carbon defines the constant objects _1, _2, _3, _4
in the carbon::lambda
namespace. They act as placeholders or proxies for parameters passed when calling a Carbon programs. _1
is a placeholder for the first parameter, _2
for the second parameter and so on.
Carbon overloads most operators for the Carbon expressions. Therefore you can form expressions using operators like +,-,*,/
. (As of this writing, the pre/post increment operators ++, --
and the index operator []
have not been overloaded.)
Carbon overloads the assignment operator =
, so you can write assignments of the form _1=_2+41
. Note that you can only use the simple assignment operator =
in assignment statements. Other assignment operators like +=, -=, |=
etc. are not allowed.
You can form a sequence of statements using the comma (,
) operator. Example :
_1 = _2, _2 = 3.14*_1*_1
You can think of the comma operator as the semi-colon (
;
) of Carbon programs.
if_(expression) [
sequence of statements
].else_ [
sequence of statements
]
```