Як рядки коду виконуються процесором?


11

Я намагаюся реально зрозуміти, як саме мова високого рівня перетворюється в машинний код і потім виконується процесором.

Я розумію, що код складається в машинний код, який є кодом низького рівня, який може використовувати процесор. Якщо у мене є заява про призначення, скажіть:

x = x + 5;
y = x - 3;

Чи виконує процесор кожний рядок один за одним? Тож спочатку буде виконано x = x + 5; інструкція, а потім наступна інструкція, яку виконає процесор, - y = x- 3; Я дійсно намагаюся зрозуміти процес виконання і те, як код, який я пишу, насправді виконується процесором.


Ви можете спробувати розібратися в дизайні одного з процесорів з відкритим кодом. Є кілька дійсно простих реалізацій на основі стека, таких як excamera.com/sphinx/fpga-j1.html - вони набагато простіші, ніж архітектури з 3 адресами як у вашому прикладі.
SK-логіка

3
Коли я зайнявся цим бізнесом, на це були б прості і чітко визначені відповіді. На сьогоднішній день процесори надзвичайно складні і роблять всілякі речі, щоб збільшити потужність обробки.
Девід Торнлі

Відповіді:


12

Рядки коду не мають нічого спільного з тим, як ЦП виконує його. Я рекомендую прочитати на асемблері, оскільки це навчить вас багато чому про те, як апаратно насправді робить справи. Ви також можете отримати вихід асемблера від багатьох компіляторів.

Цей код може компілюватись у щось на зразок (на складеній мові складання):

load R1, [x] ; meaning load the data stored at memory location x into register 1
add R1, 5
store [x], R1 ; store the modified value into the memory location x
sub R1, 3
store R1, [y]

Однак якщо компілятор знає, що змінна не використовується знову, операція зберігання може не випускатися.

Тепер, щоб налагоджувач дізнався, який машинний код відповідає рядку програмного джерела, компілятор додає анотації, щоб показати, яка лінія відповідає де в машинному коді.


Чому ні? 3-адресна архітектура матиме вказівки типу ADD Rx, Rx, $5та SUB Ry, Rx, $3(якщо припустити, що змінні x і y були відображені в регістри). Ви описуєте підхід RISC для завантаження / зберігання.
SK-логіка

1
@ SK-логіка: Хоча це може статися для дуже простих рядків коду в дуже простих мовах програмування з типами даних і операціями, процесор, як правило, підтримує досить добре, це ніде загальний випадок. Це зручно для експертів, але спочатку важливо усвідомити інструкції машинного коду, як правило, мало схожі на рядки коду у високому рівні.

@ SK-Logic: це працює лише для цього конкретного прикладу. В цілому, правда, maxpolun має рацію. Мовні висловлювання на високому рівні повинні бути перекладені на мову нижчого рівня з більшою кількістю «червоних стрічок», необхідних для того, щоб робити концептуально прості речі. Я думаю, що ОП просила приклад цієї трансформації.
Андрес Ф.

1
@ SK-Logic: ОП розпочало своє запитання з "Я намагаюся реально зрозуміти, як саме мова високого рівня [...]"
Андрес Ф.

1
@ SK-логіка Контекст: "Якщо у мене є заява про призначення, скажімо: [фрагмент коду] Чи виконує ЦП кожен рядок один за одним?" - мені здається, ніби він призначений для вихідного коду мовою, що не збирається. Загалом, я не бачу жодного показника розуміння того, як машинний код низького рівня, а деякі фрази (наприклад, розмови про рядки) вказують на деякі помилки. Це не так неможливо, як ви маєте на увазі, не всім було приємно кинути голову спочатку на прості мікроконтролери (як я і, мабуть, інші). Можливо, Френкі повинен уточнити.

2

Це залежить.

У перші дні дійсно простих машин, так, код виконував по одному рядку. Коли машини ставали більшими, швидшими та складнішими, ви почали бачити як здатність одночасно виконувати декілька інструкцій, так і пам'ять читає і записує набагато довше, ніж операції над регістрами.

Оптимізація компіляторів повинна була враховувати це, і рядки, які ви надаєте, могли бути виконані "більш-менш" паралельно, одна частина процесора працює на обчислення y, а інша частина зберігає раніше обчислене нове значення x (і для обчислення y було використано це нове значення з регістра).

Control Data 6600 - це перша машина, про яку я знав, що робив подібні речі. Додавання цілого числа займало 300 нсек, посилання на пам'ять (читання або запис) займало 1000 нсек, множення і ділення займало ЛОТ довше. Паралельно може виконуватися до десяти інструкцій, залежно від того, які функціональні підрозділи потрібні. Компілятори CDC 6600 FORTRAN були ДУЖЕ хороші в плануванні всього цього.


У цьому випадку введення наступної інструкції залежить від результату першої інструкції, тому вона повинна виконуватися послідовно.
SK-логіка

@ SK-логіка: Не зовсім. Введення другого рядка залежить від результату правого боку першого рядка, але, виходячи виключно з того, що ми можемо бачити у вихідному прикладі коду, воно НЕ може залежати від пам'яті, що зберігається в пам'яті результату перший рядок. Якби х було оголошено мінливим (у C / C ++), тоді компілятору потрібно буде спочатку зберегти результат, А ТОГО ВІДПОВІДНО З ПАМ'ЯТИ, перш ніж почати обчислювати нове значення y, оскільки "мінливий" означає, що щось (обробник переривання, скажімо) міг би зайти і запхнути х між двома рядками.
Джон Р. Стром

Я припускав, що x і y - це регістри (а код є мовою псевдоскладок з 3 адресами, а не чимсь на зразок C). У цьому випадку обидві інструкції неминуче послідовні. Інакше ОП довелося задавати два чи більше різних питань замість цього.
SK-логіка

Цікаво, чи намагалися б процесори "спекулювати", у чому xполягає цінність ? Таким чином він вже виконав код і зберігає його в кеші.
Калонь Колоб

Навіть якщо це регістри, залежні від машини, ви не можете припустити, що інструкції виконуються повністю послідовно. 6600 має логіку планування ("табло"), яка б змушувала послідовну семантику, грунтуючись на припущенні, що програміст хотів зробити очевидне. Пізніше машини опустили це обладнання, натомість покладаючись на компілятори, щоб ретельно планувати інструкції. Людські програмісти, які займаються програмою мовлення програмування на цих звірів, були НА СВОЄМО.
Джон Р. Стром

1

Ні, не існує однозначного відображення між кодовими рядками / інструкціями на мовах вищого та нижчого рівнів. Насправді обидва рядки вище перекладені на кілька інструкцій машинного коду , наприклад

  1. завантажити значення з певної адреси пам'яті в регістр
  2. змінити значення
  3. записати його назад у пам'ять

Фактичні деталі цих інструкцій залежать від платформ.

Це основний погляд на речі. Однак для подальших питань ускладнять, сучасні процесори застосовуються методи як конвеєри виконання , позачергового виконання і декількох ядер , серед інших. Це призводить до того, що ЦП робить одночасно кілька речей, наприклад, трубопроводи обробляють різні фази подальших інструкцій паралельно в межах однієї одиниці обробки, тоді як декілька ядер можуть обробляти незалежні інструкції паралельно.


0

Ви повинні детально ознайомитись у книзі, щоб знайти більше деталей про те, як вона працює, можливо, і клас компілятора.

В основному, ваше питання зосереджується на двох різних аспектах.

1) Як код переводиться в машинний код?

2) Коли / як обчислюється код за допомогою паралелізації?

Відповідь на 1) залежить від мови, якою ви користуєтесь (хоча для вашого прикладу є тривіальною, тому вихід буде однаковим). Те, як компілятор робить переклад на машинний код, є однією з сил мови. Крім того, є кілька проблем, які потрібно враховувати у вашому прикладі, код повинен завантажувати дані в пам'ять, зберігати їх тощо.

Нарешті, паралелізація - це особливості, які можна застосувати з точки зору програмування, але, у двох словах, деякі процесори можуть спробувати подумати, що якусь частину коду можна запустити одночасно, оскільки вони незалежні. У вашому випадку, очевидно, це не так, оскільки вам потрібно виконати операції послідовно, так що ні, воно не запуститься одночасно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.