Example
/*
divide_by_32_no_assume(int):
lea eax, [rdi + 31]
test edi, edi
cmovns eax, edi
sar eax, 5
ret
*/
auto divide_by_32_no_assume(int x) {
return x / 32;
}
/*
divide_by_32_assume(int):
mov eax, edi
shr eax, 5
ret
*/
auto divide_by_32_assume(int x) {
__builtin_assume(x >= 0);
return x / 32;
}
Puzzle
-
Can you modify given examples by adding assume attribute so that sum_impl/g1/g2 functions will be optimized?
- Note: Expected optimized assembly is provided above the functions
/* TODO - modify sum_impl by adding assume attribute so that sum_impl will be optimized */
auto sum(auto... ts) {
return sum_impl(ts...);
}
/*
sum_impl(int, int, int):
imul esi, edx
lea eax, [rsi + rdi]
ret
*/
auto sum_impl(int src, int n, int s) {
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
/* TODO - modify smart_ptr by adding assume attribute so that g1/g2 will be optimized */
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
/*
g1(smart_ptr):
mov eax, dword ptr [rdi]
ret
*/
auto g1(smart_ptr p) { return p.counter(); }
/*
g2(smart_ptr):
mov eax, dword ptr [rdi]
inc eax
ret
*/
auto g2(smart_ptr p) { return g1(p); }
Solutions
auto sum_impl(int src, int n, int s) {
auto i = 0;
__builtin_assume(i < n);
for (; i < n ; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ >= 1);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) {
destroy();
}
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n > 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(r.counter_ >= 1);
++counter_;
}
~smart_ptr() {
__builtin_assume(counter_ > 0);
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ >= 1);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r)
: counter_(r.counter_) {
__builtin_assume(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
//src += n * s;
__builtin_assume(n > 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ >= 1);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
#if defined(__clang__)
#define ASSUME(expr) __builtin_assume(expr)
#elif defined(__GNUC__) && !defined(__ICC)
#define ASSUME(expr) if (expr) {} else { __builtin_unreachable(); }
#elif defined(_MSC_VER) || defined(__ICC)
#define ASSUME(expr) __assume(expr)
#endif
auto sum_impl(int src, int n, int s) {
ASSUME(n > 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
ASSUME(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(r.counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};
auto sum_impl(int src, int n, int s) {
__builtin_assume(n >= 0);
for (auto i = 0; i < n; ++i) {
src += s;
}
return src;
}
struct smart_ptr final {
constexpr explicit(false) smart_ptr(const smart_ptr& r) : counter_(r.counter_) {
__builtin_assume(counter_ > 0);
++counter_;
}
~smart_ptr() {
if (--counter_ == 0) destroy();
}
[[nodiscard]] auto counter() const { return counter_; }
private:
void destroy();
int counter_{};
};