 
    g++ hello.cc get_name.cc ‑o hello
typedef struct {
    uint8_t h;
    uint8_t m;
} hh_mm;
bool
first_is_gt(hh_mm a, hh_mm b) {
    if (a.h > b.h)
        return true;
    if (a.h == b.h)
        return a.m > b.m;
    return false;
}
       
    
  Если в программе не выявлено ошибок, начинается процесс её перевода в промежуточное
      представление, которое:
      
На примере языка C++:
class my_class {
public:
  my_class(int a, int b) : m_a(a), m_b(b) { }
  int get_sum() { return m_a + m_b; }
private:
  int m_a, m_b;
};struct my_class {
  int m_a, m_b;
};
void _ZN8my_classC2Eii(struct my_class *this, int a, int b) {
  this->m_a = a;
  this->m_b = b;
}
int _ZN8my_class7get_sumEv(struct my_class *this) {
  return this->m_a + this->m_b;
} void copy(char *dest, const char *src) {
  while (*dest++ = *src++)
    ;
}   void copy(char *dest, const char *src) {
  char *dest_tmp, *src_tmp;
  do {
    dest_tmp = dest;
    dest = dest_tmp + 1;
    src_tmp = src;
    src = src_tmp + 1;
    char val = *src;
    *dest_tmp = val;
  } while (val != 0);
} 
    void foo(int a, int b) {
  if (a > b) {
    int x = a, y = b;
    bar(x, y);
  } else {
    int a = 1, y = 2;
    baz(a, y);
  }
}void foo(int a, int b) {
  int x, y_1, y_2, a_2;
  if (a > b) {
    x = a; y_1 = b;
    bar(x, y_1);
  } else {
    a_2 = 1; y_2 = 2;
    baz(a, y_2);
  }
}void cmp(int a, int b)
{
  if (a > b) {
    foo(1);
  } else {
    if (a == b)
      foo(0);
    else
      foo(-1);
  }
}
void cmp(int a, int b) {
bb_0:
  if (a > b) goto bb_1; else goto bb_2;
bb_1:
  foo(1);
  goto bb_5;
bb_2:
  if (a == b) goto bb_3; else goto bb_4;
bb_3:
  foo(0);
  goto bb_5;
bb_4:
  foo(-1);
bb_5:
  return;
}
      
void count(int n) {
  for (int i = 0; i < n; i += 5)
    foo(i);
}
      
void count(int n) {
  int i;
bb_0:
  i = 0;
  goto bb_2;
bb_1:
  foo(i);
  i = i + 5;
bb_2:
  if (i < n) goto bb_1; else goto bb_3;
bb_3:
  return;
}
       
    
int redundant(int x) {
  int y = 10;
  y += x;
  if (x > 0)
    y = 1;
  else
    y = 2;
  return y;
}
      
int redundant(int x) {
  int y;
bb_0:
  y = 10;
  y = y + x;
  if (x > 0) goto bb_1; else goto bb_2;
bb_1:
  y = 1;
  goto bb_2;
bb_2:
  y = 2;
bb_3:
  return y;
}
         
      
int redundant(int x) {
  int y_0, y_1, y_2, y_3, y_4;
bb_0:
  y_0 = 10;
  y_1 = y_0 + x;
  if (x > 0) goto bb_1; else goto bb_2;
bb_1:
  y_2 = 1;
  goto bb_3;
bb_2:
  y_3 = 2;
bb_3:
  y_4 = φ(y_2, y_3);
  return y4;
}
         
      Оптимизация, выполняемая компилятором — улучшение (в отличие от понятия оптимизации в математике).
Изначальные источники не оптимальности:По охватываемой области:
Отдельно можно выделить машинно-зависимые оптимизации, оптимизации циклов и др.
/* ~~x -> x */
(simplify
  (bit_not (bit_not @0))
  @0)
/* Simplify sin(x) / tan(x) -> cos(x). */
(simplify
 (rdiv (SIN:s @0) (TAN:s @0))
 (if (! HONOR_NANS (@0)
      && ! HONOR_INFINITIES (@0))
  (COS @0)))
    
  Затрагивают сразу несколько базовых блоков (вплоть до функции целиком).
int encode_image(int coeff, image_data *in, output_stream *out) {
  if (coeff < 0 || coeff > 100)
    return -EINVAL;
  return do_encode(coeff, in, out);
}
int encode_image_simple(quality q, image_data *in, output_stream *out) {
  int coeff;
  switch (q) {
  case Q_LOW:
    coeff = 50; break;
  case Q_MED:
    coeff = 75; break;
  case Q_HIGH:
    coeff = 90; break;
  default:
    return -EINVAL;
  }
  return encode_image(coeff, in, out);
}
    
int encode_image_simple(quality q,
                        image_data *in,
                        output_stream *out) {
  int coeff;
  switch (q) {
  case Q_LOW:
    coeff = 50; break;
  case Q_MED:
    coeff = 75; break;
  case Q_HIGH:
    coeff = 90; break;
  default:
    return -EINVAL;
  }
  // coeff: [50, 90]
  if (coeff < 0 || coeff > 100)
    return -EINVAL;
  return do_encode(coeff, in, out);
}
         
      
int encode_image_simple(quality q,
                        image_data *in,
                        output_stream *out) {
  int coeff;
  switch (q) {
  case Q_LOW:
    coeff = 50; break;
  case Q_MED:
    coeff = 75; break;
  case Q_HIGH:
    coeff = 90; break;
  default:
    return -EINVAL;
  }
  return do_encode(coeff, in, out);
}
         
      Состоит из несколько фаз (проходов). Анализ циклов включает в себя:
Полученные данные позволяют выполнять преобразования циклов, которые:
void unswitch(char *x, int n, bool flag)
{
  if (flag) {
    for (int i = 0; i < n; i++)
      if (flag)
        foo(x[i]);
      else
        bar(x[i]);
  } else {
    for (int i = 0; i < n; i++)
      if (flag)
        foo(x[i]);
      else
        bar(x[i]);
  }
}
      
void unswitch(char *x, int n, bool flag)
{
  if (flag) {
    for (int i = 0; i < n; i++)
      if (true)
        foo(x[i]);
      else
        bar(x[i]);
  } else {
    for (int i = 0; i < n; i++)
      if (false)
        foo(x[i]);
      else
        bar(x[i]);
  }
}
      
void unswitch(char *x, int n,
              bool flag)
{
  for (int i = 0; i < n; i++)
    if (flag)
      foo(x[i]);
    else
      bar(x[i]);
}
          
void unswitch(char *x, int n,
              bool flag)
{
  if (flag) {
    for (int i = 0; i < n; i++)
      foo(x[i]);
  } else {
    for (int i = 0; i < n; i++)
      bar(x[i]);
  }
}
        Распространяют по графу вызовов информацию:
Собранная информация позволяет оптимизировать функцию либо создать несколько версий одной функции, которые лучше поддаются оптимизации.
// test.c
struct point {
  int x, y, z;
};
static int
foo(const struct point *p) {
  return p->x + p->y;
}
int
bar(int x, int y) {
  struct point p = {x, y, 0};
  return foo(&p);
}
      
// После применения оптимизации
// "межпроцедурная скалярная
// замена агрегатов"
static int
foo_isra_0(int p0, int p1) {
  return p0 + p1;
}
int
bar(int x, int y) {
  return foo_isra_0(x, y);
}
      
static long add2(long *a, long *b) {
  return *a + *b;
}
long add3(long *a, long *b, long *c) {
  return add2(a, b) + *c;
}
    
; gcc -c test.c -O -fno-inline
add2: ; rsi = a, rdi = b
  mov     rax, QWORD PTR [rsi]
  add     rax, QWORD PTR [rdi]
  ret
add3: ; rsi=a, rdi=b, rdx=c
  push    rbx
  mov     rbx, rdx
  call    add2
  add     rax, QWORD PTR [rbx]
  pop     rbx
  ret
      
; gcc -c test.c -O
add3: ; rsi=a, rdi=b, rdx=c
  mov     rax, QWORD PTR [rsi]
  add     rax, QWORD PTR [rdi]
  add     rax, QWORD PTR [rdx]
  ret
      
#include <vector>
#include <numeric>
long sum(const std::vector<long>& vec) {
  return std::accumulate(vec.begin(), vec.end(), 0L);
}
    Встраивание производится двумя проходами оптимизатора, которые используют разные алгоритмы.
Жаркая дискуссия Линуса Торвальдса и мэйнтейнера GCC на тему эвристик
Попробуем скомпилировать программу:
uint8_t mod(uint8_t a, uint8_t b) {
    return a % b;
}
    Описание архитектуры процессора содержит таблицы поддерживаемых стандартных операций. Компилятор попытается найти в них что-нибудь подходящее, например:
В итоге (на x86) удастся найти шаблон udivmod для uint8_t
// Псевдокод шаблона udivmod
void udivmodqi4(uint8_t dividend, uint8_t divisor,
                uint8_t *remainder, uint8_t* quotient)
{
  *quotient = dividend / divisor;
  *remainder = dividend % divisor;
}
// Но в x86 инструкция деления работает несколько иначе.
// Псевдокод шаблона инструкции div для 8-битного делителя
// (с некоторыми допущениями):
void udivmodhiqi3(uint16_t dividend, uint8_t divisor, uint16_t *result)
{
  uint16_t quotient = (uint8_t)(dividend / (uint16_t)divisor);
  uint16_t remainder = (uint8_t)(dividend % (uint16_t)divisor);
  *result = (remainder << 8) | quotient;
}
    
// Реальная инструкция процессора делает не совсем то, что нам нужно
void udivmodhiqi3(uint16_t dividend, uint8_t divisor, uint16_t *result)
{
  uint16_t quotient = (uint8_t)(dividend / (uint16_t)divisor);
  uint16_t remainder = (uint8_t)(dividend % (uint16_t)divisor);
  *result = (remainder << 8) | quotient;
}
// Напишем адаптер
void udivmodqi4(uint8_t dividend, uint8_t divisor,
                uint8_t *remainder, uint8_t* quotient)
{
  union {
    uint16_t u16;
    struct { uint8_t low; uint8_t high; };
  } result;
  udivmodhiqi3((uint16_t)dividend, divisor, &result.u16);
  *remainder = result.high;
  *quotient = result.low;
}
    ;; Операнд 0 - результат ((remainder << 8) | quotient) ;; Операнд 1 - делимое ;; Операнд 2 - делитель (define_insn "udivmodhiqi3" [(set (match_operand:HI 0 "register_operand" "=a") (ior:HI (ashift:HI (zero_extend:HI (truncate:QI (mod:HI (match_operand:HI 1 "register_operand" "0") (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))) (const_int 8)) (zero_extend:HI (truncate:QI (div:HI (match_dup 1) (zero_extend:HI (match_dup 2))))))) (clobber (reg:CC FLAGS_REG))] "TARGET_QIMODE_MATH" "div{b}\t%2" [(set_attr "type" "idiv") (set_attr "mode" "QI")])
 
    
#define likely(x)    __builtin_expect((x),1)
int foo(int x) {
  if (likely(x < 0))
    x = bar(x);
  else
    x = baz(x);
  return x + 5;
}
      
foo: ; edi = x
    sub     rsp, 8
    test    edi, edi
    jns     .L2
    call    bar
.L3:
    add     eax, 5
    add     rsp, 8
    ret
.L2:
    call    baz
    jmp     .L3
      The real problem is that programmers have spent far too much time worrying about efficiency in the wrong place and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.Donald Ervin Knuth
Agner Fog Optimizing software in C++
 
       
    Поддержкой back-end компонентов обычно занимаются разработчики железа:
 
    Языки Go и Ada также поддерживаются крупными компаниями:
 
    Попробуйте использовать для сборки вашего кода еженедельные снэпшоты GCC (и прогонять unit-тесты).
Взамен за потраченные усилия вы: