Info
-
Did you know that C++20 added support for Unevaluated asm-declaration in constexpr functions?
Example
constexpr auto get = [](auto value) {
if consteval {
return value;
} else {
auto result = 0;
asm("movl $42, %%eax\n" : "=r" (result) );
return result;
}
};
static_assert(0 == get(0));
static_assert(4 == get(4));
static_assert(2 == get(2));
consteval auto fn() {
return get(0);
}
int main(int argc, char**) {
assert(42 == get(0));
assert(42 == get(argc));
return fn();
}
Puzzle
Can you implement
const_sub_or_asm_add
which subtract given numbers using C++ operators if values can be constant evaluated and adds them using inline assembly otherwise?
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
return 0; /*TODO*/
};
static_assert(1 == const_sub_or_asm_add(2, 1));
static_assert(-1 == const_sub_or_asm_add(3, 4));
int main(int argc, char**) {
{
constexpr auto c = const_sub_or_asm_add(1, 2);
assert(-1 == c);
}
{
auto c = const_sub_or_asm_add(1, 2);
assert(3 == c);
}
{
assert(3 == const_sub_or_asm_add(1, 2));
assert(1 == const_sub_or_asm_add(argc, 0));
assert(2 == const_sub_or_asm_add(argc, argc));
}
}
Solutions
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
if consteval {
return lhs - rhs;
} else {
auto result = 0;
asm ("addl %%ebx,%%eax"
:"=a"(result)
:"a"(lhs), "b"(rhs)
);
return result;
}
};
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
if consteval {
return lhs - rhs;
} else {
decltype(lhs + rhs) result;
asm("leal (%1, %2), %0\n" : "=r"(result) : "r"(lhs), "r"(rhs));
return result;
}
};
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
if consteval {
return lhs - rhs;
} else {
auto result = 0;
asm("add %%edx, %%eax\n" : "=r" (result) : "edx" (lhs), "eax" (rhs) );
return result;
}
};
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
if consteval {
return lhs - rhs;
} else {
auto result = 0;
asm("movl %2, %0;"
"addl %1, %0;"
: "=&r"(result)
: "r"(lhs), "r"(rhs));
return result;
}
};
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
if (std::is_constant_evaluated())
return lhs - rhs;
asm("addl %%ebx, %%eax;" : "=a" (lhs) : "a" (lhs) , "b" (rhs) );
return lhs;
};
constexpr auto const_sub_or_asm_add = [](auto lhs, auto rhs) {
if consteval {
return lhs - rhs;
} else {
auto add{0};
asm("addl %%ebx, %%eax\n"
: "=a" (add)
: "a" (lhs), "b" (rhs) );
return lhs + rhs;
}
return 0; /*TODO*/
};