Visual Studio 2017: _mm_load_ps มักจะคอมไพล์เป็น movups

ฉันกำลังดูแอสเซมบลีที่สร้างขึ้นสำหรับโค้ดของฉัน (โดยใช้ Visual Studio 2017) และสังเกตเห็นว่า _mm_load_ps มักจะ (เสมอ?) คอมไพล์เป็น movups

ข้อมูลที่ฉันใช้ _mm_load_ps มีการกำหนดดังนี้:

struct alignas(16) Vector {
    float v[4];
}

// often embedded in other structs like this
struct AABB {
    Vector min;
    Vector max;
    bool intersection(/* parameters */) const;
}

ตอนนี้เมื่อฉันใช้โครงสร้างนี้ สิ่งต่อไปนี้จะเกิดขึ้น:

// this code
__mm128 bb_min = _mm_load_ps(min.v);

// generates this
movups  xmm4, XMMWORD PTR [r8]

ฉันคาดหวังว่าจะมีการเคลื่อนย้ายเนื่องจาก alignas(16) ฉันจำเป็นต้องมีอย่างอื่นอีกหรือไม่เพื่อโน้มน้าวให้คอมไพเลอร์ใช้ momaps ในกรณีนี้?

แก้ไข: คำถามของฉันแตกต่างจากคำถามนี้ เพราะฉันไม่ได้รับข้อขัดข้องใด ๆ โครงสร้างมีการจัดตำแหน่งโดยเฉพาะและฉันก็ใช้การจัดสรรแบบจัดตำแหน่งด้วย แต่ฉันสงสัยว่าเหตุใดคอมไพเลอร์จึงเปลี่ยน _mm_load_ps (ที่แท้จริงสำหรับหน่วยความจำที่จัดตำแหน่ง) เป็น movups ถ้าฉันรู้ว่าโครงสร้างได้รับการจัดสรรตามที่อยู่ที่สอดคล้องกันและฉันกำลังเรียกมันผ่านทาง this* มันจะปลอดภัยที่จะใช้ momaps ใช่ไหม?


person B_old    schedule 09.03.2017    source แหล่งที่มา
comment
คุณต้องการ movaps โดยเฉพาะเพื่อจุดประสงค์ใด   -  person harold    schedule 09.03.2017
comment
@harold เขาย้ายสี่โฟลตและคำสั่งที่จัดตำแหน่งมักจะมีประสิทธิภาพมากกว่าโดยเฉพาะใน cpu บางรุ่น   -  person J...    schedule 09.03.2017
comment
อาจซ้ำกันของ SSE, ภายใน และการจัดตำแหน่ง   -  person J...    schedule 09.03.2017
comment
@เจ...ใช่ Core2. เท่าที่ฉันรู้ไม่สำคัญว่ามีอะไรใหม่กว่านี้ตราบใดที่ที่อยู่นั้นสอดคล้องกันจริงๆ   -  person harold    schedule 09.03.2017
comment
ทีแอลอาร์; alignas ไม่สมบูรณ์แบบหรือเป็นการรับประกัน memcpy สามารถวางโครงสร้างเหล่านี้ไว้ที่ใดก็ได้ (รวมถึงตำแหน่งที่ไม่สอดคล้องกัน) malloc จะไม่ให้หน่วยความจำที่สอดคล้องกันเสมอไป ฯลฯ ดูการหลอกลวง - โดยทั่วไปคุณจะต้องเขียนตัวจัดสรรของคุณเองโดยใช้ _aligned_malloc   -  person J...    schedule 09.03.2017
comment
นอกจากนี้ โปรดอ่านส่วนหมายเหตุที่นี่ (ซึ่งหมายถึง __declspec(align(#)) แต่เนื่องจาก VS2015 alignas มีการใช้การสนับสนุนเป็นแผ่นไม้อัดเหมือนกัน)   -  person J...    schedule 09.03.2017
comment
การสนทนาที่นี่ ก็น่าสนใจเช่นกัน .   -  person B_old    schedule 09.03.2017
comment
ตามคำจำกัดความปลอดภัยที่จะใช้ movaps เพื่อนำไปใช้ _mm_load_ps (โดยไม่คำนึงถึงการจัดตำแหน่งจริง) แต่เห็นได้ชัดว่าไม่ได้เกิดขึ้น   -  person harold    schedule 09.03.2017
comment
@harold: ตกลง แต่นั่นเป็นสิ่งที่ฉันสามารถมีอิทธิพลต่อได้หรือไม่? (นอกเหนือจากการเขียนโค้ดแอสเซมเบลอร์)   -  person B_old    schedule 09.03.2017
comment
คุณต้องแสดงตัวอย่างที่สมบูรณ์ซึ่งแสดงให้เห็นถึงปัญหา รวมถึงตัวเลือกคอมไพเลอร์ที่คุณใช้และเวอร์ชันของ Visual Studio 2017 ที่คุณใช้อยู่   -  person Ross Ridge    schedule 09.03.2017
comment
@harold No movaps จะทำให้เกิดข้อยกเว้นกับที่อยู่ที่ไม่สอดคล้องกันอย่างแน่นอน   -  person J...    schedule 09.03.2017
comment
@J... ใช่และ _mm_load_ps ก็ได้รับอนุญาตให้ทำเช่นนั้นได้เช่นกัน แม้ว่าจะไม่จำเป็นต้องทำก็ตาม   -  person harold    schedule 09.03.2017
comment
บน VS และ ICC หากคุณคอมไพล์สำหรับ AVX หรือสูงกว่า คอมไพเลอร์แทบไม่เคยมีปัญหาเกี่ยวกับโหลด/จัดเก็บ SIMD ที่สอดคล้องกันเลย อนุญาตให้ทำเช่นนั้นได้เนื่องจากไม่สูญเสียฟังก์ชันการทำงาน และโปรเซสเซอร์ทั้งหมดที่เริ่มต้นจาก Nehalem ไม่มีบทลงโทษสำหรับการใช้โหลด/ร้านค้าที่ไม่ได้จัดแนวเมื่อที่อยู่ถูกจัดตำแหน่ง พวกเขาทำเช่นนี้เพราะมันทำให้คอมไพเลอร์ง่ายขึ้น (ไม่ต้องเลือกระหว่างการจัดแนว/ไม่จัดแนว) และจะไม่เกิดปัญหาหากการจัดแนวไม่ตรง แม้ว่าฉันจะไม่เห็นด้วยอย่างยิ่งกับอันหลังนี้ เนื่องจากฉันชอบที่มันผิดพลาดในการวางแนวที่ไม่ตรง เนื่องจากเป็นข้อบกพร่องที่ควรแก้ไข ไม่ใช่ซ่อนไว้   -  person Mysticial    schedule 10.03.2017
comment
@Mystical: นั่นเป็นข้อมูลที่ดี แต่ฉันเพิ่งรวบรวมสำหรับ x64 เช่นเดียวกับที่นั่นหรือไม่?   -  person B_old    schedule 10.03.2017
comment
@Mysticial คำตอบของคุณฟังดูน่าเชื่อสำหรับฉัน อาจโพสต์ไว้เป็นคำตอบจริงหากคุณมีเวลา   -  person Guillaume Gris    schedule 02.08.2017
comment
@GuillaumeGris เสร็จแล้ว   -  person Mysticial    schedule 02.08.2017


คำตอบ (1)


ใน Visual Studio เวอร์ชันล่าสุดและ Intel Compiler (ล่าสุดหลังปี 2013?) คอมไพเลอร์แทบจะไม่เคยสร้างโหลด/จัดเก็บ SIMD ที่สอดคล้องกันอีกต่อไป

เมื่อคอมไพล์สำหรับ AVX หรือสูงกว่า:

  • คอมไพเลอร์ของ Microsoft (>VS2013?) ไม่สร้างโหลดที่สอดคล้อง แต่ก็ยังสร้างร้านค้าที่สอดคล้องกัน
  • คอมไพเลอร์ของ Intel (> Parallel Studio 2012?) ไม่ได้ทำอีกต่อไป แต่คุณจะยังคงเห็นพวกมันอยู่ในไบนารีที่คอมไพล์โดย ICC ภายในไลบรารีที่ปรับให้เหมาะสมด้วยมือเช่น memset()
  • ใน GCC 6.1 มันยังคงสร้างโหลด/ร้านค้าที่สอดคล้องเมื่อคุณใช้อินทรินซิกที่จัดตำแหน่ง

คอมไพลเลอร์ได้รับอนุญาตให้ทำเช่นนี้ได้เนื่องจากไม่สูญเสียฟังก์ชันการทำงานเมื่อเขียนโค้ดอย่างถูกต้อง โปรเซสเซอร์ทั้งหมดที่เริ่มต้นจาก Nehalem ไม่มีค่าปรับสำหรับการโหลด/จัดเก็บที่ไม่ได้จัดตำแหน่งเมื่อที่อยู่ถูกจัดตำแหน่ง

จุดยืนของ Microsoft เกี่ยวกับปัญหานี้ก็คือ "ช่วยโปรแกรมเมอร์โดยไม่ทำให้ระบบขัดข้อง" ขออภัย ฉันไม่พบแหล่งที่มาดั้งเดิมของคำชี้แจงนี้จาก Microsoft อีกต่อไป ในความคิดของฉัน สิ่งนี้บรรลุผลตรงกันข้ามอย่างแน่นอน เพราะมันซ่อนบทลงโทษที่ไม่ตรงแนวไว้ จากจุดยืนด้านความถูกต้อง มันยังซ่อนรหัสที่ไม่ถูกต้องอีกด้วย

ไม่ว่ากรณีจะเป็นเช่นไร การใช้โหลด/ร้านค้าที่ไม่มีเงื่อนไขจะทำให้คอมไพเลอร์ง่ายขึ้นเล็กน้อย

ความสัมพันธ์ใหม่:

  • นับตั้งแต่ Parallel Studio 2018 เป็นต้นไป Intel Compiler จะไม่สร้างการเคลื่อนไหวที่สอดคล้องอีกต่อไป แม้แต่กับเป้าหมายก่อน Nehalem ก็ตาม
  • เริ่มต้นจาก Visual Studio 2017 Microsoft Compiler จะไม่สร้างการเคลื่อนไหวที่สอดคล้องอีกต่อไป - แม้ว่าจะกำหนดเป้าหมายฮาร์ดแวร์ pre-AVX ก็ตาม

ทั้งสองกรณีส่งผลให้ประสิทธิภาพลดลงอย่างหลีกเลี่ยงไม่ได้ในโปรเซสเซอร์รุ่นเก่า แต่ดูเหมือนว่า สิ่งนี้ มีเจตนา เนื่องจากทั้ง Intel และ Microsoft ไม่สนใจโปรเซสเซอร์รุ่นเก่าอีกต่อไป


โหลด/ร้านค้าที่แท้จริงเพียงอย่างเดียวที่ภูมิคุ้มกันต่อสิ่งนี้คือโหลด/ร้านค้าที่ไม่ใช่ชั่วคราว ไม่มีการเทียบเท่าที่ไม่ได้จัดแนว ดังนั้นคอมไพเลอร์จึงไม่มีทางเลือก

ดังนั้นหากคุณต้องการทดสอบความถูกต้องของโค้ดของคุณ คุณสามารถแทนที่โหลด/สโตร์อินทรินซิกสำหรับโค้ดที่ไม่ใช่แบบชั่วคราวได้ แต่ระวังอย่าปล่อยให้บางสิ่งเช่นนี้หลุดลอยไปในโค้ดการผลิต เนื่องจากการโหลด/ร้านค้า NT (โดยเฉพาะร้านค้า NT) เป็นดาบสองคมที่อาจทำร้ายคุณได้หากคุณไม่รู้ว่ากำลังทำอะไรอยู่

person Mysticial    schedule 02.08.2017
comment
ที่เกี่ยวข้อง: gcc ชอบการจัดตำแหน่งจริง ๆ เมื่อทำเวคเตอร์อัตโนมัติ และสเกลาร์ไปจนถึงขอบเขตการจัดตำแหน่ง (ด้วยโค้ดแนะนำ / การล้างข้อมูลที่คลายออกทั้งหมด ซึ่งมีโค้ดขยายจำนวนมากด้วย AVX2 และองค์ประกอบขนาดเล็ก) มันทำเช่นนี้แม้จะมี -mtune=skylake หรืออะไรบางอย่าง อย่างไรก็ตาม การทำให้แน่ใจว่า gcc รู้เกี่ยวกับการรับประกันการจัดตำแหน่งใดๆ ที่คุณสามารถให้ได้ จะช่วยลดการขยายตัวของโค้ด และหลีกเลี่ยงการแตกแขนงแบบมีเงื่อนไขหรือสองอย่างเมื่อทำการเวคเตอร์อัตโนมัติ - person Peter Cordes; 03.08.2017
comment
โหลด NT บนหน่วยความจำเขียนกลับจะทำงานเหมือนกันทุกประการกับโหลดปกติทุกประการ บนตระกูล Intel Sandybridge เป็นอย่างน้อย พวกเขาสามารถทำให้มันทำงานเหมือนกับ prefetchNTA ได้ แต่ก็ไม่ได้ (อาจเป็นเพราะมันต้องใช้ตัวดึงล่วงหน้าฮาร์ดแวร์ที่รับรู้ NT ว่าจะไม่ดูด) (กำลังดำเนินการอัปเดตเป็น stackoverflow.com/questions/32103968/; ปรากฎว่าฉันเดาผิดว่ามันทำบางอย่างเช่นการดึงข้อมูลลงในแคชวิธีเดียวเท่านั้นเพื่อหลีกเลี่ยงมลภาวะ มีเพียง pfNTA เท่านั้นที่ทำอย่างนั้น .) - person Peter Cordes; 03.08.2017
comment
@PeterCordes ที่น่าสนใจคือปริมาณงานโหลด NT เพียง 1/รอบบน Skylake X เมื่อเทียบกับ 2/รอบสำหรับโหลดอื่นทั้งหมด (ตาม AIDA64) - person Mysticial; 03.08.2017
comment
บน Skylake-S (เดสก์ท็อป) โหลดซ้ำ 64 ไบต์เดิมด้วย movntdqa xmm0, [rsi] / movntdqa xmm1, [rsi+16] ฯลฯ โดยจะรัน ~1.71 ต่อนาฬิกา เทียบกับ 2.0 ต่อนาฬิกาสำหรับ movdqa ดังนั้นแม้จะเป็นเรื่องเล็กน้อยที่สุด แต่ก็ช้ากว่า ขอบคุณที่ชี้ให้เห็นว่า - person Peter Cordes; 03.08.2017
comment
ตัวเลข AIDA64 เหล่านั้นแสดงว่า AVX512 EVEX vmovntdqa (1 ต่อ 1.08) แตกต่างจาก SSE ปกติหรือ AVX VEX movntdqa (1 ต่อ 0.52) และ EVEX VMOVNTDQA + VMOVNTDQ x/y/zmm การโหลด/จัดเก็บนั้นยังคงมีเวลาแฝงที่แย่มาก แต่ปริมาณงานคือ 1 ต่อ ~19.25c แทนที่จะเท่ากับเวลาแฝง (และเวลาแฝงของการจัดเก็บ/โหลดซ้ำของ ZMM NT นั้นต่ำกว่าอีกสองขนาด ซึ่งเป็นอีกนัยหนึ่งว่าร้านค้า NT แบบแคชเต็มไลน์มีความพิเศษ การมีแบนด์วิดท์แบบเธรดเดี่ยวที่สูงกว่าร้านค้า NT ที่แคบกว่ามากถือเป็นคำใบ้สำคัญอยู่แล้ว) - person Peter Cordes; 03.08.2017
comment
ใช่. ฉันไม่ได้พยายามที่จะคิดออกว่ามีอะไรเปลี่ยนแปลงอยู่ข้างใต้ แต่เมื่อฉันสลับ NT-store ในโค้ดของฉัน ความแตกต่างนั้นรุนแรงมาก (ประมาณ 10 - 15%) นี่เป็นมากกว่าสิ่งที่ฉันเห็นในแฮสเวลล์ จริงอยู่ที่ว่าส่วนใหญ่อาจเกี่ยวข้องกับคอขวดแบนด์วิธหน่วยความจำโดยรวม - person Mysticial; 03.08.2017
comment
เกี่ยวกับการซ่อนการลงโทษที่ไม่ตรง: สิ่งนี้จะเกิดขึ้นกับ clang/gcc และ AVX หาก _mm_load[u]_ps สามารถหลอมรวมเข้ากับการดำเนินการอื่นได้ (เช่น vaddps): godbolt.org/z/2ZL5FQ ดังนั้น จึงไม่ใช่เรื่องเล็กน้อยเสมอไปที่จะบังคับให้ clang/gcc สร้างคำสั่ง [v]movaps จริงๆ - person chtz; 15.05.2020