Wird der Compiler das optimieren?



  • ohahhubu schrieb:

    Du berechnest sin und cos, aber machst dir um die 2 [] sorgen. 🙄

    Ich mache mir keine Sorgen, es interessiert mich einfach. Und die cos/sin kann ich nicht vermeiden, die Array Indizierungen vielleicht schon...



  • Ich glaube er wird es nicht optimieren, da er wohl nicht annehmen kann, dass der Wert an der Adresse beim zweiten Aufruf noch der selbe ist (wenn ich richtig verstanden habe was du meinst). Schau dir doch einfach den Code an, den der Compiler generiert.



  • brotbernd schrieb:

    Ich glaube er wird es nicht optimieren, da er wohl nicht annehmen kann, dass der Wert an der Adresse beim zweiten Aufruf noch der selbe ist (wenn ich richtig verstanden habe was du meinst). Schau dir doch einfach den Code an, den der Compiler generiert.

    Dazu müsste ich Assembler können..



  • Doppelte Derefernzierung sollten im Optimizer behandelt werden - aber ohne Gewähr!

    Wenn du es wissen willst anstelle vom glauben musst du wohl bisschen Assembler lernen 😮


  • Mod

    Ich denke nicht, dass dieser Zugriff gut optimiert werden kann, es sei denn es ist aus dem Zusammenhang klar, dass Zugriffe auf cPoint weder p noch etwas in p verändern können. Eventuell kann man da aber mit den strict-aliasing Schaltern, die fast alle Compiler kennen, etwas machen.



  • Der Compiler wird schon checken dass "p" Alias-frei ist. Wird bloss leider nicht viel bringen, da ja abhängig von i ein anderer Wert referenziert wird, ist ja nicht immer -halfWidth für p[i][0].

    Ginge höchstens wenn der Compiler sich entschliessen würde die Schleife aufzurollen, und das ist schwer einzuschätzen.

    Dazu müsste ich Assembler können..

    Na das solltest du wenn du auf der Ebene optimieren willst. Ist ja auch kein Ding, du musst ja bloss die wichtigsten paar Befehle kennen. So gut dass du in Assembler entwickeln könntest muss es lange nicht sein.

    Wirklich Code für die "doppelte Dereferenzierung" sollte ein Compiler allerdings nicht erzeugen müssen. Der 2. Index ist jeweils Konstant, d.h. die Adresse der zu verwendenden Konstante ist Basis + i * 16 + K . Die Konstante K kann man in die Basis mit einrechnen, und "plus Register*16" ist eine Sache die wohl die meisten CPUs können werden. D.h. der Compiler wird maximal ein oder zwei Befehle generieren, je nachdem ob die CPU "komplexe" Adressierungsarten direkt unterstützt oder noch ein LEA (load effective address) notwendig ist.



  • Warum nicht einfach per Hand unrollen?

    double sin_a = std::sin(a);
    double cos_a = std::cos(a);
    
    double konstante_1 = halfWidth * sin_a;
    double konstante_2 = -konstante_1;
    double konstante_3 = halfWidth * cos_a;
    double konstante_4 = -konstante_3;
    double konstante_5 = halfLength * sin_a;
    double konstante_6 = -konstante_5;
    double konstante_7 = halflength * cos_a;
    double konstante_8 = -konstante_8;
    
    cPoints[0][0] = konstante_4 + konstante_6;
    cPoints[0][1] = konstante_2 + konstante_7;
    cPoints[1][0] = konstante_3 + konstante_6;
    cPoints[1][1] = konstante_1 + konstante_7;
    cPoints[2][0] = konstante_3 + konstante_5;
    cPoints[2][1] = konstante_1 + konstante_8;
    cPoints[3][0] = konstante_4 + konstante_5;
    cPoints[3][1] = konstante_2 + konstante_8;
    


  • asdfasd schrieb:

    Warum nicht einfach per Hand unrollen?

    double sin_a = std::sin(a);
    double cos_a = std::cos(a);
    
    double konstante_1 = halfWidth * sin_a;
    double konstante_2 = -konstante_1;
    double konstante_3 = halfWidth * cos_a;
    double konstante_4 = -konstante_3;
    double konstante_5 = halfLength * sin_a;
    double konstante_6 = -konstante_5;
    double konstante_7 = halflength * cos_a;
    double konstante_8 = -konstante_8;
    
    cPoints[0][0] = konstante_4 + konstante_6;
    cPoints[0][1] = konstante_2 + konstante_7;
    cPoints[1][0] = konstante_3 + konstante_6;
    cPoints[1][1] = konstante_1 + konstante_7;
    cPoints[2][0] = konstante_3 + konstante_5;
    cPoints[2][1] = konstante_1 + konstante_8;
    cPoints[3][0] = konstante_4 + konstante_5;
    cPoints[3][1] = konstante_2 + konstante_8;
    

    Und jetzt versuch mal den Zeitunterschied zu messen.



  • double konstante_8 = -konstante_8;
    

    Das kann doch nicht gutgehen...



  • Warum?



  • Walli schrieb:

    Warum?

    Weil in der Variable danach Müll steht?



  • Ja, hab eben in meiner Betriebsblindheit übersehen, dass initialisiert wird. "a = -a" ist ja in Ordnung, nur halt bei der Initialisierung nicht, weil nix vernünftiges drin stehen kann. Aber eigentlich ist ja auch "double konstante_8 = -konstante_7;" gemeint.



  • g++ produziert folgenden Code bei konstantem a:

    //vom Compiler vorberechnete +-sin/cos(a)-Werte:
    	movsd	.LC1(%rip), %xmm11
    	movsd	.LC2(%rip), %xmm0
    	movsd	.LC3(%rip), %xmm10
    	movsd	.LC4(%rip), %xmm9
    	//xmm2=halfWidth und xmm3=halfLength
    	movsd	40(%rsp), %xmm2
    	movsd	32(%rsp), %xmm3
    	movapd	%xmm2, %xmm4
    	movapd	%xmm3, %xmm7
    	xorpd	%xmm11, %xmm4
    	xorpd	%xmm11, %xmm7
    	movapd	%xmm3, %xmm12
    	movapd	%xmm2, %xmm8
    	movapd	%xmm4, %xmm6
    	mulsd	%xmm10, %xmm12
    	mulsd	%xmm0, %xmm6
    	movapd	%xmm7, %xmm5
    	mulsd	%xmm9, %xmm4
    	mulsd	%xmm0, %xmm3
    	mulsd	%xmm0, %xmm8
    	mulsd	%xmm9, %xmm2
    	movapd	%xmm6, %xmm13
    	addsd	%xmm12, %xmm13
    	mulsd	%xmm10, %xmm5
    	movapd	%xmm4, %xmm15
    	mulsd	%xmm0, %xmm7
    	addsd	%xmm3, %xmm15
    	addsd	%xmm8, %xmm12
    	addsd	%xmm2, %xmm3
    	addsd	%xmm5, %xmm8
    	addsd	%xmm7, %xmm2
    	addsd	%xmm6, %xmm5
    	addsd	%xmm4, %xmm7
    

    Wenn a nicht zur Kompilierzeit bekannt ist, kommt ein call sincos gegen Anfang hinzu.
    Wie man sieht, bleibt hier von "doppelter Dereferenzierung" nicht viel übrig und es gibt auch keine Schleife mehr.
    Die Moral von der Geschicht' ist (wie immer), dass man Mikrooptimierungen meist besser dem Compiler überlässt.


Anmelden zum Antworten