Skip to content

Latest commit

 

History

History
673 lines (575 loc) · 12.7 KB

291.md

File metadata and controls

673 lines (575 loc) · 12.7 KB
Info

Example

void report_error();
[[gnu::cold]] void report_error_cold();
void logic();

/*
cold(bool):
        test    edi, edi
        jne     .LBB0_1
        jmp     logic()
.LBB0_1:
        jmp     report_error_cold()
*/
auto cold(bool error) {
    if (error) {
        report_error_cold();
        return;
    }

    logic();
}

/*
normal(bool):
        test    edi, edi
        je      .LBB1_2
        jmp     report_error()
.LBB1_2:
        jmp     logic()
*/
auto normal(bool error) {
    if (error) {
        report_error();
        return;
    }

    logic();
}

/*
unlikely(bool):
        test    edi, edi
        jne     .LBB2_1
        jmp     logic()
.LBB2_1:
        jmp     report_error()
*/
auto unlikely(bool error) {
    if (error) [[unlikely]] {
        report_error();
        return;
    }

    logic();
}

https://godbolt.org/z/EE1jjG45j

Puzzle

  • Can you implement required error policies using provided lambdas so that they will match assembly?
void logic();

template<auto ErrorPolicy>
auto handle(bool error) {
  if (error) {
    ErrorPolicy(error);
    return;
  }
  logic();
}

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) {}>(error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) { if (error) throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) {  }>(error);
}

https://godbolt.org/z/xPGs36dTM

Solutions

auto test_lambda_cold(bool error) {
    handle<[][[gnu::cold]](bool error) {}>(error);
}

auto test_lambda_throw(bool error) {
    handle<[](bool error) { if (error) throw; }>(error);
}

auto test_lambda_abort(bool error) {
    handle<[][[gnu::hot]] (bool error) { if (error) abort(); }>(error);
}

https://godbolt.org/z/fas5c6KKG

void report_error();
[[gnu::cold]] void report_error_cold();
void logic();

/*
cold(bool):
        test    edi, edi
        jne     .LBB0_1
        jmp     logic()
.LBB0_1:
        jmp     report_error_cold()
*/
auto cold(bool error) {
    if (error) {
        report_error_cold();
        return;
    }

    logic();
}

/*
normal(bool):
        test    edi, edi
        je      .LBB1_2
        jmp     report_error()
.LBB1_2:
        jmp     logic()
*/
auto normal(bool error) {
    if (error) {
        report_error();
        return;
    }

    logic();
}

/*
unlikely(bool):
        test    edi, edi
        jne     .LBB2_1
        jmp     logic()
.LBB2_1:
        jmp     report_error()
*/
auto unlikely(bool error) {
    if (error) [[unlikely]] {
        report_error();
        return;
    }

    logic();
}

https://godbolt.org/z/EE1jjG45j

Puzzle

  • Can you implement required error policies using provided lambdas so that they will match assembly?
void logic();

template<auto ErrorPolicy>
auto handle(bool error) {
  if (error) {
    ErrorPolicy(error);
    return;
  }
  logic();
}

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) {}>(error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) { if (error) throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) {  }>(error);
}

https://godbolt.org/z/xPGs36dTM

Solutions

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
  // adding the [[gnu::cold]] attribute to the lambda changes je to jne
  handle<[] [[gnu::cold]] (bool) {}>(error);
}

/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
  // no attribute needed here: does the throw already cause coldness?
  // consider: an if branch that throws is already considered [[unlikely]]
  handle<[] (bool) { throw; }>(error);
}

#include <cstdlib>

/*
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
  // does abort also imply coldness?
  // [[noreturn]] makes no difference here but may also imply coldness?
  handle<[] [[noreturn]] (bool) { std::abort(); }>(error);
}

https://godbolt.org/z/j39c5Kf4x

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    handle<[](bool error) {[[gnu::cold]]; }>(error);
}

/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    handle<[](bool error) { if (error) throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    handle<[](bool error) { abort(); }>(error);
}

https://godbolt.org/z/P5ssGz9f8

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    handle<[] [[gnu::cold]] (bool error) {}>(error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    handle<[](bool error) { if (error) throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    handle<[](bool error) { std::abort(); }>(error);
}

https://godbolt.org/z/s7KxMrhrK

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
  handle<[] [[gnu::cold]] {}>(error);
}

/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L6
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L6:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
  handle<[] [[gnu::cold]] { throw; }>(error);
}

#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L11
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L11:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
  handle<[] [[gnu::cold]] { std::abort(); }>(error);
}

https://godbolt.org/z/a8463WjzP

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[] [[gnu::cold]] (bool error) { }>(error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool) { throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) { std::abort(); }>(error);
}

https://godbolt.org/z/1zd87f1Gj

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[] [[gnu::cold]] (bool error) {}>(error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[] (bool error) { throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[] [[gnu::cold]] (bool error) { abort(); }>(error);
}

https://godbolt.org/z/5sz1jxdbe

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    // TODO - modify the following line to get the above assembly
    handle< [][[gnu::cold]](bool error) {}> (error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[]  (bool error) { if (error) [[unlikely]] throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[] (bool error) { if(error) [[unlikely]] abort(); }>( error);
}

https://godbolt.org/z/88b58cd45

/*
test_lambda_cold(bool):
        test    dil, dil
        jne     .L1
        jmp     logic()
.L1:
        ret
*/
auto test_lambda_cold(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error ) { [[unlikely]] return;}>(error);
}


/*
test_lambda_throw(bool):
        test    dil, dil
        jne     .L7
        jmp     logic()
test_lambda_throw(bool) [clone .cold]:
.L7:
        push    rax
        call    __cxa_rethrow
*/
auto test_lambda_throw(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) { if (error)[[unlikely]] throw; }>(error);
}


#include <cstdlib>

/**
test_lambda_abort(bool):
        test    dil, dil
        jne     .L12
        jmp     logic()
test_lambda_abort(bool) [clone .cold]:
.L12:
        push    rax
        call    abort
*/
auto test_lambda_abort(bool error) {
    // TODO - modify the following line to get the above assembly
    handle<[](bool error) { if (error)[[unlikely]] abort();  }>(error) ;
}

https://godbolt.org/z/frv8MPTY8