short als Übergabeparamter gleich schnell wie int?



  • Hallo,
    man liest da des öfteren, dass Typen, die die Registerbreite exakt ausnutzen schneller sind als andere.
    Wenn ich jetzt aber z.B. eine Funktion

    void foo(short x, short y)
    

    habe, wird dann von modernen Compilern (MSVC, GCC) das ganze zu einem 32-Bit Typ optimiert, oder werden dann zwei mal 16-Bit durch die Register gejagt?



  • Wir haben hier gerade einen sehr ähnlichen Thread.

    Ich denke, deine Frage ist schwierig allgemein zu beantworten, zumal solche Dinge auch von Compilereinstellungen und Optimierungen (und erst recht vom Compiler selbst) abhängen. Aber der erzeugte Assemblercode könnte Licht ins Dunkel bringen.


  • Mod

    Pikkolini schrieb:

    habe, wird dann von modernen Compilern (MSVC, GCC) das ganze zu einem 32-Bit Typ optimiert, oder werden dann zwei mal 16-Bit durch die Register gejagt?

    Da hilft wohl nur ausprobieren und im Maschinencode gucken. Sofern du aber auf Geschwindigkeit optimierst, würde ich jedoch auf zwei Maschinenworte tippen. Schließlich würde das Verpacken von zwei Shorts in einen einzelnen, größeren Typ eine nicht trivial Rechenoperation sein für die die Werte ohnehin in den Prozessor geladen werden müssten.



  • Das sagt die Disassembly bei vollständiger Optimierung:

    #include <iostream>
    
    void foo(int x, int y) {
    	std::cout << x << y << std::endl;
    }
    
    void foo(short x, short y) {
    	std::cout << x << y << std::endl;
    }
    
    int main()
    {
    	foo(10,10);
    013E1000  mov         eax,dword ptr [__imp_std::endl (13E2050h)]  
    013E1005  mov         ecx,dword ptr [__imp_std::cout (13E204Ch)]  
    013E100B  push        eax  
    013E100C  push        0Ah  
    013E100E  push        0Ah  
    013E1010  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13E2048h)]  
    013E1016  mov         ecx,eax  
    013E1018  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13E2048h)]  
    013E101E  mov         ecx,eax  
    013E1020  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13E2044h)]  
    	foo(10,10);
    013E1026  mov         ecx,dword ptr [__imp_std::endl (13E2050h)]  
    013E102C  push        ecx  
    013E102D  mov         ecx,dword ptr [__imp_std::cout (13E204Ch)]  
    013E1033  push        0Ah  
    013E1035  push        0Ah  
    013E1037  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13E2048h)]  
    013E103D  mov         ecx,eax  
    013E103F  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13E2048h)]  
    013E1045  mov         ecx,eax  
    013E1047  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13E2044h)]  
    	return 0;
    013E104D  xor         eax,eax  
    }
    013E104F  ret
    

    Ich bin jetzt nicht sonderlich Assemblerversiert, aber es sieht so aus, als wäre die Version mit int schneller.



  • mit welchem Program schaut man sich sowas (unter linux) an?


  • Mod

    padreigh schrieb:

    mit welchem Program schaut man sich sowas (unter linux) an?

    less 😃
    Das ist einfach die Ausgabe wenn du den Compiler mit der -S Option aufrufst.

    Mach dich auch mit den anderen Zwischenschritten vertraut:
    -E: Nur Präprozessor aufrufen, nicht compilieren
    -S: Nur Präprozessor und Compiler aufrufen, nicht Assemblieren
    -c: Nur Präprozessor, Compiler und Assembler aufrufen, nicht linken

    Das alles natürlich nur für GNU Compiler, aber bei anderen Compilern heißen die Optionen meistens genauso. Will ich aber nicht für alle Compiler beschwören.



  • @Pikkolini: Du erstellt zwei gleichnamige Funktionen um einen Unterschied zwischen beiden zu erkennen? Wie wäre es mit foo1 und foo2?



  • @Pikkolini:
    Genau Registerbreite oder kleiner als Registerbreite spielt in den meisten Fällen keinen Walzer. Unterschiede können bestehen, sind aber eher zu vernachlässigen.
    Wichtig ist halt: nicht GRÖSSER als die Registerbreite. Also 64 bittiges Gedöns mit 32 bittigem Instruction-Set, das tut weh. Merkbar.



  • short sollte 8 Bit sein, also wäre

    push 0Ah
    pop al
    

    eigentlich angebracht, aber das wird wohl gar nicht mehr von irgendwelchen compilern unterstützt/umgesetzt. 😞



  • GCC unter x86-64 behandelt short-Werte bei der Übergabe als 32-Bit-Parameter, sprich die höheren 16 Bits werden bei Bedarf durch sign extend ausgelöscht.
    Trotzdem werden keine zwei shorts in das gleiche 64-Bit-Register gepackt. Das wäre kontraproduktiv und verbietet sich schon wegen der calling convention.
    short-Arithmetik findet dementsprechend hauptsächlich auch auf 32-Bit-Ebene statt, es sei denn, es müssen Werte aus dem RAM gelesen werden.
    Ob man short oder int verwendet, ist im Hinblick auf Performanz daher i.d.R. egal, der Compiler macht zum Glück sowieso, was er will.



  • @Pikkolini

    Übersehe ich gerade etwas, oder rufst du einfach zweimal die gleiche Funktion auf?



  • @EinEtwasAndererGast:

    Sehe ich auch so.
    Ich hab's mal explizit gemacht. Bei mir (VS2005) ist auch keinerlei Unterschied:

    void fooint(int x, int y) {
        std::cout << x << y /*<< std::endl*/;
    }
    
    void fooshort(short x, short y) {
        std::cout << x << y /*<< std::endl*/;
    }
    
    int main()
    {
        fooint(10,10); 
    00401000  mov         ecx,dword ptr [__imp_std::cout (402040h)] 
    00401006  push        0Ah  
    00401008  push        0Ah  
    0040100A  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] 
    00401010  mov         ecx,eax 
    00401012  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402038h)] 
    	fooshort(10,10);
    00401018  mov         ecx,dword ptr [__imp_std::cout (402040h)] 
    0040101E  push        0Ah  
    00401020  push        0Ah  
    00401022  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40203Ch)] 
    00401028  mov         ecx,eax 
    0040102A  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40203Ch)] 
    
    	return 0;
    00401030  xor         eax,eax 
    }
    00401032  ret
    

Anmelden zum Antworten