рдЗрдВрдЯреЗрд▓ рдкреНрд░реЛрд╕реЗрд╕рд░ рдкрд░ рдирд┐рд░реНрджреЗрд╢ рдПрдордПрдордПрдХреНрд╕, рдПрд╕рдПрд╕рдИ рдФрд░ рдмрд╛рдж рдореЗрдВ рдПрд╡реАрдПрдХреНрд╕ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдХрдИ рд╕рд╛рд▓ рдмреАрдд рдЪреБрдХреЗ рд╣реИрдВред рдПрдХ рд╕рдордп рдореЗрдВ, рд╡реЗ x86 рдЕрд╕реЗрдВрдмрд▓рд░ рдХреА рдкреГрд╖реНрдарднреВрдорд┐ рдХреЗ рдЦрд┐рд▓рд╛рдл рдХрд┐рд╕реА рддрд░рд╣ рдХреЗ рдЬрд╛рджреВ рдХреА рддрд░рд╣ рд▓рдЧ рд░рд╣реЗ рдереЗ, рдЬреЛ рд▓рдВрдмреЗ рд╕рдордп рд╕реЗ рдХреБрдЫ рд╕рд╛рдВрд╕рд╛рд░рд┐рдХ рдерд╛ред рдЙрдиреНрд╣реЛрдВрдиреЗ рдореБрдЭреЗ рдЗрддрдирд╛ рдЭреБрдХрд╛ рджрд┐рдпрд╛ рдХрд┐ рдХреБрдЫ рд╕рд╛рд▓ рдкрд╣рд▓реЗ рдореБрдЭреЗ рдПрдХ рдкреНрд░рд╕рд┐рджреНрдз рдЧреЗрдо рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рд░реЗрдВрдбрд░ рд▓рд┐рдЦрдиреЗ рдХрд╛ рд╡рд┐рдЪрд╛рд░ рдЖрдпрд╛ред рдЬрд┐рд╕ рдЪреАрдЬ рдиреЗ рдЗрди рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рд╡рд╛рджрд╛ рдХрд┐рдпрд╛ рдерд╛ рдЙрд╕рдиреЗ рдореБрдЭрд╕реЗ рдпрд╣ рд╡рд╛рджрд╛ рдХрд┐рдпрд╛ рдерд╛ред рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░, рдореИрдВрдиреЗ рдЗрд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреА рд╕реЛрдЪрд╛ред рд▓реЗрдХрд┐рди рдкрд╛рда рд▓рд┐рдЦрдирд╛ рдХреЛрдб рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реЛ рдЧрдпрд╛ред
рдЙрд╕ рд╕рдордп, рдореИрдВ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░реЛрд╕реЗрд╕рд░ рдкрд░ рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдУрдВ рд╕реЗ рдмрдЪрдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдореИрдВ рдЕрдзрд┐рдХрддрдо рдЙрдкрд▓рдмреНрдз рд░рд╛рд╢рд┐ рдкрд░ рдЕрдкрдиреЗ рд░реЗрдВрдбрд░рд░ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдореЗрд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдкреБрд░рд╛рдиреЗ AMD рдкреНрд░реЛрд╕реЗрд╕рд░ рд╡рд╛рд▓реЗ рджреЛрд╕реНрдд рд╣реИрдВ, рдФрд░ рдЙрдирдХреА рдЫрдд SSE3 рдереАред рдЗрд╕рд▓рд┐рдП, рдЙрд╕ рд╕рдордп рдореИрдВрдиреЗ рдЦреБрдж рдХреЛ рдЕрдзрд┐рдХрддрдо SSE3 рддрдХ рд╕реАрдорд┐рдд рд░рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рддреЛ рдПрдХ рд╡реЗрдХреНрдЯрд░ рдЧрдгрд┐рддреАрдп рдкреБрд╕реНрддрдХрд╛рд▓рдп рдерд╛, рдЬреЛ SSE3 рдХреЗ рдкрд╣рд▓реЗ рдПрдХ рджреБрд░реНрд▓рдн рд╕рдорд╛рд╡реЗрд╢ рдХреЗ рд╕рд╛рде, SSE рдкрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд▓рд╛рдЧреВ рд╣реЛрдиреЗ рд╕реЗ рдереЛрдбрд╝рд╛ рдХрдо рдерд╛ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХреБрдЫ рдмрд┐рдВрджреБ рдкрд░ рдореИрдВрдиреЗ рд╕реЛрдЪрд╛ рдХрд┐ рдореИрдВ рдХрд┐рддрдиреЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рджрд░реНрд╢рди рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ рдЬреЛ рдХрд┐ рдХрдИ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╡реЗрдХреНрдЯрд░ рдЧрдгрд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрд╕реЗрд╕рд░ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдЪреЛрдбрд╝ рд╕рдХрддрд╛ рд╣реИред рдРрд╕рд╛ рд╣реА рдПрдХ рдСрдкрд░реЗрд╢рди 4 рдореИрдЯреНрд░рд┐рд╕реЗрд╕ рдХреЛ 4 рд╕реЗ рдЧреБрдгрд╛ рдХрд░рдирд╛ рд╣реИред

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдореИрдВрдиреЗ рдЗрд╕ рд╡реНрдпрд╡рд╕рд╛рдп рдХреЛ рдордиреЛрд░рдВрдЬрди рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдореИрдВрдиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА SSE рдкрд░ рдЕрдкрдиреЗ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рдкреНрд░рддрд┐рдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдореИрдЯреНрд░рд┐рдХреНрд╕ рдЧреБрдгрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рд╣реИ рдФрд░ рд▓рд┐рдЦрд╛ рд╣реИ рдФрд░ рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд▓рдЧрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдлрд┐рд░ рдореИрдВрдиреЗ рдпрд╣ рджреЗрдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐ рдореИрдВ 2 рдлреНрд▓реЛрдЯ 4x4 рдореИрдЯреНрд░рд┐рд╕ рдХреЛ рдЧреБрдгрд╛ рдХрд░рдиреЗ рд╕реЗ рд╕рд┐рджреНрдзрд╛рдВрдд рдореЗрдВ рдХрд┐рддрдиреЗ рдЙрдкрд╛рдп рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВред рдореЗрд░реЗ рд╡рд░реНрддрдорд╛рди SSE рдкрд░, рдпреЗ 16 рдШрдбрд╝реА рдЪрдХреНрд░ рд╣реИрдВред рд╕рдЪ рд╣реИ,
IACA 3 рдХреЗ рд▓рд┐рдП рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд╕рдВрдХреНрд░рдордг 19 рдХреЛ рджрд┐рдЦрд╛рдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдореИрдВрдиреЗ 0 * рдХреЗ рдмрдЬрд╛рдп рдХреБрдЫ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП 1 * рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд┐рдпрд╛ред рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд╣рд▓реЗ рдпрд╣ рдХреЗрд╡рд▓ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдореЗрдВ рдПрдХ рджреЛрд╖ рдерд╛ред
рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ
рдХреЛрдб рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдкреНрд░рд╕рд┐рджреНрдз
рдЗрдВрдЯреЗрд▓ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЛрдб рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХреЗ рд▓рд┐рдП рдореИрдВ рдПрд╡реАрдПрдХреНрд╕ 2 рдХреЗ рд╕рдорд░реНрдерди рдХреЗ рд╕рд╛рде рдиреНрдпреВрдирддрдо рдХреЗ рд░реВрдк рдореЗрдВ, рд╣реИрд╕рд╡реЗрд▓ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ (рдПрдЪрдПрд╕рдбрдмреНрд▓реНрдпреВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рдХреЛрдб рд▓рд┐рдЦрдирд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ:
рдЗрдВрдЯреЗрд▓ рдЖрдВрддрд░рд┐рдХ рдЧрд╛рдЗрдб рдФрд░
рдЗрдВрдЯреЗрд▓ рдЕрдиреБрдХреВрд▓рди рдореИрдиреБрдЕрд▓ ред
рдЕрд╕реЗрдВрдмрд▓реА рдХреЗ рд▓рд┐рдП рдореИрдВ рдХрдВрд╕реЛрд▓ рд╕реЗ MSVS 2017 рд╕рдореБрджрд╛рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред рдореИрдВ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдЖрдВрддрд░рд┐рдХ рдХреЗ рд╕рд╛рде рдХреЛрдб рд▓рд┐рдЦрддрд╛ рд╣реВрдВред рдЖрдк рдПрдХ рдмрд╛рд░ рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рдФрд░ рдЖрдорддреМрд░ рдкрд░ рдпрд╣ рддреБрд░рдВрдд рд╡рд┐рднрд┐рдиреНрди рдкреНрд▓реЗрдЯрдлрд╛рд░реНрдореЛрдВ рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, x64 VC ++ рдХрдВрдкрд╛рдЗрд▓рд░ рдЗрдирд▓рд╛рдЗрди рдЕрд╕реЗрдВрдмрд▓рд░ рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдпрд╣ x64 рдХреЗ рддрд╣рдд рднреА рдХрд╛рдо рдХрд░реЗред
рдЪреВрдВрдХрд┐ рдпрд╣ рд▓реЗрдЦ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА SIMD рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдореЗрдВ рд╢реБрд░реБрдЖрддреА рд╕реНрддрд░ рд╕реЗ рдкрд░реЗ рд╣реИ, рдореИрдВ рд╕реБрдВрджрд░ рдЪрд┐рддреНрд░реЛрдВ рдХреЗ рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ, рдирд┐рд░реНрджреЗрд╢реЛрдВ, рдбреНрд░рд╛ (рдпрд╛ рджрд╛рдврд╝реА) рдХрд╛ рд╡рд░реНрдгрди рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ рдФрд░ SIMD рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рд╕реАрдЦрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реВрдВрдЧрд╛ред рдЗрдВрдЯреЗрд▓ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдЙрддреНрдХреГрд╖реНрдЯ, рд╕реНрдкрд╖реНрдЯ рдФрд░ рд╡рд┐рд╕реНрддреГрдд рдкреНрд░рд▓реЗрдЦрди рд╕реЗ рднрд░реА рд╣реИред
рдореИрдВ рд╕рдм рдХреБрдЫ рдЖрд╕рд╛рди рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред ... рд▓реЗрдХрд┐рди рдпрд╣ рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣ рдирд┐рдХрд▓рд╛
рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рдХреНрд╖рдг рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рдЬреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдФрд░ рд▓реЗрдЦ рджреЛрдиреЛрдВ рдХреЛ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдХрд░рддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЗрд╕ рдкрд░ рдереЛрдбрд╝рд╛ рдзреНрдпрд╛рди рджреВрдВрдЧрд╛ред рддрддреНрд╡реЛрдВ рдХреА рдорд╛рдирдХ рдкрдВрдХреНрддрд┐ рд▓реЗрдЖрдЙрдЯ рдХреЗ рд╕рд╛рде рдореИрдЯреНрд░рд┐рдХреНрд╕ рдЧреБрдгрд╛ рд▓рд┐рдЦрдирд╛ рдореЗрд░реЗ рд▓рд┐рдП рджрд┐рд▓рдЪрд╕реНрдк рдирд╣реАрдВ рд╣реИред рдЬрд┐рдиреНрд╣реЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереА, рдФрд░ рдЗрд╕рд▓рд┐рдП рдЙрдиреНрд╣реЛрдВрдиреЗ рд╡рд┐рд╢реНрд╡рд╡рд┐рджреНрдпрд╛рд▓рдпреЛрдВ рдореЗрдВ рдпрд╛ рдЕрдкрдиреЗ рджрдо рдкрд░ рдЕрдзреНрдпрдпрди рдХрд┐рдпрд╛ред рд╣рдорд╛рд░рд╛ рд▓рдХреНрд╖реНрдп рдЙрддреНрдкрд╛рджрдХрддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВрдиреЗ рдмрд╣реБрдд рд╕рдордп рдкрд╣рд▓реЗ рдХреЙрд▓рдо рд▓реЗрдЖрдЙрдЯ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд┐рдпрд╛ рдерд╛ред рдореЗрд░рд╛ рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рд░реЗрдВрдбрд░рд░ OpenGL API рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ рдФрд░ рдЗрд╕рд▓рд┐рдП, рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝рд┐рд╢рди рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдХреЙрд▓рдо рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ред рдпрд╣ рднреА рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдЧреБрдгрди рдЗрддрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИред рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ 2-5-10 рдЧреБрдгрд╛ рдЧреБрдгрд╛ред рдФрд░ рд╡рд╣ рдпрд╣ рд╣реИред рдФрд░ рдлрд┐рд░ рд╣рдо рддреИрдпрд╛рд░ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЛ рд╣рдЬрд╛рд░реЛрдВ рдпрд╛ рд▓рд╛рдЦреЛрдВ рдЪрдХреНрдХрд░реЛрдВ рд╕реЗ рдЧреБрдгрд╛ рдХрд░рддреЗ рд╣реИрдВред рдФрд░ рдпрд╣ рдСрдкрд░реЗрд╢рди рдЕрдзрд┐рдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред рдЖрдк рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╣рд░ рдмрд╛рд░ рд╕рдВрдХреНрд░рдордг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдХреНрдпреЛрдВ, рдЕрдЧрд░ рдЗрд╕рд╕реЗ рдмрдЪрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рд▓реЗрдХрд┐рди рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдореЗрдЯреНрд░рд┐рд╕реЗрд╕ рдкрд░ рд╡рд╛рдкрд╕ред рд╣рдордиреЗ рдХреЙрд▓рдо рдореЗрдВ рднрдВрдбрд╛рд░рдг рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд┐рдпрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдФрд░ рдЬрдЯрд┐рд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред SIMD рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдореЗрдВ рд╡реИрдХреНрдЯрд░ рдФрд░ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд╡рд░рд┐рд╖реНрда рддрддреНрд╡реЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рдореЗрд░реЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ рддрд╛рдХрд┐
x рдЙрдЪреНрдЪрддрдо рдлреНрд▓реЛрдЯ (рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ 3) рдореЗрдВ рд╣реЛ, рдФрд░ рдорд╛рдЗрдирд░ (рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ 0) рдореЗрдВ
w ред рдпрд╣рд╛рдБ, рдЬрд╛рд╣рд┐рд░ рд╣реИ, рд╣рдореЗрдВ рдлрд┐рд░ рд╕реЗ рдкреАрдЫреЗ рд╣рдЯрдирд╛ рд╣реЛрдЧрд╛ рдХреНрдпреЛрдВред
рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдПрдХ рд╡реЗрдХреНрдЯрд░ рдореЗрдВ рдПрдХ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рд░реЗрдВрдбрд░рд░ рдореЗрдВ, рдЖрдкрдХреЛ
рдбрдмреНрд▓реНрдпреВ рдШрдЯрдХ рдХреЛ рдЕрдзрд┐рдХ рдмрд╛рд░ рд╣реЗрд░рдлреЗрд░ рдХрд░рдирд╛
рд╣реЛрдЧрд╛ (
1 / z рд╡рд╣рд╛рдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ), рдФрд░ рдСрдкрд░реЗрд╢рди рдХреЗ
_ss рд╕рдВрд╕реНрдХрд░рдг (
рдПрдХреНрд╕рдПрдордПрдо рд░рдЬрд┐рд╕реНрдЯрд░ рдХреЗ рдирд┐рдЪрд▓реЗ рдлреНрд▓реЛрдЯ рдореЗрдВ рдШрдЯрдХ рдХреЗ рд╕рд╛рде рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕рдВрдЪрд╛рд▓рди) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдРрд╕рд╛ рдХрд░рдирд╛ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИ,
рдПрдХреНрд╕, рд╡рд╛рдИ рдХреЛ рдЫреВрдиреЗ рдХреЗ рдмрд┐рдирд╛
ред z рдЗрд╕рд▓рд┐рдП, SSE рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ, рд╡реЗрдХреНрдЯрд░ рдХреЛ рдПрдХ рд╕рдордЭрдиреЗ рдпреЛрдЧреНрдп рдХреНрд░рдо
x, y, z, w , рдФрд░ рдореЗрдореЛрд░реА рдореЗрдВ рд░рд┐рд╡рд░реНрд╕
w, z, y, x рдореЗрдВ рд╕рдВрдЧреНрд░рд╣рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╕рднреА рдЧреБрдгрд╛ рд╡рд┐рдХрд▓реНрдк рд╡реНрдпрдХреНрддрд┐рдЧрдд рдХрд╛рд░реНрдпреЛрдВ рджреНрд╡рд╛рд░рд╛ рднреА рд▓рд╛рдЧреВ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдпрд╣ рдЗрд╕рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рдЙрдиреНрд╣реЗрдВ рдЗрдЪреНрдЫрд┐рдд рд╡рд┐рдХрд▓реНрдк рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЗрдЪреНрдЫрд┐рдд рд╡рд┐рдХрд▓реНрдк рдХреЗ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВред
рдпрд╣рд╛рдБ рд╡рд░реНрдгрд┐рдд рд╣реИредрд╣рдо рдмреБрдирд┐рдпрд╛рджреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ
рдЫреЛрд░реЛрдВ рдХреЗ рд╕рд╛рде рдЧреБрдгрд╛, рдкрдВрдХреНрддрд┐ рдХрд╛ рдЖрджреЗрд╢ рджрд┐рдпрд╛
рддрддреНрд╡реЛрдВ рдХреЗ рд▓рд╛рдЗрди рд▓реЗрдЖрдЙрдЯ рдХреЗ рд▓рд┐рдП рд╡рд┐рдХрд▓реНрдкfor (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { r[i][j] = 0.f; for (int k = 0; k < 4; ++k) { r[i][j] += m[i][k] * n[k][j]; } } }
рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рдФрд░ рд╕реНрдкрд╖реНрдЯ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдХреЗ рд▓рд┐рдП рд╣рдо 4 рдЧреБрдгрд╛ рдФрд░ 3 рдЬреЛрдбрд╝ рдХрд░рддреЗ рд╣реИрдВред рдХреБрд▓ рдореЗрдВ, рдпреЗ 64 рдЧреБрдгрд╛ рдФрд░ 48 рдЬреЛрдбрд╝ рд╣реИрдВред рдФрд░ рдпрд╣ рд░рд┐рдХреЙрд░реНрдб рддрддреНрд╡реЛрдВ рдХреЗ рдкрдврд╝рдиреЗ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗ рдмрд┐рдирд╛ рд╣реИред
рд╕рдм рдХреБрдЫ рджреБрдЦ рдХреА рдмрд╛рдд рд╣реИ, рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВред рдЗрд╕ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП, рдЖрдВрддрд░рд┐рдХ рдЪрдХреНрд░ рдХреЗ рд▓рд┐рдП, IACA рдиреЗ рдЬрд╛рд░реА рдХрд┐рдпрд╛:
x86 рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЗ рд▓рд┐рдП 3.65 рдШрдбрд╝реА рдЪрдХреНрд░ рдФрд░ x64 рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЗ рд▓рд┐рдП 2.97 рдШрдбрд╝реА ред рдпрд╣ рдордд рдкреВрдЫреЛ рдХрд┐ рднрд┐рдиреНрдирд╛рддреНрдордХ рд╕рдВрдЦреНрдпрд╛рдПрдБ рдХреНрдпреЛрдВ рд╣реИрдВред рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ IACA 2.1 рдХреЛ рдЗрд╕рд╕реЗ рдиреБрдХрд╕рд╛рди рдирд╣реАрдВ рд╣реБрдЖред рдХрд┐рд╕реА рднреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдЗрди рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рд▓рдЧрднрдЧ 4 * 4 * 4 = 64 рд╕реЗ рдЧреБрдгрд╛ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рднрд▓реЗ рд╣реА рдЖрдк x64 рд▓реЗрддреЗ рд╣реИрдВ, рдкрд░рд┐рдгрд╛рдо 192 рдЙрдкрд╛рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИред рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рдореЛрдЯрд╛ рдЕрдиреБрдорд╛рди рд╣реИред рдореБрдЭреЗ рдЗрд╕ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд░реНрд╢рди рдХрд╛ рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреА рдмрд╛рдд рдирд╣реАрдВ рджрд┐рдЦрддреА рд╣реИред
рд▓реВрдкрд┐рдВрдЧ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди, рдХреЙрд▓рдо рдХрд╛ рдЖрджреЗрд╢ рджрд┐рдпрд╛
рдЯреНрд░рд╛рдВрд╕рдкреЛрдЬрд╝реНрдб рдореИрдЯреНрд░рд┐рдХреНрд╕, рд░рд┐рдпрд░ рдкрдВрдХреНрддрд┐ рдФрд░ рдХреЙрд▓рдо рдЗрдВрдбреЗрдХреНрд╕ for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { r[j][i] = 0.f; for (int k = 0; k < 4; ++k) { r[j][i] += m[k][i] * n[j][k]; } } }
рд╕рд╛рдЗрдХрд┐рд▓ рдЧреБрдгрд╛, SIMD рдЙрдиреНрдореБрдЦ рднрдВрдбрд╛рд░рдг
рдореЗрдореЛрд░реА рдореЗрдВ рд░рд┐рд╡рд░реНрд╕ рдСрд░реНрдбрд░ рдореЗрдВ рд▓рд╛рдЗрдиреЛрдВ рдХрд╛ рднрдВрдбрд╛рд░рдг рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { r[j][3-i] = 0.f; for (int k = 0; k < 4; ++k) { r[j][3-i] += m[k][3-i] * n[j][3-k]; } } }
рдпрд╣ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреБрдЫ рд╣рдж рддрдХ рдЗрд╕ рд╕рдордЭ рдХреЛ рд╕рд░рд▓ рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЕрдВрджрд░ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИред
рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧ
рд╕рдВрджрд░реНрдн рдФрд░ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЛрдб рдХреЛ рд╕рдордЭрдиреЗ рдФрд░ рд▓рд┐рдЦрдиреЗ рдХреА рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧреЛрдВ рдХреЗ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдЬреНрдпрд╛рджрд╛ рдХреБрдЫ рдирд╣реАрдВ, рд╕рдм рдХреБрдЫ рдХреЗрд╡рд▓ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИред рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдкреВрд░реНрдг-рд╕рджрд┐рд╢ рдФрд░ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХрдХреНрд╖рд╛рдУрдВ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдПрдХ рдЕрд▓рдЧ рдХрдард┐рди рдкреНрд░рд╢реНрди рд╣реИ, рдФрд░ рдЗрд╕ рд▓реЗрдЦ рдХреЗ рд╡рд┐рд╖рдп рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реИред
рд╡реЗрдХреНрдЯрд░ рдФрд░ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХрдХреНрд╖рд╛рдПрдВ struct alignas(sizeof(__m128)) vec4 { union { struct { float w, z, y, x; }; __m128 fmm; float arr[4]; }; vec4() {} vec4(float a, float b, float c, float d) : w(d), z(c), y(b), x(a) {} static bool equ(float const a, float const b, float t = .00001f) { return fabs(ab) < t; } bool operator == (vec4 const& v) const { return equ(x, vx) && equ(y, vy) && equ(z, vz) && equ(w, vw); } }; struct alignas(sizeof(__m256)) mtx4 {
рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд╕рдВрджрд░реНрдн рд╕рдорд╛рд░реЛрд╣
рдЪреВрдВрдХрд┐ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдореЗрдВ рддрддреНрд╡реЛрдВ рдХрд╛ рд╕реНрд╡реАрдХреГрдд рдХреНрд░рдо рд╕рдордЭ рдХреЛ рдмрд╣реБрдд рдЬрдЯрд┐рд▓ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╕рдВрджрд░реНрдн
рд╕реНрдкрд╖реНрдЯ рдлрд╝рдВрдХреНрд╢рди рд╕реЗ рднреА рдкрд░реЗрд╢рд╛рди рдирд╣реАрдВ рд╣реЛрдВрдЧреЗ, рдЬреЛ рднрд╡рд┐рд╖реНрдп рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рджрд┐рдЦрд╛рдПрдЧрд╛ рдХрд┐ рд╕рдм рдХреБрдЫ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд╣рдо рдЗрд╕рдХреЗ рд╕рд╛рде рдмрд╛рдж рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░реЗрдВрдЧреЗред
рдЗрд╕реЗ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдЪрдХреНрд░ рдХреЛ рд▓реЗрдВ рдФрд░ рдЙрд╕рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВ void mul_mtx4_mtx4_unroll(__m128* const _r, __m128 const* const _m, __m128 const* const _n) { mtx4 const& m = **reinterpret_cast<mtx4 const* const*>(&_m); mtx4 const& n = **reinterpret_cast<mtx4 const* const*>(&_n); mtx4& r = **reinterpret_cast<mtx4* const*>(&_r); r._00 = m._00*n._00 + m._01*n._10 + m._02*n._20 + m._03*n._30; r._01 = m._00*n._01 + m._01*n._11 + m._02*n._21 + m._03*n._31; r._02 = m._00*n._02 + m._01*n._12 + m._02*n._22 + m._03*n._32; r._03 = m._00*n._03 + m._01*n._13 + m._02*n._23 + m._03*n._33; r._10 = m._10*n._00 + m._11*n._10 + m._12*n._20 + m._13*n._30; r._11 = m._10*n._01 + m._11*n._11 + m._12*n._21 + m._13*n._31; r._12 = m._10*n._02 + m._11*n._12 + m._12*n._22 + m._13*n._32; r._13 = m._10*n._03 + m._11*n._13 + m._12*n._23 + m._13*n._33; r._20 = m._20*n._00 + m._21*n._10 + m._22*n._20 + m._23*n._30; r._21 = m._20*n._01 + m._21*n._11 + m._22*n._21 + m._23*n._31; r._22 = m._20*n._02 + m._21*n._12 + m._22*n._22 + m._23*n._32; r._23 = m._20*n._03 + m._21*n._13 + m._22*n._23 + m._23*n._33; r._30 = m._30*n._00 + m._31*n._10 + m._32*n._20 + m._33*n._30; r._31 = m._30*n._01 + m._31*n._11 + m._32*n._21 + m._33*n._31; r._32 = m._30*n._02 + m._31*n._12 + m._32*n._22 + m._33*n._32; r._33 = m._30*n._03 + m._31*n._13 + m._32*n._23 + m._33*n._33; }
рд╢рд╛рд╕реНрддреНрд░реАрдп рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдпрд╣рд╛рдВ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЪрд┐рддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдПрдХ рдЧрд▓рддреА рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ (рд▓реЗрдХрд┐рди рдЖрдк :-)) рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЙрд╕ рдкрд░, IACA рдиреЗ рдЬрд╛рд░реА рдХрд┐рдпрд╛:
x86 - 69.95 рдЙрдкрд╛рдп, x64 - 64 рдЙрдкрд╛рдп ред рдпрд╣рд╛рдВ рд▓рдЧрднрдЧ 64 рдЪрдХреНрд░ рд╣реИрдВ рдФрд░ рд╣рдо рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЗрд╕ рдСрдкрд░реЗрд╢рди рдХреЗ рддреНрд╡рд░рдг рдХреЛ рджреЗрдЦреЗрдВрдЧреЗред
SSE рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдХреНрд▓рд╛рд╕рд┐рдХ SSE рдПрд▓реНрдЧреЛрд░рд┐рдердо
рдХреНтАНрдпреЛрдВ рдХреНрд▓рд╛рд╕рд┐рдХ? рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд▓рдВрдмреЗ рд╕рдордп рд╕реЗ
рдПрдордПрд╕рд╡реАрдПрд╕ рдХреЗ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд░реВрдк рдореЗрдВ
рдПрдлрд╡реАрдИрд╕реА рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рд╣реИред рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд▓рд┐рдЦреЗрдВрдЧреЗ рдХрд┐ рд╣рдо рдПрд╕рдПрд╕рдИ рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдореЗрдВ рдореИрдЯреНрд░рд┐рдХреНрд╕ рддрддреНрд╡ рдХреИрд╕реЗ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдпрд╣рд╛рдБ рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИред рдмрд╕ рдПрдХ рдЯреНрд░рд╛рдВрд╕рдкреЛрдВрдб рдореИрдЯреНрд░рд┐рдХреНрд╕ред
// 00, 10, 20, 30 // m[0] - SIMD / 01, 11, 21, 31 // m[1] 02, 12, 22, 32 // m[2] 03, 13, 23, 33 // m[3]
рд╣рдо рдКрдкрд░ рджрд┐рдП рдЧрдП рд╡реЗрд░рд┐рдПрдВрдЯ рдХрд╛
рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рдХреЛрдб рд▓реЗрддреЗ рд╣реИрдВред рдХрд┐рд╕реА рддрд░рд╣ рд╡рд╣ SSE рдХреЗ рд▓рд┐рдП рдЕрдорд┐рддреНрд░ рд╣реИред рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рдкрд╣рд▓реЗ рд╕рдореВрд╣ рдореЗрдВ рдкрд░рд┐рдгрд╛рдореА рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЗ рдХреЙрд▓рдо рдХреЗ рдкрд░рд┐рдгрд╛рдо рд╣реЛрддреЗ рд╣реИрдВ:
r._00, r._01, r._02, r._03 ред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдпрд╣ рдХреЙрд▓рдо рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдПрдХ рдкрдВрдХреНрддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рд╛рдВ, рдФрд░
рдореА ,
рдПрди рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рджрд┐рдЦрддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдПрд▓реНрдЧреЛрд░рд┐рдердо рдХреА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдкреБрдирд░реНрд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдкрд░рд┐рдгрд╛рдо
рдЖрд░ рдкрдВрдХреНрддрд┐-рд╡рд╛рд░ рд╣реЛред
// , r[0] r00 = m00*n00 + m01*n10 + m02*n20 + m03*n30; r10 = m10*n00 + m11*n10 + m12*n20 + m13*n30; r20 = m20*n00 + m21*n10 + m22*n20 + m23*n30; r30 = m30*n00 + m31*n10 + m32*n20 + m33*n30; // , r[1] r01 = m00*n01 + m01*n11 + m02*n21 + m03*n31; r11 = m10*n01 + m11*n11 + m12*n21 + m13*n31; r21 = m20*n01 + m21*n11 + m22*n21 + m23*n31; r31 = m30*n01 + m31*n11 + m32*n21 + m33*n31; // , r[2] r02 = m00*n02 + m01*n12 + m02*n22 + m03*n32; r12 = m10*n02 + m11*n12 + m12*n22 + m13*n32; r22 = m20*n02 + m21*n12 + m22*n22 + m23*n32; r32 = m30*n02 + m31*n12 + m32*n22 + m33*n32; // , r[3] r03 = m00*n03 + m01*n13 + m02*n23 + m03*n33; r13 = m10*n03 + m11*n13 + m12*n23 + m13*n33; r23 = m20*n03 + m21*n13 + m22*n23 + m23*n33; r33 = m30*n03 + m31*n13 + m32*n23 + m33*n33;
рд▓реЗрдХрд┐рди рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рдХрд╛рдлреА рдмреЗрд╣рддрд░ рд╣реИред рдХреНрдпрд╛, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдХреНрдпрд╛ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ? рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдореЗрдВ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рдХреЙрд▓рдо рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╢рд╛рдорд┐рд▓ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреА рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд╣реИрдВ:
m [0] = {00,10,20,30}, m [1] = {01,11,21,31}, m [2] = {02,12,22,32}, m [3] = {} 03,13,23,33,
рдЬреЛ рдореИрдЯреНрд░рд┐рдХреНрд╕
n рдХреЗ рдПрдХ рд╣реА рддрддреНрд╡ рджреНрд╡рд╛рд░рд╛ рдЧреБрдгрд╛ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ рд╕рдореВрд╣ рдХреЗ рд▓рд┐рдП рдпрд╣ рд╣реИ:
n._00, n._10, n._20, n._30 ред рдФрд░ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдХреЗ рд▓рд┐рдП рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЗ рддрддреНрд╡ рдлрд┐рд░ рд╕реЗ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреА рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдЭреВрда рдмреЛрд▓рддреЗ рд╣реИрдВред
рддрдм рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИ: рд╣рдо рдХреЗрд╡рд▓ рдореИрдЯреНрд░рд┐рдХреНрд╕
рдореАрдЯрд░ рдХреА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рд╕реВрдЪрдХрд╛рдВрдХ рджреНрд╡рд╛рд░рд╛ рд▓реЗрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рддрддреНрд╡реЛрдВ
n рдХреЗ рд▓рд┐рдП , рд╣рдо рдЗрд╕рдХреА рдкрдВрдХреНрддрд┐ рд▓реЗрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд░рдЬрд┐рд╕реНрдЯрд░ рдХреЗ рд╕рднреА 4 рддрддреНрд╡реЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ
рдлреЗрд░рдмрджрд▓ рдХрд░рддреЗ рд╣реИрдВ, рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рдореИрдЯреНрд░рд┐рдХреНрд╕
рдореАрдЯрд░ рдХреА рдкрдВрдХреНрддрд┐ рджреНрд╡рд╛рд░рд╛ рдЧреБрдгрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рддрддреНрд╡
n._00 рдХреЗ рд▓рд┐рдП (рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рдЗрд╕рдХреА рдкрд╛рд░реА рдореЗрдВ рд╕реВрдЪрдХрд╛рдВрдХ 3 рд╣реИ), рдпрд╣ рд╣реЛрдЧрд╛:
_mm_shuffle_ps (n [0], n [0], _MM_SHUFFLE (3,3,3,3))
рд╕рд░рд▓реАрдХреГрдд рд░реВрдк рдореЗрдВ, рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
// n[0]={00,10,20,30} r[0] = m[0] * n00 + m[1] * n10 + m[2] * n20 + m[3] * n30; // n[1]={01,11,21,31} r[1] = m[0] * n01 + m[1] * n11 + m[2] * n21 + m[3] * n31; // n[2]={02,12,22,32} r[2] = m[0] * n02 + m[1] * n12 + m[2] * n22 + m[3] * n32; // n[3]={03,13,23,33} r[3] = m[0] * n03 + m[1] * n13 + m[2] * n23 + m[3] * n33;
рдмреБрдирд┐рдпрд╛рджреА рдПрд╕рдПрд╕рдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди void mul_mtx4_mtx4_sse_v1(__m128* const r, __m128 const* const m, __m128 const* const n) { r[0] = _mm_add_ps( _mm_add_ps( _mm_mul_ps(m[0], _mm_shuffle_ps(n[0], n[0], _MM_SHUFFLE(3,3,3,3))), _mm_mul_ps(m[1], _mm_shuffle_ps(n[0], n[0], _MM_SHUFFLE(2,2,2,2)))), _mm_add_ps( _mm_mul_ps(m[2], _mm_shuffle_ps(n[0], n[0], _MM_SHUFFLE(1,1,1,1))), _mm_mul_ps(m[3], _mm_shuffle_ps(n[0], n[0], _MM_SHUFFLE(0,0,0,0))))); r[1] = _mm_add_ps( _mm_add_ps( _mm_mul_ps(m[0], _mm_shuffle_ps(n[1], n[1], _MM_SHUFFLE(3,3,3,3))), _mm_mul_ps(m[1], _mm_shuffle_ps(n[1], n[1], _MM_SHUFFLE(2,2,2,2)))), _mm_add_ps( _mm_mul_ps(m[2], _mm_shuffle_ps(n[1], n[1], _MM_SHUFFLE(1,1,1,1))), _mm_mul_ps(m[3], _mm_shuffle_ps(n[1], n[1], _MM_SHUFFLE(0,0,0,0))))); r[2] = _mm_add_ps( _mm_add_ps( _mm_mul_ps(m[0], _mm_shuffle_ps(n[2], n[2], _MM_SHUFFLE(3,3,3,3))), _mm_mul_ps(m[1], _mm_shuffle_ps(n[2], n[2], _MM_SHUFFLE(2,2,2,2)))), _mm_add_ps( _mm_mul_ps(m[2], _mm_shuffle_ps(n[2], n[2], _MM_SHUFFLE(1,1,1,1))), _mm_mul_ps(m[3], _mm_shuffle_ps(n[2], n[2], _MM_SHUFFLE(0,0,0,0))))); r[3] = _mm_add_ps( _mm_add_ps( _mm_mul_ps(m[0], _mm_shuffle_ps(n[3], n[3], _MM_SHUFFLE(3,3,3,3))), _mm_mul_ps(m[1], _mm_shuffle_ps(n[3], n[3], _MM_SHUFFLE(2,2,2,2)))), _mm_add_ps( _mm_mul_ps(m[2], _mm_shuffle_ps(n[3], n[3], _MM_SHUFFLE(1,1,1,1))), _mm_mul_ps(m[3], _mm_shuffle_ps(n[3], n[3], _MM_SHUFFLE(0,0,0,0))))); }
рдЕрдм рд╣рдо рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рддрддреНрд╡реЛрдВ рдХреЛ рд╕рдВрдмрдВрдзрд┐рдд
рдлреЗрд░рдмрджрд▓ рдореЗрдВ рдмрджрд▓рддреЗ рд╣реИрдВ ,
_mm_mul_ps рджреНрд╡рд╛рд░рд╛ рдЧреБрдгрд╛,
_mm_add_ps рджреНрд╡рд╛рд░рд╛ рдпреЛрдЧ, рдФрд░ рдЖрдк рдХрд░
рд░рд╣реЗ рд╣реИрдВ ред рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреЛрдб, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рдЦрд░рд╛рдм рд▓рдЧ рд░рд╣рд╛ рдерд╛ред рдЗрд╕ рдХреЛрдб рдХреЗ рд▓рд┐рдП, IACA рдиреЗ рдЬрд╛рд░реА рдХрд┐рдпрд╛:
x86 - 18.89, x64 - 16 рдЪрдХреНрд░ ред рдпрд╣ рдкрд┐рдЫрд▓реЗ рд╡рд╛рд▓реЗ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ 4 рдЧреБрдирд╛ рддреЗрдЬ рд╣реИред SSE рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ 4th рдлреНрд▓реЛрдЯред рд▓рдЧрднрдЧ рд░реИрдЦрд┐рдХ рд╕рдВрдмрдВрдзред
рдПрд╕рдПрд╕рдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рд╕рдЬрд╛рдиреЗ
рдлрд┐рд░ рднреА, рдХреЛрдб рдореЗрдВ рдпрд╣ рднрдпрд╛рдирдХ рд▓рдЧ рд░рд╣рд╛ рд╣реИред рд╣рдо рдереЛрдбрд╝рд╛ рд╕рд╛ рд╕рдВрд╢реНрд▓рд┐рд╖реНрдЯ рдЪреАрдиреА рд▓рд┐рдЦрдХрд░ рдЗрд╕реЗ рд╕реБрдзрд╛рд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВрдЧреЗред
рд╕рдВрдЪрд╛рд▓рдХ рдФрд░ рд╕реБрдзрд╛рд░рдХ рдХрдВрдкрд╛рдЗрд▓рд░ рдЗрди рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЗрдирд▓рд╛рдЗрди рдХрд░ рд╕рдХрддрд╛ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдХрднреА-рдХрднреА __рдлреЛрд░реНрд╕рд┐рдирд▓рд╛рдЗрди рдХреЗ рдмрд┐рдирд╛ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ)ред
рдЗрд╕рд▓рд┐рдП рдХреЛрдб рдмрджрд▓ рд░рд╣рд╛ рд╣реИ ... void mul_mtx4_mtx4_sse_v2(__m128* const r, __m128 const* const m, __m128 const* const n) { r[0] = m[0]*shuf<3>(n[0]) + m[1]*shuf<2>(n[0]) + m[2]*shuf<1>(n[0]) + m[3]*shuf<0>(n[0]); r[1] = m[0]*shuf<3>(n[1]) + m[1]*shuf<2>(n[1]) + m[2]*shuf<1>(n[1]) + m[3]*shuf<0>(n[1]); r[2] = m[0]*shuf<3>(n[2]) + m[1]*shuf<2>(n[2]) + m[2]*shuf<1>(n[2]) + m[3]*shuf<0>(n[2]); r[3] = m[0]*shuf<3>(n[3]) + m[1]*shuf<2>(n[3]) + m[2]*shuf<1>(n[3]) + m[3]*shuf<0>(n[3]); }
рдФрд░ рдЗрд╕рд▓рд┐рдП рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рдмрд╣реБрдд рдмреЗрд╣рддрд░ рдФрд░ рдЕрдзрд┐рдХ рдкрдардиреАрдп рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП, IACA рдиреЗ рд▓рдЧрднрдЧ рдЕрдкреЗрдХреНрд╖рд┐рдд рдкрд░рд┐рдгрд╛рдо рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд┐рдпрд╛:
x86 - 19 (рдФрд░ рднрд┐рдиреНрдирд╛рддреНрдордХ рдХреНрдпреЛрдВ рдирд╣реАрдВ?), X64 - 16 ред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдкреНрд░рджрд░реНрд╢рди рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЛрдб рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реБрдВрджрд░ рдФрд░ рд╕рдордЭрдиреЗ рдпреЛрдЧреНрдп рд╣реИред
рднрд╡рд┐рд╖реНрдп рдХреЗ рдЕрдиреБрдХреВрд▓рди рдореЗрдВ рдереЛрдбрд╝рд╛ рдпреЛрдЧрджрд╛рди
рдЖрдЗрдП рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕реНрддрд░ рдкрд░ рдПрдХ рдФрд░ рд╕реБрдзрд╛рд░ рдкреЗрд╢ рдХрд░реЗрдВ рдЬреЛ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд▓реЛрд╣реЗ рдХреЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ред рдСрдкрд░реЗрд╢рди
рдорд▓реНрдЯреАрдкрд▓-рдРрдб (fma) ред
fma (рдП, рдмреА, рд╕реА) = рдП * рдмреА + рд╕реА ред
рдХрдИ-рдХрдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди __m128 mad(__m128 const a, __m128 const b, __m128 const c) { return _mm_add_ps(_mm_mul_ps(a, b), c); }
рдпрд╣ рдХреНрдпреЛрдВ рдЖрд╡рд╢реНрдпрдХ рд╣реИ? рднрд╡рд┐рд╖реНрдп рдХреЗ рдЕрдиреБрдХреВрд▓рди рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдкрд╣рд▓реЗред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдмрд╕ рдЙрд╕реА рдореИрдХреНрд░реЛрдЬрд╝ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рддреИрдпрд╛рд░ рдХреЛрдб рдореЗрдВ
fma рдХреЗ рд╕рд╛рде
рдкрд╛рдЧрд▓ рдХреЛ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ рдЬреИрд╕реЗ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд▓реЗрдХрд┐рди рдЕрдм рд╣рдо рдЕрдиреБрдХреВрд▓рди рдХреА рдиреАрдВрд╡ рд░рдЦреЗрдВрдЧреЗ:
рдмрд╣реБ-рдЬреЛрдбрд╝ рдХреЗ рд╕рд╛рде рднрд┐рдиреНрди void mul_mtx4_mtx4_sse_v3(__m128* const r, __m128 const* const m, __m128 const* const n) { r[0] = mad(m[0], shuf<3>(n[0]), m[1]*shuf<2>(n[0])) + mad(m[2], shuf<1>(n[0]), m[3]*shuf<0>(n[0])); r[1] = mad(m[0], shuf<3>(n[1]), m[1]*shuf<2>(n[1]) + mad(m[2], shuf<1>(n[1]), m[3]*shuf<0>(n[1])); r[2] = mad(m[0], shuf<3>(n[2]), m[1]*shuf<2>(n[2])) + mad(m[2], shuf<1>(n[2]), m[3]*shuf<0>(n[2])); r[3] = mad(m[0], shuf<3>(n[3]), m[1]*shuf<2>(n[3])) + mad(m[2], shuf<1>(n[3]), m[3]*shuf<0>(n[3])); }
IACA:
x86 - 18.89, x64 - 16 ред рдлрд┐рд░ рд╕реЗ рднрд┐рдиреНрдирд╛рддреНрдордХред рдлрд┐рд░ рднреА, IACA рдХрднреА-рдХрднреА рдЕрдЬреАрдм рдкрд░рд┐рдгрд╛рдо рдкреИрджрд╛ рдХрд░рддрд╛ рд╣реИред рдХреЛрдб рдЗрддрдирд╛ рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реИред рд╢рд╛рдпрдж рдереЛрдбрд╝рд╛ рдмреБрд░рд╛ рднреАред рд▓реЗрдХрд┐рди рдЕрдиреБрдХреВрд▓рди рдХреЗ рд▓рд┐рдП рдХрднреА-рдХрднреА рдРрд╕реЗ рдмрд▓рд┐рджрд╛рдиреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
рд╣рдо _mm_stream рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдмрдЪрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ
рд╡рд┐рднрд┐рдиреНрди рдЕрдиреБрдХреВрд▓рди рдЧрд╛рдЗрдб рдПрдХ рдмрд╛рд░ рдлрд┐рд░ рд╕реЗ рдмрд▓реНрдХ рд╕реЗрд╡ рдСрдкрд░реЗрд╢рдВрд╕ рдХреЗ рд▓рд┐рдП рдХреИрд╢ рдХреЛ рдЦреАрдВрдЪрдиреЗ рдХреА рд╕рд▓рд╛рд╣ рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВред рдпрд╣ рдЖрдорддреМрд░ рдкрд░ рдЙрдЪрд┐рдд рд╣реИ рдЬрдм рдЖрдк рд▓рдВрдмрд╡рдд рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЬреЛ рд╣рдЬрд╛рд░реЛрдВ рдпрд╛ рдЕрдзрд┐рдХ рд╣реИрдВред рд▓реЗрдХрд┐рди рдореИрдЯреНрд░рд┐рд╕ рдХреЗ рд▓рд┐рдП, рдпрд╣ рд╢рд╛рдпрдж рдЗрддрдирд╛ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдореИрдВ рдЗрд╕реЗ рд╡реИрд╕реЗ рднреА рдЬреЛрдбрд╝реВрдВрдЧрд╛ред
рд╕реНрдЯреНрд░реАрдо рд╕реЗрд╡рд┐рдВрдЧ рдСрдкреНрд╢рди void mul_mtx4_mtx4_sse_v4(__m128* const r, __m128 const* const m, __m128 const* const n) { _mm_stream_ps(&r[0].m128_f32[0], mad(m[0], shuf<3>(n[0]), m[1]*shuf<2>(n[0])) + mad(m[2], shuf<1>(n[0]), m[3]*shuf<0>(n[0]))); _mm_stream_ps(&r[1].m128_f32[0], mad(m[0], shuf<3>(n[1]), m[1]*shuf<2>(n[1])) + mad(m[2], shuf<1>(n[1]), m[3]*shuf<0>(n[1]))); _mm_stream_ps(&r[2].m128_f32[0], mad(m[0], shuf<3>(n[2]), m[1]*shuf<2>(n[2])) + mad(m[2], shuf<1>(n[2]), m[3]*shuf<0>(n[2]))); _mm_stream_ps(&r[3].m128_f32[0], mad(m[0], shuf<3>(n[3]), m[1]*shuf<2>(n[3])) + mad(m[2], shuf<1>(n[3]), m[3]*shuf<0>(n[3]))); }
рдпрд╣рд╛рдВ рд╕рдордп рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реИ, рд╢рдмреНрдж рд╕реЗ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдирд╣реАрдВред рд▓реЗрдХрд┐рди, рд╕рд┐рдлрд╛рд░рд┐рд╢реЛрдВ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╣рдо рдЕрдм рдХреИрд╢ рдХреЛ рдПрдХ рдмрд╛рд░ рдлрд┐рд░ рд╕реЗ рдирд╣реАрдВ рдЫреВрддреЗ рд╣реИрдВред
рдПрд╡реАрдПрдХреНрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдЖрдзрд╛рд░ AVX рд╡рд┐рдХрд▓реНрдк

рдЕрдЧрд▓рд╛, рд╣рдо рдЕрдиреБрдХреВрд▓рди рдХреЗ рдЕрдЧрд▓реЗ рдЪрд░рдг рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВред 4 рд╡реЗрдВ рдлреНрд▓реЛрдЯ рдХреЛ рдПрд╕рдПрд╕рдИ рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдПрд╡реАрдПрдХреНрд╕ рдореЗрдВ рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА 8. рд╣реИред рдЕрд░реНрдерд╛рддреН, рдкреНрд░рджрд░реНрд╢рди рдХрд┐рдП рдЧрдП рд╕рдВрдЪрд╛рд▓рди рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рдореМрдХрд╛ рд╣реИ, рдФрд░ рдЙрддреНрдкрд╛рджрдХрддрд╛ рдореЗрдВ рд╡реГрджреНрдзрд┐ рдЕрдЧрд░ рдЖрдзреЗ рд╕реЗ рдирд╣реАрдВ, рддреЛ рдХрдо рд╕реЗ рдХрдо 1.5 рдЧреБрдирд╛ред рд▓реЗрдХрд┐рди рдХреБрдЫ рдореБрдЭреЗ рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рдПрд╡реАрдПрдХреНрд╕ рдХреЗ рд╕рдВрдХреНрд░рдордг рдХреЗ рд╕рд╛рде рд╕рдм рдХреБрдЫ рдЗрддрдирд╛ рд╕рд░рд▓ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рдХреНрдпрд╛ рд╣рдо рдбрдмрд▓ рд░рдЬрд┐рд╕реНрдЯрд░ рд╕реЗ рдЖрд╡рд╢реНрдпрдХ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?
рдЖрдЗрдП рдЗрд╕реЗ рдЬрд╛рдирдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВред рдлрд┐рд░, рд╣рдо рдЕрдкрдиреЗ рдЧреБрдгрди рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдКрдкрд░ рд▓рд┐рдЦрддреЗ рд╣реИрдВред рдЖрдк рдРрд╕рд╛ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, рд▓реЗрдХрд┐рди рдЬрдм рд╕рдм рдХреБрдЫ рдкрд╛рд╕ рд╣реЛ рддреЛ рдХреЛрдб рд╕реЗ рдирд┐рдкрдЯрдирд╛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛ рдФрд░ рдЖрдкрдХреЛ рдЖрдзреЗ рдкреГрд╖реНрда рддрдХ рд╕реНрдХреНрд░реЙрд▓ рдирд╣реАрдВ рдХрд░рдирд╛ рдкрдбрд╝реЗрдЧрд╛ред
// : 00, 10, 20, 30, 01, 11, 21, 31, 02, 12, 22, 32, 03, 13, 23, 33 // SSE: r0 = m0*n00 + m1*n10 + m2*n20 + m3*n30 r1 = m0*n01 + m1*n11 + m2*n21 + m3*n31 r2 = m0*n02 + m1*n12 + m2*n22 + m3*n32 r3 = m0*n03 + m1*n13 + m2*n23 + m3*n33
рдЖрдЙрдЯрдкреБрдЯ рдкрд░, рд╣рдо
ymm = {r0: r1} рдФрд░
ymm = {r2: r3} рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ SSE рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рд╣рдорд╛рд░реЗ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рд╕реНрддрдВрднреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рддреЛ рдЕрдм рд╣рдореЗрдВ рдЗрд╕реЗ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рддреЛ рдПрд╕рдПрд╕рдИ рд╡рд┐рдХрд▓реНрдк рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред
рдпрджрд┐ рд╣рдо рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ
ymm рдореЗрдВ рдореИрдЯреНрд░рд┐рдХреНрд╕
m рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо
рдХреНрд░рдорд╢рдГ ymm = {m0: m1} рдФрд░
ymm = {m2: m3} рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред рдкрд╣рд▓реЗ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рдХреЗрд╡рд▓ рдореИрдЯреНрд░рд┐рдХреНрд╕ рдХреЙрд▓рдо рдереЗ, рдФрд░ рдЕрдм рдХреЙрд▓рдо рдФрд░ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рд╣реИрдВред
рдпрджрд┐ рдЖрдк рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рдХрд╛рд░реНрдп рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ
ymm = {m0: m1} рдХреЛ рд░рдЬрд┐рд╕реНрдЯрд░
ymm = {n00, n00, n00, n00} рд╕реЗ рдЧреБрдгрд╛ рдХрд░рдирд╛ рд╣реЛрдЧрд╛
: {n10, n10, n10, n10} ред рдЪреВрдВрдХрд┐
n00 рдФрд░
n01 рдореИрдЯреНрд░рд┐рдХреНрд╕
n рдХреА рдПрдХ рд╣реА рдкрдВрдХреНрддрд┐ рдореЗрдВ рд╣реИрдВ, рдПрд╡реАрдПрдХреНрд╕ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рдЙрдкрд▓рдмреНрдз рд╕реЗрдЯ рдХреЛ рджреЗрдЦрддреЗ рд╣реБрдП, рдЙрдиреНрд╣реЗрдВ
рдпрдо рджреНрд╡рд╛рд░рд╛
рдмрд┐рдЦреЗрд░рдирд╛ рдорд╣рдВрдЧрд╛ рд╣реЛрдЧрд╛ред
рд╢рдлрд▓ рдФрд░
рдкрд░рдорд┐рдЯ рджреЛрдиреЛрдВ
рдпрдо рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдХреЗ рдЕрдВрджрд░ рдПрдХ рдлреНрд▓реЛрдЯ (рдЙрдЪреНрдЪ рдФрд░ рдирд┐рдореНрди
рдПрдХреНрд╕рдПрдордПрдо ) рдХреЗ рджреЛ рдЪрд╛рд░ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ рд╕реЗ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред
рдпрджрд┐ рд╣рдо рдореИрдЯреНрд░рд┐рдХреНрд╕
n рд╕реЗ
ymm рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рджреЛрдиреЛрдВ рддрддреНрд╡реЛрдВ
n00 рдФрд░
n10 рдХреЛ
ymm рд░рдЬрд┐рд╕реНрдЯрд░ рдХреЗ рдЕрдВрджрд░ рдЕрдзрд┐рдХрддрдо 2
xmm рдореЗрдВ
рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред
{n00, n10, n20, n30}: {n01, n11, n21, n31} ред рдЖрдорддреМрд░ рдкрд░, рдореМрдЬреВрджрд╛ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП рд╕реВрдЪрдХрд╛рдВрдХ 0 рд╕реЗ 3 рддрдХ рд╣реЛрддрд╛ рд╣реИред рдФрд░ рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдХреЗрд╡рд▓ рдПрдХ
xmm рд░рдЬрд┐рд╕реНрдЯрд░ рдХреЗ рдЕрдВрджрд░ рджреЛ
ymm рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рд╕реЗ
рддреИрд░рддрд╛ рд╣реИ ред
рд╕рд╕реНрддреЗ рдореЗрдВ рдкреБрд░рд╛рдиреЗ
xmm рд╕реЗ
n10 рдХреЛ
рд╕рд╕реНрддреЗ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИред рдФрд░ рдлрд┐рд░ рдЗрд╕ рдлреЛрдХрд╕ рдХреЛ рдХрдИ рдмрд╛рд░ рджреЛрд╣рд░рд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рд╣рдо рдЗрд╕ рддрд░рд╣ рдХреЗ рдиреБрдХрд╕рд╛рди рд╕реЗ рдирд╣реАрдВ рдЬреВрдЭ рд╕рдХрддреЗред рдХреБрдЫ рдФрд░ рдХреЗ рд╕рд╛рде рдЖрдирд╛ рдЬрд░реВрд░реА рд╣реИред
рд╣рдо рд╕реНрддрдВрднреЛрдВ рдХреЛ рд╕рд╛рдорд╛рдиреНрдп рдХрд░рддреЗ рдереЗ, рд▓реЗрдХрд┐рди рдЕрдм рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рддрд░реАрдХреЗ рд╕реЗ рдЬрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ
{r0: r1} рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рдпрд╣ рд╣реИ рдХрд┐ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреА рдЕрд▓рдЧ-рдЕрд▓рдЧ рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рдирд╣реАрдВ, рдмрд▓реНрдХрд┐ рдПрдХ рд╕рд╛рде рджреЛ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдФрд░ рдпрд╣рд╛рдБ, рдХреНрдпрд╛
рдлреЗрд░рдмрджрд▓ рдФрд░
рдкрд░рдорд┐рдЯ рдХреЗ рдХрд╛рдо рдореЗрдВ рдПрдХ рд╢реВрдиреНрдп рдерд╛ рдЬреЛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдПрдХ рдкреНрд▓рд╕ рд╣реЛрдЧрд╛ред рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдЬрдм рд╣рдо рдореИрдЯреНрд░рд┐рдХреНрд╕
рдПрди рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕
рдпрдо рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрдЧрд╛ред
n0n1 = {00, 10, 20, 30} : {01, 11, 21, 31} n2n3 = {02, 12, 22, 32} : {03, 13, 23, 33}
рд╣рд╛рдБ, рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐
ymm register рдХреЗ рд╡рд┐рднрд┐рдиреНрди
xmm рднрд╛рдЧреЛрдВ рдореЗрдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕
00 рдФрд░
01 рддрддреНрд╡ рд╣реИрдВред рдЙрдиреНрд╣реЗрдВ
{_00, _00, _00, _00} рдореЗрдВ рдкрд░рдорд┐рдЯ рдХрдорд╛рдВрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░рдХреЗ рдЧреБрдгрд╛ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ
: {_ 01, _01, _01, _01} , рджреЛрдиреЛрдВ
xmm рднрд╛рдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ рдПрдХ рдЗрдВрдбреЗрдХреНрд╕ 3 рдХреЛ
рджрд░реНрд╢рд╛рддрд╛ рд╣реИ ред рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдПред рджрд░рдЕрд╕рд▓, рдЧреБрдгрд╛рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд┐рднрд┐рдиреНрди рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рднреА рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЧреБрдгрди рдХреЗ рд▓рд┐рдП рд╕рдВрдмрдВрдзрд┐рдд
рдпрдо рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рдЕрдм рдХреЗрд╡рд▓
{m0: m0} , рдпрд╛рдиреА рдореИрдЯреНрд░рд┐рдХреНрд╕
m рдХреА рдбреБрдкреНрд▓реАрдХреЗрдЯреЗрдб рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рдХреЛ рд░рдЦрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛ред
рдЗрд╕рд▓рд┐рдП, рд╣рдо рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдЪрд┐рддреНрд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рд╣рдо
ymm рд░рдЬрд┐рд╕реНрдЯрд░реЛрдВ рдореЗрдВ рдореИрдЯреНрд░рд┐рдХреНрд╕
m рдХреА рджреЛрд╣рд░реА рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ
рдкрдврд╝рддреЗ рд╣реИрдВ:
mm[0] = {m0:m0} mm[1] = {m1:m1} mm[2] = {m2:m2} mm[3] = {m3:m3}
рдФрд░ рдлрд┐рд░ рд╣рдо рдЧреБрдгрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВрдЧреЗ:
r0r1 = mm[0] * {n00,n00,n00,n00:n01,n01,n01,n01} + // permute<3,3,3,3>(n0n1) mm[1] * {n10,n10,n10,n10:n11,n11,n11,n11} + // permute<2,2,2,2>(n0n1) mm[2] * {n20,n20,n20,n20:n21,n21,n21,n21} + // permute<1,1,1,1>(n0n1) mm[3] * {n30,n30,n30,n30:n31,n31,n31,n31} // permute<0,0,0,0>(n0n1) r2r3 = mm[0] * {n02,n02,n02,n02:n03,n03,n03,n03} + // permute<3,3,3,3>(n2n3) mm[1] * {n12,n12,n12,n12:n13,n13,n13,n13} + // permute<2,2,2,2>(n2n3) mm[2] * {n22,n22,n22,n22:n23,n23,n23,n23} + // permute<1,1,1,1>(n2n3) mm[3] * {n32,n32,n32,n32:n33,n33,n33,n33} // permute<0,0,0,0>(n2n3)
рд╣рдо рдФрд░ рдЕрдзрд┐рдХ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:
r0r1 = mm[0]*n0n1<3,3,3,3>+mm[1]*n0n1<2,2,2,2>+mm[2]*n0n1<1,1,1,1>+mm[3]*n0n1<0,0,0,0> r2r3 = mm[0]*n2n3<3,3,3,3>+mm[1]*n2n3<2,2,2,2>+mm[2]*n2n3<1,1,1,1>+mm[3]*n2n3<0,0,0,0>
рдпрд╛ рд╕рд░рд▓реАрдХреГрдд рд░реВрдк рдореЗрдВ:
r0r1 = mm[0]*n0n1<3> + mm[1]*n0n1<2> + mm[2]*n0n1<1> + mm[3]*n0n1<0> r2r3 = mm[0]*n2n3<3> + mm[1]*n2n3<2> + mm[2]*n2n3<1> + mm[3]*n2n3<0>
рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдиреЗ рд▓рдЧрддрд╛ рд╣реИред
рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ void mul_mtx4_mtx4_avx_v1(__m128* const r, __m128 const* const m, __m128 const* const n) { __m256 mm0 = _mm256_set_m128(m[0], m[0]); __m256 mm1 = _mm256_set_m128(m[1], m[1]); __m256 mm2 = _mm256_set_m128(m[2], m[2]); __m256 mm3 = _mm256_set_m128(m[3], m[3]); __m256 n0n1 = _mm256_load_ps(&n[0].m128_f32[0]); __m256 y1 = _mm256_permute_ps(n0n1, 0xFF);
рдпрд╣рд╛рдБ IACA рд╕реЗ рд░реЛрдЪрдХ рд╕рдВрдЦреНрдпрд╛рдПрдБ рд╣реИрдВ:
x86 - 12.53, x64 - 12 ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдореИрдВ рдмреЗрд╣рддрд░ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдХреБрдЫ рдпрд╛рдж рдЖрдпрд╛ред
рдПрд╡реАрдПрдХреНрд╕ рдСрдкреНрдЯрд┐рдорд╛рдЗрдЬрд╝реЗрд╢рди рдкреНрд▓рд╕ рд╕рд┐рдВрдереИрдЯрд┐рдХ рд╢реБрдЧрд░
рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ, AVX рдХреЛ рдЗрд╕рдХреА рдкреВрд░реА рдХреНрд╖рдорддрд╛ рдХреЗ рд▓рд┐рдП рдЗрд╕реНрддреЗрдорд╛рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рд╣рдо рдкрд╛рддреЗ рд╣реИрдВ рдХрд┐
рдпрдо рд░рдЬрд┐рд╕реНрдЯрд░ рдореЗрдВ рджреЛ рд╕рдорд╛рди рд░реЗрдЦрд╛рдПрдБ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рдмрдЬрд╛рдп, рд╣рдо
рдкреНрд░рд╕рд╛рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рджреЛ рд╕рдорд╛рди
рдорд┐рдореА рдорд╛рдиреЛрдВ рдХреЗ рд╕рд╛рде
рдпрдо рд░рдЬрд┐рд╕реНрдЯрд░ рднрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд░рд╛рд╕реНрддреЗ рдореЗрдВ, AVX рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдХреБрдЫ "рд╕рд┐рдВрдЯреИрдХреНрдЯрд┐рдХ рд╢реБрдЧрд░" рдЬреЛрдбрд╝реЗрдВред
рдЙрдиреНрдирдд AVX рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди __m256 operator + (__m256 const a, __m256 const b) { return _mm256_add_ps(a, b); } __m256 operator - (__m256 const a, __m256 const b) { return _mm256_sub_ps(a, b); } __m256 operator * (__m256 const a, __m256 const b) { return _mm256_mul_ps(a, b); } __m256 operator / (__m256 const a, __m256 const b) { return _mm256_div_ps(a, b); } template <int i> __m256 perm(__m256 const v) { return _mm256_permute_ps(v, _MM_SHUFFLE(i, i, i, i)); } template <int a, int b, int c, int d> __m256 perm(__m256 const v) { return _mm256_permute_ps(v, _MM_SHUFFLE(a, b, c, d)); } template <int i, int j> __m256 perm(__m256 const v) { return _mm256_permutevar_ps(v, _mm256_set_epi32(i, i, i, i, j, j, j, j)); } template <int a, int b, int c, int d, int e, int f, int g, int h> __m256 perm(__m256 const v) { return _mm256_permutevar_ps(v, _mm256_set_epi32(a, b, c, d, e, f, g, h)); } __m256 mad(__m256 const a, __m256 const b, __m256 const c) { return _mm256_add_ps(_mm256_mul_ps(a, b), c); } void mul_mtx4_mtx4_avx_v2(__m128* const r, __m128 const* const m, __m128 const* const n) { __m256 const mm[] { _mm256_broadcast_ps(m+0), _mm256_broadcast_ps(m+1), _mm256_broadcast_ps(m+2), _mm256_broadcast_ps(m+3) }; __m256 const n0n1 = _mm256_load_ps(&n[0].m128_f32[0]); _mm256_stream_ps(&r[0].m128_f32[0], mad(perm<3>(n0n1), mm[0], perm<2>(n0n1)*mm[1])+ mad(perm<1>(n0n1), mm[2], perm<0>(n0n1)*mm[3])); __m256 const n2n3 = _mm256_load_ps(&n[2].m128_f32[0]); _mm256_stream_ps(&r[2].m128_f32[0], mad(perm<3>(n2n3), mm[0], perm<2>(n2n3)*mm[1])+ mad(perm<1>(n2n3), mm[2], perm<0>(n2n3)*mm[3])); }
рдФрд░ рдпрд╣рд╛рдВ рдкрд░рд┐рдгрд╛рдо рдкрд╣рд▓реЗ рд╕реЗ рдЕрдзрд┐рдХ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИрдВред IACA рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рддрд╛ рд╣реИ:
x86 - 10, x64 - 8.58 , рдЬреЛ рдмрд╣реБрдд рдмреЗрд╣рддрд░ рджрд┐рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА 2 рдмрд╛рд░ рдирд╣реАрдВред
AVX + FMA рд╡рд┐рдХрд▓реНрдк (рдЕрдВрддрд┐рдо)
рдЪрд▓рд┐рдП рдПрдХ рдФрд░ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рдЕрдм рдПрдПрдордПрдХреНрд╕ рдХреЗ рдмрд╛рдж рдЗрд╕реЗ рдкреНрд░реЛрд╕реЗрд╕рд░ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рдерд╛, рдлрд┐рд░ рд╕реЗ рдПрдлрдПрдордП рдирд┐рд░реНрджреЗрд╢ рдХреЛ рдлрд┐рд░ рд╕реЗ рдпрд╛рдж рдХрд░рдирд╛ рддрд░реНрдХрд╕рдВрдЧрдд рд╣реЛрдЧрд╛ред рдмрд╕ рдЕрд▓рдЧ-рдЕрд▓рдЧ
mul + рдХреЛ рдПрдХ рдСрдкрд░реЗрд╢рди рдХреЗ рд▓рд┐рдП
рдЬреЛрдбрд╝реЗрдВ ред рдпрджреНрдпрдкрд┐ рд╣рдо рдЕрднреА рднреА рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЛ рдЕрдиреБрдХреВрд▓рди рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдЕрд╡рд╕рд░ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЧреБрдгрди рдХреЗ рдирд┐рд░реНрджреЗрд╢ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдкреНрд░реЛрд╕реЗрд╕рд░ рдЧреБрдгрди рдХреЗ рд╕рдорд╛рдирд╛рдВрддрд░ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдПред рдЖрдорддреМрд░ рдкрд░ рдореИрдВ рдЕрд╕реЗрдВрдмрд▓рд░ рдореЗрдВ рдЙрддреНрдкрдиреНрди рдХреЛрдб рдХреЛ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреЗрдЦрддрд╛ рд╣реВрдВ рдХрд┐ рдХреМрди рд╕рд╛ рд╡рд┐рдХрд▓реНрдк рдмреЗрд╣рддрд░ рд╣реИред
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдореЗрдВ
рдПрдХ * рдмреА + рд╕реА * рдбреА + рдИ * рдПрдл + рдЬреА * рдПрдЪ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЖрдк рдпрд╣ рдорд╛рдерд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
fma (a, b, fma (c, d, fma (e, f, g * h))) ред рд▓реЗрдХрд┐рди, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рджреЗрдЦрддреЗ рд╣реИрдВ, рдкрд┐рдЫрд▓реЗ рдПрдХ рдХреЛ рдкреВрд░рд╛ рдХрд┐рдП рдмрд┐рдирд╛ рдпрд╣рд╛рдВ рдПрдХ рдСрдкрд░реЗрд╢рди рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИред рдФрд░ рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╣рдо рдпреБрдЧреНрдорд┐рдд рдЧреБрдгрд╛ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рдкрд╛рдПрдВрдЧреЗ, рдХреНрдпреЛрдВрдХрд┐ SIMD рдкрд╛рдЗрдкрд▓рд╛рдЗрди рд╣рдореЗрдВ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИред рдпрджрд┐ рд╣рдо рдЧрдгрдирд╛рдУрдВ рдХреЛ рдереЛрдбрд╝рд╛ рдмрджрд▓ рджреЗрддреЗ рд╣реИрдВ рддреЛ
fma (a, b, c * d) + fma (e, f, g * h) , рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рд╣рдо рдЧрдгрдирд╛ рдХреЛ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдкрд╣рд▓реЗ рджреЛ рд╕реНрд╡рддрдВрддреНрд░ рдЧреБрдгрди рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рджреЛ рд╕реНрд╡рддрдВрддреНрд░
fma рд╕рдВрдЪрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВред
рдПрд╡реАрдПрдХреНрд╕ + рдПрдлрдПрдордП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди __m256 fma(__m256 const a, __m256 const b, __m256 const c) { return _mm256_fmadd_ps(a, b, c); } void mul_mtx4_mtx4_avx_fma(__m128* const r, __m128 const* const m, __m128 const* const n) { __m256 const mm[]{ _mm256_broadcast_ps(m + 0), _mm256_broadcast_ps(m + 1), _mm256_broadcast_ps(m + 2), _mm256_broadcast_ps(m + 3) }; __m256 const n0n1 = _mm256_load_ps(&n[0].m128_f32[0]); _mm256_stream_ps(&r[0].m128_f32[0], fma(perm<3>(n0n1), mm[0], perm<2>(n0n1)*mm[1])+ fma(perm<1>(n0n1), mm[2], perm<0>(n0n1)*mm[3])); __m256 const n2n3 = _mm256_load_ps(&n[2].m128_f32[0]); _mm256_stream_ps(&r[2].m128_f32[0], fma(perm<3>(n2n3), mm[0], perm<2>(n2n3)*mm[1])+ fma(perm<1>(n2n3), mm[2], perm<0>(n2n3)*mm[3])); }
IACA:
x86 - 9.21, x64 - 8 ред рдЕрдм рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ рдХреЛрдИ рд╢рд╛рдпрдж рдХрд╣реЗрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рдмреЗрд╣рддрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ рдХреИрд╕реЗред
рдорд╛рдирдХ
рдореИрдВ рддреБрд░рдВрдд рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рдЗрди рдЖрдВрдХрдбрд╝реЛрдВ рдХреЛ рдЕрдВрддрд┐рдо рд╕рддреНрдп рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рд▓рд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдкрд░реАрдХреНрд╖рдг рдХреЗ рд╕рд╛рде рднреА, рд╡реЗ рдХреБрдЫ рд╕реАрдорд╛рдУрдВ рдХреЗ рднреАрддрд░ рддреИрд░рддреЗ рд╣реИрдВред
рдФрд░ рдЗрд╕рд╕реЗ рднреА рдЕрдзрд┐рдХ рд╡реЗ рд╡рд┐рднрд┐рдиреНрди рдкреНрд▓реЗрдЯрдлрд╛рд░реНрдореЛрдВ рдкрд░ рдЕрд▓рдЧ рддрд░рд╣ рд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рддреЗ рд╣реИрдВред рдХрд┐рд╕реА рднреА рдЕрдиреБрдХреВрд▓рди рдХреЗ рд╕рд╛рде, рдЕрдкрдиреЗ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдорд╛рдк рд▓реЗрдВредрд╕рд╛рдордЧреНрд░реА рдХреА рддрд╛рд▓рд┐рдХрд╛
- рд╕рдорд╛рд░реЛрд╣: рд╕рдорд╛рд░реЛрд╣ рдХрд╛ рдирд╛рдоред рдПрд╕ рдкрд░ рд╕рдорд╛рдкреНрдд - рдПрдХ рд╕реНрдЯреНрд░реАрдорд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕рд╛рдорд╛рдиреНрдп Mov (рд╕реНрдЯреНрд░реАрдорд┐рдВрдЧ рдХреЗ рдмрд┐рдирд╛)ред рд╕реНрдкрд╖реНрдЯрддрд╛ рдХреЗ рд▓рд┐рдП рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдкрд░реНрдпрд╛рдкреНрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИред
- IACA рдЪрдХреНрд░: IACA рджреНрд╡рд╛рд░рд╛ рдЧрдгрдирд╛ рдХреА рдЧрдИ рдкреНрд░рддрд┐ рдлрд╝рдВрдХреНрд╢рди рдЯрд┐рдХ рдХреА рд╕рдВрдЦреНрдпрд╛
- рдорд╛рдкрд╛ рдЪрдХреНрд░: рдорд╛рдкреА рдЧрдИ рд╕рдВрдЦреНрдпрд╛ рдХреА рдорд╛рдк (рдХрдо рдЕрдзрд┐рдХ рд╣реИ)
- IACA рд╕реНрдкреАрдбрдЕрдк: рдПрдХ рд╢реВрдиреНрдп рд░реЗрдЦрд╛ рдореЗрдВ рдЙрдкрд╛рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ / рдПрдХ рдкрдВрдХреНрддрд┐ рдореЗрдВ рдЙрдкрд╛рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛
- рдорд╛рдкрд╛ рдЧрддрд┐: рд╢реВрдиреНрдп рд▓рд╛рдЗрди рдореЗрдВ рдЙрдкрд╛рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ / рд▓рд╛рдЗрди рдореЗрдВ рдЙрдкрд╛рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ (рдЕрдзрд┐рдХ рдмреЗрд╣рддрд░)
рд▓реВрдк_рдо рдХреЗ рд▓рд┐рдП, рд▓реЗрдЦ рдХреЗ рдЯрд┐рдХреНрд╕ рдХреЛ 64 рд╕реЗ рдЧреБрдгрд╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдЕрд░реНрдерд╛рддреН, рдпрд╣ рдПрдХ рдмрд╣реБрдд рд╣реА рдЕрдиреБрдорд╛рдирд┐рдд рдореВрд▓реНрдп рд╣реИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдирд┐рдХрд▓рд╛редi3-3770:
i7-8700K:
рд╕реНрд░реЛрдд рдореЗрдВ рдЯреЗрд╕реНрдЯ рдХреЛрдбред рдпрджрд┐ рдЙрдирдореЗрдВ рд╕реБрдзрд╛рд░ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЙрдЪрд┐рдд рд╕реБрдЭрд╛рд╡ рд╣реИрдВ, рддреЛ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рд▓рд┐рдЦреЗрдВредрдХрд▓реНрдкрдирд╛ рдХреЗ рджрд╛рдпрд░реЗ рд╕реЗ рдЕрд▓рдЧ
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдХрд▓реНрдкрдирд╛ рдХреЗ рджрд╛рдпрд░реЗ рд╕реЗ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдЕрдЧрд░ рдореИрдВрдиреЗ AVX512 рдХреЗ рд▓рд┐рдП рдкреНрд░реЛрд╕реЗрд╕рд░ рджреЗрдЦрд╛, рддреЛ рд╢рд╛рдпрдж рддрд╕реНрд╡реАрд░реЛрдВ рдореЗрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореИрдВрдиреЗ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреАред рдпрд╣рд╛рдВ рдореИрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рд╕рдордЭрд╛рдКрдВрдЧрд╛, рдПрд╡реАрдПрдХреНрд╕ + рдПрдлрдПрдордП рдХреЗ рд╕рд╛рде рдПрдХ рдкреВрд░реНрдг рд╕рд╛рджреГрд╢реНрдпред рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдПрдХ рд╣реА рд╣реИ, рдХреЗрд╡рд▓ рдХрдо рд╕рдВрдЪрд╛рд▓рдиредрдЬреИрд╕рд╛ рдХрд┐ рд╡реЗ рдХрд╣рддреЗ рд╣реИрдВ, рдореИрдВ рдЗрд╕реЗ рдпрд╣рд╛рдБ рдЫреЛрдбрд╝ рджреВрдБрдЧрд╛ __m512 operator + (__m512 const a, __m512 const b) { return _mm512_add_ps(a, b); } __m512 operator - (__m512 const a, __m512 const b) { return _mm512_sub_ps(a, b); } __m512 operator * (__m512 const a, __m512 const b) { return _mm512_mul_ps(a, b); } __m512 operator / (__m512 const a, __m512 const b) { return _mm512_div_ps(a, b); } template <int i> __m512 perm(__m512 const v) { return _mm512_permute_ps(v, _MM_SHUFFLE(i, i, i, i)); } template <int a, int b, int c, int d> __m512 perm(__m512 const v) { return _mm512_permute_ps(v, _MM_SHUFFLE(a, b, c, d)); } __m512 fma(__m512 const a, __m512 const b, __m512 const c) { return _mm512_fmadd_ps(a, b, c); } void mul_mtx4_mtx4_avx512(__m128* const r, __m128 const* const m, __m128 const* const _n) { __m512 const mm[]{ _mm512_broadcast_f32x4(m[0]), _mm512_broadcast_f32x4(m[1]), _mm512_broadcast_f32x4(m[2]), _mm512_broadcast_f32x4(m[3]) }; __m512 const n = _mm512_load_ps(&_n[0].m128_f32[0]); _mm512_stream_ps(&r[0].m128_f32[0], fma(perm<3>(n), mm[0], perm<2>(n)*mm[1])+ fma(perm<1>(n), mm[2], perm<0>(n)*mm[3])); }
рд╕рдВрдЦреНрдпрд╛ рд╢рд╛рдирджрд╛рд░ рд╣реИрдВ: x86 - 4.79, x64 - 5.42 (SKX рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХреЗ рд╕рд╛рде IACA)ред рдЗрд╕ рддрдереНрдп рдХреЗ рдмрд╛рд╡рдЬреВрдж рдХрд┐ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдореЗрдВ 64 рдЧреБрдгрд╛ рдФрд░ 48 рдЬреЛрдбрд╝ рд╣реИрдВредрд▓реЗрдЦ рд╕реЗ PS рдХреЛрдб
рдпрд╣ рдПрдХ рд▓реЗрдЦ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдореЗрд░рд╛ рдкрд╣рд▓рд╛ рдЕрдиреБрднрд╡ рд╣реИред рдЖрдкрдХреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЖрдк рд╕рднреА рдХрд╛ рдзрдиреНрдпрд╡рд╛рджред рд╡реЗ рдХреЛрдб рдФрд░ рд▓реЗрдЦ рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддреЗ рд╣реИрдВред