Skip to content

Commit

Permalink
De Morgan's laws
Browse files Browse the repository at this point in the history
  • Loading branch information
yurichev committed Nov 5, 2019
1 parent e00fd40 commit c195be0
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 1 deletion.
3 changes: 2 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(This file is poorly maintained, since there is no reason to keep it at all...)

Nov-2019: Many blog posts from yurichev.com/blog has been copypasted into the book
Jan-2019: There was a time when \IT macro was used for italic text and \ITA for Italian text.
To be consistent, I'm using \emph for italic text now and \IT for Italian text.
True for filename suffixes as well.
Expand All @@ -17,7 +18,7 @@
20-Jul-2016: The book is now licensed under CC BY-SA 4.0 (like Wikipedia)
instead of CC NC-ND 3.0.
16-Jul-2016: Blog posts about C/C++ pointers has been copypasted into the book
14-Jul-2016: No more LITE version, which was somewhat unpopular
14-Jul-2016: No more LITE version, which was somewhat unwanted
04-Nov-2015: All exercises has been moved to http://challenges.re
21-Mar-2015: toupper() function example
18-Mar-2015: Lite (introductory) version
Expand Down
109 changes: 109 additions & 0 deletions other/DeMorgan_EN.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
\subsection{De Morgan's laws and decompilation}

Sometimes a compiler's optimizer can use De Morgan's laws to make code shorter/faster.

For example, this:

\begin{lstlisting}[style=customc]
void f(int a, int b, int c, int d)
{
if (a>0 && b>0)
printf ("both a and b are positive\n");
else if (c>0 && d>0)
printf ("both c and d are positive\n");
else
printf ("something else\n");
};
\end{lstlisting}

... looks pretty innocent, when compiled by optimizing GCC 5.4.0 x64:

\begin{lstlisting}[style=customasmx86]
; \verb|int __fastcall f(int a, int b, int c, int d)|
public f
f proc near
test edi, edi
jle short loc_8
test esi, esi
jg short loc_30

loc_8:
test edx, edx
jle short loc_20
test ecx, ecx
jle short loc_20
mov edi, offset s ; "both c and d are positive"
jmp puts

loc_20:
mov edi, offset aSomethingElse ; "something else"
jmp puts

loc_30:
mov edi, offset aAAndBPositive ; "both a and b are positive"

loc_35:
jmp puts
f endp
\end{lstlisting}

... also looks innocent, but Hex-Rays 2.2.0 cannot clearly see that both AND operations were actually used in the source code:

\begin{lstlisting}[style=customc]
int __fastcall f(int a, int b, int c, int d)
{
int result;

if ( a > 0 && b > 0 )
{
result = puts("both a and b are positive");
}
else if ( c <= 0 || d <= 0 )
{
result = puts("something else");
}
else
{
result = puts("both c and d are positive");
}
return result;
}
\end{lstlisting}

The \verb|c <= 0 || d <= 0| expression is inversion of \verb|c>0 && d>0| since
$\overline{A \cup B} = \overline{A} \cap \overline{B}$ and
$\overline{A \cap B} = \overline{A} \cup \overline{B}$,
in other words,
\verb~!(cond1 || cond2) == !cond1 && !cond2~ and \verb~!(cond1 && cond2) == !cond1 || !cond2~.

These rules are worth to be kept in mind, since this compiler optimization is used heavily almost everywhere.

Sometimes it's good idea to invert a condition, in order to understand a code better.
This is a piece of a real code decompiled by Hex-Rays:

\begin{lstlisting}[style=customc]
for (int i=0; i<12; i++)
{
if (v1[i-12] != 0.0 || v1[i] != 0.0)
{
v108=min(v108, (float)v0[i*24 -2]);
v113=max(v113, (float)v0[i*24]);
};
}
\end{lstlisting}

... it can be rewritten like:

\begin{lstlisting}[style=customc]
for (int i=0; i<12; i++)
{
if (v1[i-12] == 0.0 && v1[i] == 0.0)
continue;

v108=min(v108, (float)v0[i*24 -2]);
v113=max(v113, (float)v0[i*24]);
}
\end{lstlisting}

Which is better? I don't know yet, but for better understanding, it's great to take a look on both.

2 changes: 2 additions & 0 deletions other/hexrays_EN.tex
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ \subsection{Long and messed expressions}
Mathematica has added two new variables: \TT{Compile`\$1} and \TT{Compile`\$2}, values of which are to be used several times in expression.
So we can add two additional variables.

\input{other/DeMorgan_EN}

\subsection{My plan}

\begin{itemize}
Expand Down
2 changes: 2 additions & 0 deletions other/hexrays_FR.tex
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ \subsection{Expressions longues et confuses}
qui vont être ré-utilisées plusieurs fois dans l'expression.
Donc, nous pouvons ajouter deux variables supplémentaires.

%\input{other/DeMorgan_FR}

\subsection{Mon plan}

\begin{itemize}
Expand Down
2 changes: 2 additions & 0 deletions other/hexrays_RU.tex
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ \subsection{Длинные и запутанные выражения}
в выражении несколько раз.
Так что мы можем добавить две дополнительных переменных.

%\input{other/DeMorgan_RU}

\subsection{Мой план}

\begin{itemize}
Expand Down

0 comments on commit c195be0

Please sign in to comment.