MSVC: warning C4714
От: rus blood Россия  
Дата: 09.03.13 16:23
Оценка:
Добрый день.

Как известно, компилятор не может за-inline-ить функцию в некоторых случаях.
В частности, MSVC выдает warning C4714 в случае, если функция возвращает объект класса с деструктором, и выполняется сборка с /EHa,/EHs.
// EHa

struct A
{
    A() { }
    ~A() { MessageBox(0, "Hello, World!", 0, 0); }
};

__forceinline A GetA()
    { return A(); }    // warning C4714

int main(int /*argc*/, char* /*argv*/[])
{
    {
        auto a = GetA();
    }

    return 0;
}

Компилятор вставит в main вызов функции для "построения объекта a", которая ничего, кроме инициализации и деинициализации кода для раскрутки пустого стека, не делает.

Из-за этого, всякие конструкции типа ScopeGuard и SCOPE_EXIT Александреску не инлайнятся.
Мне кажется странным, что для построения guard-объекта вызывается функция, часто пустая, которая сама может бросить исключение.
Т.е., указывая компилятору некую функциональность, которую надо вызвать на выходе из scope, мы получаем в нагрузку определенный и не маленький оверхед.
Имею скафандр — готов путешествовать!
Re: MSVC: warning C4714
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 17:41
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Т.е., указывая компилятору некую функциональность, которую надо вызвать на выходе из scope, мы получаем в нагрузку определенный и не маленький оверхед.


MSVC2010SP1 Release:
/EHsc (default):
;    COMDAT main
_TEXT    SEGMENT
__formal$ = 48
__formal$ = 56
main    PROC                        ; COMDAT
; Line 13
$LN6:
    sub    rsp, 40                    ; 00000028H
; Line 16
    lea    rdx, OFFSET FLAT:??_C@_0O@KLMCIIGF@Hello?0?5World?$CB?$AA@
    xor    r9d, r9d
    xor    r8d, r8d
    xor    ecx, ecx
    call    QWORD PTR __imp_MessageBoxA
; Line 18
    xor    eax, eax
; Line 19
    add    rsp, 40                    ; 00000028H
    ret    0
main    ENDP
_TEXT    ENDS
END

/EHs:
;    COMDAT main
_TEXT    SEGMENT
__formal$ = 48
__formal$ = 56
main    PROC                        ; COMDAT
; Line 13
$LN6:
    sub    rsp, 40                    ; 00000028H
; Line 16
    lea    rdx, OFFSET FLAT:??_C@_0O@KLMCIIGF@Hello?0?5World?$CB?$AA@
    xor    r9d, r9d
    xor    r8d, r8d
    xor    ecx, ecx
    call    QWORD PTR __imp_MessageBoxA
; Line 18
    xor    eax, eax
; Line 19
    add    rsp, 40                    ; 00000028H
    ret    0
main    ENDP
_TEXT    ENDS
END

/EHa:
;    COMDAT text$x
text$x    SEGMENT
$T66300 = 0
$T66307 = 8
__$ReturnUdt$ = 32
?dtor$0@?0??GetA@@YA?AUA@@XZ@4HA PROC            ; `GetA'::`1'::dtor$0
    push    rbp
    sub    rsp, 32                    ; 00000020H
    mov    rbp, rdx
    mov    eax, DWORD PTR $T66300[rbp]
    and    eax, 1
    test    eax, eax
    je    SHORT $LN4@dtor$0
    and    DWORD PTR $T66300[rbp], -2
    mov    rcx, QWORD PTR __$ReturnUdt$[rbp]
    call    ??1A@@QEAA@XZ                ; A::~A
$LN4@dtor$0:
    add    rsp, 32                    ; 00000020H
    pop    rbp
    ret    0
?dtor$0@?0??GetA@@YA?AUA@@XZ@4HA ENDP            ; `GetA'::`1'::dtor$0
text$x    ENDS
PUBLIC    main
;    COMDAT pdata
pdata    SEGMENT
$pdata$main DD    imagerel $LN6
    DD    imagerel $LN6+42
    DD    imagerel $unwind$main
pdata    ENDS
;    COMDAT xdata
xdata    SEGMENT
$unwind$main DD    010401H
    DD    04204H
; Function compile flags: /Ogtpy
xdata    ENDS
;    COMDAT main
_TEXT    SEGMENT
__formal$ = 48
__formal$ = 56
a$66206 = 64
main    PROC                        ; COMDAT
; Line 13
$LN6:
    sub    rsp, 40                    ; 00000028H
; Line 15
    lea    rcx, QWORD PTR a$66206[rsp]
    call    ?GetA@@YA?AUA@@XZ            ; GetA
; Line 16
    lea    rdx, OFFSET FLAT:??_C@_0O@KLMCIIGF@Hello?0?5World?$CB?$AA@
    xor    r9d, r9d
    xor    r8d, r8d
    xor    ecx, ecx
    call    QWORD PTR __imp_MessageBoxA
; Line 18
    xor    eax, eax
; Line 19
    add    rsp, 40                    ; 00000028H
    ret    0
main    ENDP
_TEXT    ENDS
END


RB>Мне кажется странным, что для построения guard-объекта вызывается функция, часто пустая, которая сама может бросить исключение.


А что ты предлагаешь? Из-за того, что на одном из компиляторов, при non-default настройках, что-то не инлайнится — отказаться от type deduction и нормального синтаксиса?
SCOPE_EXIT { do(); };

Который от чисто языковой конструкции в языке D, отличается только ";"
Re[2]: MSVC: warning C4714
От: rus blood Россия  
Дата: 09.03.13 18:36
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>MSVC2010SP1 Release:

EP>/EHsc (default):
EP>/EHs:
EP>/EHa:

Ну, для чуть более нетривиального примера, наподобие SCOPE_EXIT, построение guard-а с помощью вызова функции происходит и при default /EHsc.

EP>Из-за того, что на одном из компиляторов, при non-default настройках, что-то не инлайнится — отказаться от type deduction и нормального синтаксиса?

EP>Который от чисто языковой конструкции в языке D, отличается только ";"

Меня производительность интересует больше чем красота кода.

Вопрос был — пробовал кто-нибудь красиво обойти это ограничение MSVC, или всем пофиг?
Имею скафандр — готов путешествовать!
Re[3]: MSVC: warning C4714
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 19:44
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Ну, для чуть более нетривиального примера, наподобие SCOPE_EXIT, построение guard-а с помощью вызова функции происходит и при default /EHsc.


Код в студию!

EP>>Из-за того, что на одном из компиляторов, при non-default настройках, что-то не инлайнится — отказаться от type deduction и нормального синтаксиса?

EP>>Который от чисто языковой конструкции в языке D, отличается только ";"
RB>Меня производительность интересует больше чем красота кода.

Функция с type deduction, возвращающая guard, в случае с lambda — как раз и нужна для производительности — если без неё, то будет std::function, что ещё хуже.
Если тебе действительно нужна производительность, и не нужна lambda, то можешь сделать просто отдельный guard:
#define CONCAT(x,y) CONCAT2(x,y)
#define CONCAT2(x,y) x ## y

#define SCOPE_EXIT struct CONCAT(ANON,__LINE__) { ~CONCAT(ANON,__LINE__)()
#define SCOPE_END } CONCAT(guard,__LINE__)

int main()
{
    SCOPE_EXIT
    {
        MessageBox(0, "Hello, World!", 0, 0);
    } SCOPE_END;
}



RB>Вопрос был — пробовал кто-нибудь красиво обойти это ограничение MSVC, или всем пофиг?


У тебя есть код, где это является проблемой?
Re[4]: MSVC: warning C4714
От: rus blood Россия  
Дата: 09.03.13 19:57
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Код в студию!


/EHsc
_wmain    PROC                        ; COMDAT

; 67   : {

  00000    83 ec 08     sub     esp, 8

; 68   :     {
; 69   :         SCOPE_EXIT{ MessageBox(0, 0, 0, 0); };

  00003    c6 44 24 04 00     mov     BYTE PTR $T73844[esp+8], 0
  00008    8b 44 24 04     mov     eax, DWORD PTR $T73844[esp+8]
  0000c    50         push     eax
  0000d    8d 44 24 08     lea     eax, DWORD PTR _STATEMENT_ON_EXIT0$68415[esp+12]
  00011    c6 44 24 07 00     mov     BYTE PTR $T73843[esp+12], 0
  00016    e8 00 00 00 00     call     ??$?HV<lambda0>@?A0x1f3a01f9@@@detail@@YA?AV?$ScopeGuard@V<lambda0>@?A0x1f3a01f9@@@@VScopeGuardOnExit@0@$$QAV<lambda0>@?A0x1f3a01f9@@@Z ; detail::operator+<`anonymous namespace'::<lambda0> >
  0001b    83 c4 04     add     esp, 4

; 71   :     }

  0001e    80 7c 24 05 00     cmp     BYTE PTR _STATEMENT_ON_EXIT0$68415[esp+9], 0
  00023    74 0e         je     SHORT $LN9@wmain
  00025    6a 00         push     0
  00027    6a 00         push     0
  00029    6a 00         push     0
  0002b    6a 00         push     0
  0002d    ff 15 00 00 00
    00         call     DWORD PTR __imp__MessageBoxW@16
$LN9@wmain:

; 73   :     return 0;

  00033    33 c0         xor     eax, eax

; 74   : }

  00035    83 c4 08     add     esp, 8
  00038    c3         ret     0
_wmain    ENDP
Имею скафандр — готов путешествовать!
Re[3]: MSVC: warning C4714
От: rus blood Россия  
Дата: 09.03.13 20:10
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Меня производительность интересует больше чем красота кода.

RB>Вопрос был — пробовал кто-нибудь красиво обойти это ограничение MSVC, или всем пофиг?

Например, в терминах из статьи:
  Скрытый текст
//  Alexandrescu
template <class Fun>
class ScopeGuard 
{
    Fun f_;
    bool active_;
public:
    ScopeGuard(Fun f)
        : f_(std::move(f)), active_(true) {}
    ~ScopeGuard() { if (active_) f_(); }
    void dismiss() { active_ = false; }
    ScopeGuard(ScopeGuard&& rhs)
        : f_(std::move(rhs.f_)), active_(rhs.active_) {rhs.dismiss();}
private:
    ScopeGuard();
    ScopeGuard(const ScopeGuard&);
    ScopeGuard& operator=(const ScopeGuard&);
};

#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __LINE__)
#endif


#define SCOPE_GUARD(N, F)    \
    auto CONCATENATE(N, _) = F;    \
    ScopeGuard<decltype(CONCATENATE(N, _))> N = std::move(CONCATENATE(N, _));
    
#define SCOPE_EXIT_(A)    \
    SCOPE_GUARD(ANONYMOUS_VARIABLE(STATEMENT_ON_EXIT), [&]()##A);


Приходится заключать функционал в скобки, зато результат (EHsc, EHs, EHa — пофиг):
_wmain    PROC                        ; COMDAT

; 79   :     {
; 80   :         SCOPE_EXIT_({ MessageBox(0, 0, 0, 0); });
; 81   :     }

  00000    6a 00         push     0
  00002    6a 00         push     0
  00004    6a 00         push     0
  00006    6a 00         push     0
  00008    ff 15 00 00 00
    00         call     DWORD PTR __imp__MessageBoxW@16

; 82   : 
; 83   :     return 0;

  0000e    33 c0         xor     eax, eax

; 84   : }

  00010    c3         ret     0
_wmain    ENDP
Имею скафандр — готов путешествовать!
Re[5]: MSVC: warning C4714
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 20:16
Оценка:
Здравствуйте, rus blood, Вы писали:

EP>>Код в студию!

RB>/EHsc

#include <Windows.h>
#include <utility>

template<typename Fun>
class Guard
{
    Fun f;
public:
    Guard(Fun &&f_)
        : f(std::move(f_))
    {}
    ~Guard()
    {
        f();
    }
};

struct Aux
{
    template<typename Fun>
    Guard<Fun> operator*(Fun &&f)
    {
        return Guard<Fun>(std::forward<Fun>(f));
    }
};

#define CONCAT(x,y) CONCAT2(x,y)
#define CONCAT2(x,y) x ## y

#define SCOPE_EXIT auto &&CONCAT(aux,__LINE__)= Aux()*[&]

int main()
{
    SCOPE_EXIT
    {
        MessageBox(0, 0, 0, 0);
    };
}


MSVC2010SP1 Release: /EHsc, /EHs:
_TEXT    SEGMENT
main    PROC                        ; COMDAT
; Line 33
$LN8:
    sub    rsp, 40                    ; 00000028H
; Line 38
    xor    r9d, r9d
    xor    r8d, r8d
    xor    edx, edx
    xor    ecx, ecx
    call    QWORD PTR __imp_MessageBoxA
    xor    eax, eax
    add    rsp, 40                    ; 00000028H
    ret    0
main    ENDP
_TEXT    ENDS
END

Re[6]: MSVC: warning C4714
От: rus blood Россия  
Дата: 09.03.13 20:27
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>


Под /EHa не оптимизирует, да и warning летит...

А ты у себя /EHa не используешь?
Имею скафандр — готов путешествовать!
Re[4]: MSVC: warning C4714
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 20:33
Оценка:
Здравствуйте, rus blood, Вы писали:


RB>Приходится заключать функционал в скобки, зато результат (EHsc, EHs, EHa — пофиг):

RB>SCOPE_EXIT_({ MessageBox(0, 0, 0, 0); });

Скобки как раз не проблема — фигурные можно убрать в макрос.
А вот например:
SCOPE_EXIT_({
        std::map<int,int> v;
        MessageBox(0, 0, 0, 0);
});

Re[7]: MSVC: warning C4714
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 20:37
Оценка:
Здравствуйте, rus blood, Вы писали:

EP>>

RB>Под /EHa не оптимизирует, да и warning летит...
RB>А ты у себя /EHa не используешь?

Я тебе уже показал
Автор: Evgeny.Panasyuk
Дата: 09.03.13
вывод /EHa на более простом примере
Re[7]: MSVC: warning C4714
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 20:44
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>да и warning летит...


Чтобы убрать C4189, нужно заменить
#define SCOPE_EXIT auto &&CONCAT(aux,__LINE__)= Aux()*[&]

на
#define SCOPE_EXIT auto CONCAT(aux,__LINE__)= Aux()*[&]
Re: stack_unwinding library
От: Evgeny.Panasyuk Россия  
Дата: 09.03.13 21:27
Оценка: 4 (1)
Кстати, stack_unwinding:
int main()
{
    using namespace std;
    {
        cout << "success case:" << endl;
        scope(exit)
        {
            cout << "exit" << endl;
        };
        scope(success)
        {
            cout << "success" << endl;
        };
        scope(failure)
        {
            cout << "failure" << endl;
        };
    }
    cout << string(16,'_') << endl;
    try
    {
        cout << "failure case:" << endl;
        scope(exit)
        {
            cout << "exit" << endl;
        };
        scope(success)
        {
            cout << "success" << endl;
        };
        scope(failure)
        {
            cout << "failure" << endl;
        };
        throw 1;
    }
    catch(int){}
}

Вывод:

success case:
success
exit
________________
failure case:
failure
exit

Re[8]: MSVC: warning C4714
От: rus blood Россия  
Дата: 09.03.13 21:57
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

RB>>Под /EHa не оптимизирует, да и warning летит...

RB>>А ты у себя /EHa не используешь?

EP>Я тебе уже показал
Автор: Evgeny.Panasyuk
Дата: 09.03.13
вывод /EHa на более простом примере


Ну да, вызов функции.
call    ?GetA@@YA?AUA@@XZ            ; GetA

Вот от него желательно избавиться.
Имею скафандр — готов путешествовать!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.