জিরসির সামগ্রীর সূচনা কেন শূন্য নয় এমন উপাদানগুলি সহ জিরো দিয়ে প্রথমে পুরো জিনিসটি পূরণ করে?


21

জিসিসি কেন কেবলমাত্র বাকি ৯৯ টি পূর্ণসংখ্যার পরিবর্তে পুরো অ্যারে জিরো দিয়ে পূরণ করে? অ-শূন্য শুরুর দিকের অ্যারেগুলির শুরুতে।

void *sink;
void bar() {
    int a[100]{1,2,3,4};
    sink = a;             // a escapes the function
    asm("":::"memory");   // and compiler memory barrier
    // forces the compiler to materialize a[] in memory instead of optimizing away
}

মিনজিডব্লিউ 8.1 এবং জিসিসি 9.2 উভয়ই এ্যাসএম তৈরি করে ( গডবোল্ট সংকলক এক্সপ্লোরার )।

# gcc9.2 -O3 -m32 -mno-sse
bar():
    push    edi                       # save call-preserved EDI which rep stos uses
    xor     eax, eax                  # eax=0
    mov     ecx, 100                  # repeat-count = 100
    sub     esp, 400                  # reserve 400 bytes on the stack
    mov     edi, esp                  # dst for rep stos
        mov     DWORD PTR sink, esp       # sink = a
    rep stosd                         # memset(a, 0, 400) 

    mov     DWORD PTR [esp], 1        # then store the non-zero initializers
    mov     DWORD PTR [esp+4], 2      # over the zeroed part of the array
    mov     DWORD PTR [esp+8], 3
    mov     DWORD PTR [esp+12], 4
 # memory barrier empty asm statement is here.

    add     esp, 400                  # cleanup the stack
    pop     edi                       # and restore caller's EDI
    ret

(এসএসই সক্ষম করে এটি মুভিডকা লোড / স্টোর সহ সমস্ত 4 টি আরম্ভকারীকে অনুলিপি করবে)

জিসিসি কেন lea edi, [esp+16]ক্লাংয়ের rep stosdমতো কেবল সর্বশেষ 96 টি উপাদানকে স্মরণ করে না (দিয়ে )? এটি কি কোনও মিসড অপটিমাইজেশন, না এইভাবে এটি করা কোনওরকম আরও দক্ষ? (ঝাঁকুনি আসলে memsetইনলাইনিংয়ের পরিবর্তে কল করে rep stos)


সম্পাদকের দ্রষ্টব্য: প্রশ্নটির মূলত অ-অপটিমাইজড সংকলক আউটপুট ছিল যা একইভাবে কাজ করেছিল, তবে অক্ষম কোডটিতে -O0কোনও কিছুই প্রমাণিত হয় না। তবে দেখা যাচ্ছে যে এই অপ্টিমাইজেশনটি এমনকি জিসিসি দ্বারা মিস হয়েছে -O3

aএকটি অন-ইনলাইন ফাংশনে একটি পয়েন্টার পাস করা সংকলককে বাস্তবায়িত করতে বাধ্য করার অন্য উপায় হতে পারে a[], তবে 32-বিট কোডে যা asm এর উল্লেখযোগ্য বিশৃঙ্খলা বাড়ে। (স্ট্যাক আরোগুলির ফলে পুশ হয়, যা স্টোরের সাথে অ্যারের সূচনা করতে স্টোরগুলিতে মিশে যায়))

ব্যবহার করে volatile a[100]{1,2,3,4}জিসিসি পায় অ্যারে তৈরি এবং তারপরে অনুলিপি , যা উন্মাদ। সাধারণত volatileকম্পাইলাররা স্থানীয় ভেরিয়েবলগুলি কীভাবে শুরু করে বা স্ট্যাকের উপরে রাখে তা দেখার জন্য সাধারণত ভাল।


1
@ দামিয়ান আপনি আমার প্রশ্নকে ভুল বুঝেছেন। আমি জিজ্ঞাসা করি কেন উদাহরণস্বরূপ কেন [[]] এর দ্বিগুণ মূল্য নির্ধারিত হয় যদি a[0] = 0;এবং তারপরে a[0] = 1;
ল্যাসি

1
আমি অ্যাসেম্বলিটি পড়তে পারছি না, তবে এটি কোথায় দেখায় যে অ্যারে পুরো শূন্যে পূর্ণ?
smac89

3
আরও একটি আকর্ষণীয় সত্য: আরও আইটেমের জন্য আরম্ভ করা, জিসিসি এবং ক্ল্যাং উভয়ই পুরো অ্যারে থেকে অনুলিপি করতে ফিরে আসে .rodata... আমি বিশ্বাস করতে পারি না 400 বাইট অনুলিপি করা শূন্যের চেয়ে 8 টি আইটেম সেট করার চেয়ে দ্রুত।
জেসেটার

2
আপনি অপ্টিমাইজেশন অক্ষম করেছেন; অযোগ্য কোডটি অবাক করা অবধি অবধি অবধি নয় যে আপনি যাচাই না করে একই জিনিসটি ঘটে -O3(যা এটি করে)। Godbolt.org/z/rh_TNF
পিটার

12
আপনি আরও কি জানতে চান? এটি একটি মিসড অপটিমাইজেশন, missed-optimizationকীওয়ার্ড সহ এটি জিসিসির বাগজিলায় রিপোর্ট করুন ।
পিটার

উত্তর:


2

তাত্ত্বিকভাবে আপনার সূচনাটি দেখতে দেখতে দেখতে পারে:

int a[100] = {
  [3] = 1,
  [5] = 42,
  [88] = 1,
};

সুতরাং এটি পুরো মেমরির ব্লকটি শূন্য করে প্রথমে স্বতন্ত্র মান নির্ধারণের ক্ষেত্রে ক্যাশে এবং অপ্টিমাইজিবিলিটি বিবেচনায় আরও কার্যকর হতে পারে।

উপর নির্ভর করে আচরণের পরিবর্তন হতে পারে:

  • লক্ষ্য আর্কিটেকচার
  • লক্ষ্য ওএস
  • অ্যারে দৈর্ঘ্য
  • প্রারম্ভিক অনুপাত (সুস্পষ্টভাবে আরম্ভিত মান / দৈর্ঘ্য)
  • আরম্ভ করা মানগুলির অবস্থান

অবশ্যই, আপনার ক্ষেত্রে সূচনাটি অ্যারের শুরুতে কমপ্যাক্ট করা হয়েছে এবং অপ্টিমাইজেশনটি তুচ্ছ হবে।

সুতরাং দেখে মনে হয় যে এখানে সিসিটি সবচেয়ে জেনেরিক পন্থা করছে। মনে হচ্ছে নিখোঁজ অপ্টিমাইজেশন।


হ্যাঁ, এই কোডটির জন্য একটি সর্বোত্তম কৌশল সম্ভবত সমস্ত কিছু শূন্যের হতে পারে, বা সম্ভবত a[6]প্রথম দিকের শুরু থেকে শুরু হওয়া শূন্যস্থানগুলির সাথে একক স্টোরেজ বা জিরোগুলির একক স্টোরগুলি পূর্ণ। বিশেষত যদি x86-64 টার্গেট করে তাই আপনি একবারে 2 টি উপাদান করার জন্য কিওয়ার্ড স্টোরগুলি ব্যবহার করতে পারেন, নিম্নটি ​​একটি শূন্য নয়। উদাহরণস্বরূপ mov QWORD PTR [rsp+3*4], 1একটি বিভ্রান্ত কিওয়ার্ড স্টোর দিয়ে 3 এবং 4 উপাদানগুলি করা।
পিটার কর্ডেস

আচরণ তাত্ত্বিকভাবে লক্ষ্যযুক্ত ওএসের উপর নির্ভর করতে পারে, তবে প্রকৃত জিসিসিতে এটি হবে না এবং এর কোনও কারণ নেই। শুধুমাত্র টার্গেট আর্কিটেকচার (এবং এর মধ্যে, -march=skylakeবনাম -march=k8বনাম এর মতো বিভিন্ন মাইক্রো আর্কিটেকচারের জন্য টিউনিং বিকল্পগুলি -march=knlসাধারণভাবে খুব আলাদা হবে, এবং সম্ভবত এটির জন্য উপযুক্ত কৌশলের দিক
থেকেও

এটি কি এমনকি সি ++ এ অনুমোদিত? আমি ভেবেছিলাম এটি কেবল সি।
ল্যাসি

@ ল্যাসি আপনি সি ++ এ ঠিক আছেন এটি অনুমোদিত নয় তবে প্রশ্নটি সংকলক ব্যাকএন্ডের সাথে আরও সম্পর্কিত, যাতে এটি এতটা গুরুত্বপূর্ণ না। প্রদর্শিত কোড উভয়ই হতে পারে
vlad_tepesch

এমনকি আপনি সহজেই এমন কিছু উদাহরণ তৈরি করতে পারেন যা সি ++ তে একই রকম কাজ করে কিছু ঘোষণা করে struct Bar{ int i; int a[100]; int j;} এবং Bar a{1,{2,3,4},4};
সিসিটি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.