Recent

Author Topic: compilation and arithmetic operations with numbers  (Read 11982 times)

Seenkao

  • Hero Member
  • *****
  • Posts: 546
    • New ZenGL.
compilation and arithmetic operations with numbers
« on: October 14, 2021, 12:32:20 am »
Приветствую!
Я хотел бы знать, что вообще происходит? Это банальное сложение чисел, но компилятор не переводит 30 + 33 в 63. Он делает двойное сложение.
Я уже умалчиваю о том, что компилятор сам не создаёт ссылочный тип для структур данных. Вполне возможно это далеко не так просто и надо достаточное время на обработку данных, для перевода структуры в ссылку.

Но здесь мне приходится банальные вещи вручную писать. Я расписываю эти данные для себя, а не для компилятора. )))

Yandex translate:
Greetings!
I would like to know what is going on at all? This is a banal addition of numbers, but the compiler does not translate 30 + 33 into 63. He does double addition.
I am already silent about the fact that the compiler itself does not create a reference type for data structures. It is quite possible that this is not so simple and it takes enough time to process the data to translate the structure into a link.

But here I have to write banal things manually. I'm writing this data for myself, not for the compiler.)))

FPC 3.2.1, Linux-Debian 10
-al
Code: Pascal  [Select][+][-]
  1.   useEl^.rh2 := ry1 + 30 + 33;
  2. // assembler
  3. //      movaps  %xmm1,%xmm2
  4. //      movq    _$DRAWALL$_Ld1@GOTPCREL(%rip),%rdx
  5. //      addss   (%rdx),%xmm2
  6. //      movq    _$DRAWALL$_Ld48@GOTPCREL(%rip),%rdx
  7. //      addss   (%rdx),%xmm2
  8. //      movss   %xmm2,28(%rax)
  9. .Ll56:
  10.   useEl^.tx21 := rx1 + 5;
  11. // assembler
  12. //      movaps  %xmm0,%xmm2
  13. //      movq    _$DRAWALL$_Ld16@GOTPCREL(%rip),%rdx
  14. //      addss   (%rdx),%xmm2
  15. //      movss   %xmm2,56(%rax)

changing the code (there's a lot of data further on, so it makes sense).
Code: Pascal  [Select][+][-]
  1.   n30_7 := 30 - 7;
  2. // assembler
  3. //      movq    _$DRAWALL$_Ld45@GOTPCREL(%rip),%rdx
  4. //      movss   (%rdx),%xmm3
  5.   useEl^.ty11 := ry1 + n30_7;
  6. // assembler
  7. //      movaps  %xmm1,%xmm2
  8. //      addss   %xmm3,%xmm2
  9. //      movss   %xmm2,44(%rax)
Получается, что я даже в таком случае в выгоде, сокращая код на одну команду, а если данных немного больше, то автоматически мы выигрываем чуть ли не в два раза (как минимум приближаемся к этому). Я не считаю, что это мало!
Может я что-то упустил?

Yandex translate:
It turns out that even in this case I benefit by reducing the code by one command, and if there is a little more data, then automatically we win almost twice (at least we are approaching this). I think that's a "lot"!
Maybe I missed something?
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

avk

  • Hero Member
  • *****
  • Posts: 752
Re: compilation and arithmetic operations with numbers
« Reply #1 on: October 14, 2021, 10:06:12 am »
...
I would like to know what is going on at all? This is a banal addition of numbers, but the compiler does not translate 30 + 33 into 63. He does double addition.
...

Just curious if something changes if the code changes a bit?
Code: Pascal  [Select][+][-]
  1.   useEl^.rh2 := ry1 + single(30 + 33);
  2.  

Seenkao

  • Hero Member
  • *****
  • Posts: 546
    • New ZenGL.
Re: compilation and arithmetic operations with numbers
« Reply #2 on: October 14, 2021, 01:20:57 pm »
Да, компилятор объединил числа. Но подобное решение - это дополнительная нагрузка на разработчика. )))

Yandex translate:
Yes, the compiler combined the numbers. But such a solution is an additional burden on the developer.)))
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: compilation and arithmetic operations with numbers
« Reply #3 on: October 14, 2021, 01:26:36 pm »
...

Just curious if something changes if the code changes a bit?
Code: Pascal  [Select][+][-]
  1.   useEl^.rh2 := ry1 + single(30 + 33);
  2.  
Then maybe it is worth trying also:
Code: Pascal  [Select][+][-]
  1.   useEl^.rh2 := 30 + 33 + ry1;
  2.   useEl^.rh2 := ry1 + (30 + 33);

"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Seenkao

  • Hero Member
  • *****
  • Posts: 546
    • New ZenGL.
Re: compilation and arithmetic operations with numbers
« Reply #4 on: October 14, 2021, 01:52:10 pm »
Then maybe it is worth trying also:
Code: Pascal  [Select][+][-]
  1.   useEl^.rh2 := 30 + 33 + ry1;
  2.   useEl^.rh2 := ry1 + (30 + 33);
Это сработало! Компилятор не разбирает, что в выражении присутствуют числа и не анализирует код вообще? Работает компилятор с SIMD и тут такой код:

Yandex translate:
It worked! The compiler does not understand that there are numbers in the expression and does not analyze the code at all? The compiler works with SIMD and here is the following code:
Code: Pascal  [Select][+][-]
  1.   useEl^.rh2 := 33 + 30 + ry1;
  2. // assembler
  3. //      movq    _$DRAWALL$_Ld51@GOTPCREL(%rip),%rdx   <<<< why not immediately XMM?
  4. //      movss   (%rdx),%xmm2
  5. //      addss   %xmm1,%xmm2
  6. //      movss   %xmm2,28(%rax)

Проверил дальше. Если число стоит впереди всей цепочки выражения, то это число не отправится сразу в регистр XMM. Почему? Ведь вся цепочка будет вычисляться с помощью XMM регистров. Почему компилятор не производит проверку полного выражения до его компиляции?

Yandex translate:
I checked further. If the number is ahead of the entire expression chain, then this number will not be sent immediately to the XMM register. Why? After all, the entire chain will be calculated using XMM registers. Why doesn't the compiler check the full expression before compiling it?
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: compilation and arithmetic operations with numbers
« Reply #5 on: October 14, 2021, 02:15:25 pm »
Nothing to wonder, because + operator is with left-to-right associativity. It depends whether the two int constants (30, 33) will be at the same node in the parser tree. In your example:
Code: [Select]
useEl^.rh2 := ry1 + 30 + 33; // := ((ry1 + 30) + 33)they'll be not.

Besides, It's bad thing to rearrange FP arithmetic, will yield a different result.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Seenkao

  • Hero Member
  • *****
  • Posts: 546
    • New ZenGL.
Re: compilation and arithmetic operations with numbers
« Reply #6 on: October 14, 2021, 02:50:21 pm »
Это в принципе можно так не рассматривать. И это не правильное поведение!
Правильное поведение: если результат тип Single, а выражение тип Integer и тип Single, то мы переводим все значения в тип Single (по значению результата) и пересчитываем.

Другое правильное поведение, когда в выражении все размерности одного типа (допустим Integer). Тогда мы вычисляем значение и переводим в значение типа Single.

Мы не должны смешивать типы в выражениях - это приводит к накладным расходам. Поэтому все значения должны быть сразу приведены к одному типу.

Yandex translate:
In principle, this can not be considered that way. And this is not the right behavior!
Correct behavior: if the result is type Single, and the expression is type Integer and type Single, then we convert all values to type Single (by the value of the result) and recalculate.

Another correct behavior is when all dimensions of the same type are in the expression (let's say Integer). Then we calculate the value and translate it into a Single type value.

We should not mix types in expressions - this leads to overhead. Therefore, all values should be immediately converted to the same type.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: compilation and arithmetic operations with numbers
« Reply #7 on: October 14, 2021, 03:11:14 pm »
*snip*
In principle, this can not be considered that way. And this is not the right behavior!
Correct behavior: if the result is type Single, and the expression is type Integer and type Single, then we convert all values to type Single (by the value of the result) and recalculate.

Another correct behavior is when all dimensions of the same type are in the expression (let's say Integer). Then we calculate the value and translate it into a Single type value.

We should not mix types in expressions - this leads to overhead. Therefore, all values should be immediately converted to the same type.
I'm just explaining why, I had not assessed it as neither right or wrong.
BTW, I am just OK with how it works, and it is on the safe side.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: compilation and arithmetic operations with numbers
« Reply #8 on: October 15, 2021, 05:08:47 pm »
In principle, this can not be considered that way. And this is not the right behavior!
Correct behavior: if the result is type Single, and the expression is type Integer and type Single, then we convert all values to type Single (by the value of the result) and recalculate.

Pascal does not consider the result type when determining the result type of an expression. Also as y.ivanov wrote, expressions are evaluated left-to-right and its completely legitimate for the compiler not to optimize this.

That said: the compiler does store the 30 and the 33 as Single values, cause if you look at the location of e.g. _$DRAWALL$_Ld51 in your assembly output you'll see something like this (this is from my own test that's similar to your code cause you didn't provide a full example):

Code: [Select]
.section .rodata.n__$TTEST$_Ld1,"a"
.balign 4
.globl _$TTEST$_Ld1
_$TTEST$_Ld1:
# value: 0d+3.000000000E+01
.byte 0,0,240,65

.section .rodata.n__$TTEST$_Ld2,"a"
.balign 4
.globl _$TTEST$_Ld2
_$TTEST$_Ld2:
# value: 0d+3.300000000E+01
.byte 0,0,4,66

Seenkao

  • Hero Member
  • *****
  • Posts: 546
    • New ZenGL.
Re: compilation and arithmetic operations with numbers
« Reply #9 on: October 15, 2021, 07:12:51 pm »
Pascal does not consider the result type when determining the result type of an expression. Also as y.ivanov wrote, expressions are evaluated left-to-right and its completely legitimate for the compiler not to optimize this.
Лично моё мнение - это не правильно. Но возможно ни кто и не занимался данным вопросом. Если это интересно для развития FPC, то я могу заняться созданием анализатора кода и оптимизацией кода паскаля (не ассемблерного, а именно паскаля). Протестируете, посмотрите как работает и есть ли от него смысл.

Я ни в коем случае не говорю, что FPC не оптимизирован. Я даже могу сказать, что достаточная часть компилятора обрабатывает код лучше меня.
Но я зачастую вижу что происходит в конечном коде и понимаю, где можно сделать код быстрее и (или) меньше. Я ставлю подсказки компилятору и компилятор успешно пользуется этими подсказками.
Но это ручная работа!!! А это не очень хорошо.
Я всё равно занимаюсь своими разработками и попутно могу заниматься анализом кода. По полученным данным составлю анализатор кода. Впоследствии такого анализа код на паскале вероятнее всего вырастет, но конечный компилируемый код с большой вероятностью уменьшится и будет работать быстрее.

Интересно вам моё предложение?

Yandex translate:
Personally, my opinion is wrong. But perhaps no one has dealt with this issue. If this is interesting for the development of FPC, then I can create a code analyzer and optimize Pascal's code (not assembler, namely pascal). Test it, see how it works and whether it makes sense.

I am by no means saying that FPC is not optimized. I can even say that a sufficient part of the compiler handles the code better than me.
But I often see what happens in the final code and understand where it is possible to make the code faster and (or) smaller. I put hints to the compiler and the compiler successfully uses these hints.
But it's handmade!!! And this is not very good.
I'm still doing my own development and I can do code analysis along the way. Based on the received data, I will compile a code analyzer. After such an analysis, the pascal code is likely to grow, but the final compiled code is likely to decrease and run faster.

Are you interested in my offer?
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: compilation and arithmetic operations with numbers
« Reply #10 on: October 16, 2021, 10:55:46 am »
Interestingly, Delphi considers constants as a Double type, but sums constants at compile time, no matter in what order it go.
From Delphi 10.4 disassembler:
Code: ASM  [Select][+][-]
  1. Project1.dpr.10: R.rh2 := 30 + 33 + D + 28;
  2. 000000000040D51F F3480F5A0580280000 cvtss2sd xmm0,qword ptr [rel $00002880]
  3. 000000000040D528 F20F580528000000 addsd xmm0,qword ptr [rel $00000028]
  4. 000000000040D530 F2480F5AC0       cvtsd2ss xmm0,xmm0
  5. 000000000040D535 F30F1105A38C0000 movss dword ptr [rel $00008ca3],xmm0

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: compilation and arithmetic operations with numbers
« Reply #11 on: October 16, 2021, 04:10:42 pm »
I'd repeat myself from the reply #5
*snip*

Besides, It's bad thing to rearrange FP arithmetic, will yield a different result.

Consider:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$mmx on}
  3.  
  4. uses
  5.   Math;
  6.  
  7. var
  8.   x, y, z, r1, r2: Float;
  9.  
  10. begin
  11.   x := Power(10, 30); // 10^30
  12.   y := -Power(10, 30); // -(10^30)
  13.   z := 1;
  14.   r1 := (x + y) + z;
  15.   r2 := x + (y + z);
  16.   WriteLn(r1, ' ', r2); // 1 0
  17.   ReadLn;
  18. end.      


One should be utterly careful about the order of floating point operations.

What Every Computer Scientist Should Know About Floating-Point Arithmetic

"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Seenkao

  • Hero Member
  • *****
  • Posts: 546
    • New ZenGL.
Re: compilation and arithmetic operations with numbers
« Reply #12 on: October 17, 2021, 08:42:55 pm »
ASerge, это как раз более-менее правильное поведение. Я не могу сказать точно, потому что не разобрался пока с SIMD. Типы выражения приводятся к одному типу и вычисляются.
Вопрос, это весь код? Если да, то значит Delphi преобразовал все числа в единое число.
FPC также может неплохо справляться с оптимизацией, если мы укажем для него определенные точки, и он будет их использовать.

Yandex translate:
Serge, this is just more or less correct behavior. I can't say for sure, because I haven't figured out SIMD yet. Expression types are reduced to the same type and evaluated.
The question is, is this the whole code? If yes, then Delphi has converted all the numbers into a single number.
FPC can also do a good job with optimization if we specify certain points for it, and it will use them.

y.ivanov, это знать желательно при разработке, но я вёду речь не об этом.  :)
Yandex translate:
y.ivanov, it is desirable to know this when developing, but that's not what I'm talking about. :)
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

Paolo

  • Sr. Member
  • ****
  • Posts: 499
Re: compilation and arithmetic operations with numbers
« Reply #13 on: October 18, 2021, 12:06:42 am »
Code: Pascal  [Select][+][-]
  1. Besides, It's bad thing to rearrange FP arithmetic, will yield a different result.
  2.  
+1

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: compilation and arithmetic operations with numbers
« Reply #14 on: October 18, 2021, 01:42:28 am »
*snip*
y.ivanov, это знать желательно при разработке, но я вёду речь не об этом.  :)
Yandex translate:
y.ivanov, it is desirable to know this when developing, but that's not what I'm talking about. :)
Have you tried my snippet from reply #11? It is actually an example from the link.

The point is that the floating point arithmetic doesn't obey to the associative laws of algebra. Neither the distributive.

By my understanding, what you're talking about is to pre-calculate at compile time with what is known by the compiler. But that is wrong because:
Code: Pascal  [Select][+][-]
  1.   r0 := x + y + z;
  2.   r1 := (x + y) + z;
  3.   r2 := x + (y + z);
  • If x,y are constants and z is variable, r0 will be calculated in same way as r1, i.e. x+y will be pre-calculated as xy by compiler and then, xy+z will be calculated at run-time, which is OK.
  • if x is variable and y,z are constants, r0 will be calculated in same way as r2, i.e. y+z will be pre-calculated as yz by compiler and then, x+yz will be calculated at run-time, which is not OK, because it is shown that exists a case when r1≠r2 for the same values for (x,y,z). 

"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

 

TinyPortal © 2005-2018