Interested in the question that is optimal for bool operation:
if (var1) var2 = false else var2 = true or
var2 = !var1 In other words, is it better to compare and subject to the desired value, or is it easier to assign a negative right away?
Interested in the question that is optimal for bool operation:
if (var1) var2 = false else var2 = true or
var2 = !var1 In other words, is it better to compare and subject to the desired value, or is it easier to assign a negative right away?
I am writing for a microprocessor - this is the idea that the second option is much faster, I just do not know the assembler.
It all depends on the compiler. It can inline this function to the place of the call and do anything with it, depending on the surrounding code. In general, I would expect the same code to come out, although this may not be the case.
It may be recalled that in a C, any non-zero value is true, therefore, inverting itself simply does not do that. As I understand it, it should decompose into a test statement and a conditional branch.
Options for how I could write this in assembly language (approximately, at the level of ideas). I don't specifically use ret, assuming that the function will be inline.
The most primitive variant, is similar to the first code without any optimizations:
test a jz ZERO jmp NONZERO ZERO: mov b 1 jmp DONE NONZERO: mov b 0 DONE: no Check, conditional jump, assignment, unconditional jump (not always).
Looks like the first one, a bit optimized:
test a jz ZERO mov b 0 jmp DONE ZERO: mov b 1 DONE: nop Check, assignment, exactly 1 transition (but in one of two places).
b = 0; if (!a) b = 1; optimized:
xor b, b // то же, что `mov b 0`, но быстрее test a jnz NONZERO mov b 1 NONZERO: nop For true a : Assignment, validation, transition.
For false a : Assignment, check, assignment.
I think for the option b = !a compiler will choose the best option. This is a very simple construction, with which it should be easier for him to understand, so you should choose it. Anyway, it is readable.
Yes, and another trick. If the compiler is sure that there is 0 or 1, it can replace the invert with xor like this b = a ^ 1 :
mov ba xor b 1 One move and one bit operation.
PS: And he can use specific commands that I do not know or do not remember. Or which is only in a specific processor.
sete command (found out thanks to this question and gcc -S) - "Sets the operand to 0." / gcc -O3 uses just her after testl - avpmov ebx, [var2] // xor eax, eax // sub ebx, 1 // adc eax, 0 // mov [var1], eax However, it’s a bit long and useless considering other options. - PinkTux@Uraty nice painted, I will try to go on the other side.
Wrote two small methods.
private static boolean m1(boolean value) { boolean result; if (value) result = false; else result = true; return result; } private static boolean m2(boolean value) { boolean result = !value; return result; } Compiled and looked at baytkod:
private static boolean m1(boolean); 0: iload_0 1: ifeq 9 4: iconst_0 5: istore_1 6: goto 11 9: iconst_1 10: istore_1 11: iload_1 12: ireturn private static boolean m2(boolean); 0: iload_0 1: ifne 4: iconst_1 5: goto 9 8: iconst_0 9: istore_1 10: iload_1 11: ireturn It’s not necessary to understand everything, it’s worth noting that both methods produced almost the same number of instructions, and they are almost identical, except for one instruction: in the m1() method there is ifeq in m2() ifen is a test for equality and a test for inequality.
It can be concluded that they are identical, but a record of the form:
boolean result = !value looks more concise.
C ++ is optimized in the same way :
bool f(bool var1) { bool var2 = !var1; return var2; } bool g(bool var1) { bool var2; if (var1) var2 = false; else var2 = true; return var2; } turn into the same thing:
f(bool): mov eax, edi xor eax, 1 ret g(bool): mov eax, edi xor eax, 1 ret Update Yes, it is indeed C ++, I repent. Well, let's take VC ++ 2015. In C ++ mode, the code is the same with optimization:
g: cmp BYTE PTR _var1$[esp-4], 0 sete al f: cmp BYTE PTR _var1$[esp-4], 0 sete al Without optimization, everything is scary;)
g: push ebp mov ebp, esp push ecx movzx eax, BYTE PTR _var1$[ebp] test eax, eax je SHORT $LN2@g mov BYTE PTR _var2$[ebp], 0 jmp SHORT $LN3@g $LN2@g: mov BYTE PTR _var2$[ebp], 1 $LN3@g: mov al, BYTE PTR _var2$[ebp] mov esp, ebp pop ebp ret 0 f: push ebp mov ebp, esp sub esp, 8 movzx eax, BYTE PTR _var1$[ebp] test eax, eax jne SHORT $LN3@f mov DWORD PTR tv66[ebp], 1 jmp SHORT $LN4@f $LN3@f: mov DWORD PTR tv66[ebp], 0 $LN4@f: mov cl, BYTE PTR tv66[ebp] mov BYTE PTR _var2$[ebp], cl mov al, BYTE PTR _var2$[ebp] mov esp, ebp pop ebp ret 0 Those. long, but almost the same.
For C code slightly corrected:
#define bool _Bool bool f(bool var1) { bool var2 = !var1; return var2; } bool g(bool var1) { bool var2; if (var1) var2 = 0; else var2 = 1; return var2; } We get with optimization exactly the same as for C ++ :
_g PROC ; COMDAT cmp BYTE PTR _var1$[esp-4], 0 sete al ret 0 _g ENDP _f PROC ; COMDAT cmp BYTE PTR _var1$[esp-4], 0 sete al ret 0 _f ENDP And without optimization:
_g PROC push ebp mov ebp, esp push ecx movzx eax, BYTE PTR _var1$[ebp] test eax, eax je SHORT $LN2@g mov BYTE PTR _var2$[ebp], 0 jmp SHORT $LN3@g $LN2@g: mov BYTE PTR _var2$[ebp], 1 $LN3@g: mov al, BYTE PTR _var2$[ebp] mov esp, ebp pop ebp ret 0 _g ENDP _f PROC push ebp mov ebp, esp sub esp, 8 movzx eax, BYTE PTR _var1$[ebp] test eax, eax jne SHORT $LN3@f mov DWORD PTR tv66[ebp], 1 jmp SHORT $LN4@f $LN3@f: mov DWORD PTR tv66[ebp], 0 $LN4@f: mov cl, BYTE PTR tv66[ebp] mov BYTE PTR _var2$[ebp], cl mov al, BYTE PTR _var2$[ebp] mov esp, ebp pop ebp ret 0 _f ENDP Again, there is a difference, but it is very small ..
If you optimize the functions themselves by declaring them as _fastcall , you get the code
test cl, cl sete al (cf. with Open Watcom below).
Open Watcom behaved very funny (for it it was necessary to replace bool with int ):
f_: L$1: test eax,eax sete al movzx eax,al ret g_: jmp L$1 He generally threw a call to g in f ! :)
It did exactly the same thing in C ++ mode (optimization in both cases is by default).
bool near f( bool ): L$1: test al,al sete al ret bool near g( bool ): jmp L$1 With full optimization in C mode, he simply merged both functions:
f_: g_: test eax,eax sete al movzx eax,al ret jmp from g right in f . Already here 200% that the code is the same! :) - Harrypush 'and forgot ... - HarryIn the case of negation, such a set of assembler commands should be created:
Moreover, 1 and 3 - not necessarily. It depends on what goes further and what was before.
When comparing (this is not necessarily the case, here the compiler can optimize and depending on the processor another code can work):
As you can see, the difference is not very big. Conclusion?
a) Prefer clear and beautiful code instead of optimized.
b) First test the application either manually, or based on common sense, or profiler, and then optimize the bottlenecks.
test , then jz , not? - Qwertiy ♦The so-called "optimization" of this code fragment will have absolutely no effect on the performance of your program. But on the readability and understanding of your program can greatly affect.
This code snippet
if (var1) var2 = false; else var2 = true; looks very confusing. It is not immediately obvious that var2 is the negation of var1 .
To make it even more obvious that this code is confusing, imagine that in this place you have to exit the function. Then you have to write.
if (var1) var2 = false; else var2 = true; return var2; This code snippet
var2 = !var1; more clear. It immediately shows that the value of the variable var2 is the negation of the value of the variable var1 . With the additional clause return everything can be written in one line
return !var1; Or if you want the variable var2 to get the value, then
return var2 = !var1; Moreover, for example in C ++ without any additional inclusions, you can even write
return not var1; Or
return var2 = not var1; In C, it suffices to include the <iso646.h> header
Moreover, in the same C ++, you can declare variables in conditions. Therefore, if a variable is used only, for example, in the body of an if statement or in a loop, then you can write
if ( bool var2 = not var1 ) { // using var2 } or
while ( bool var2 = not var1 ) { //... } And even in C, where you cannot declare variables in conditions, it is nevertheless better to write
bool var2; while ( var2 = !var1 ) { // changing of var1 } Source: https://ru.stackoverflow.com/questions/618752/
All Articles