1 תורת הקומפילציה 236360 הרצאה 11 יצירת הקוד Code Generation Aho, Lam, Sethi and Ullman – Chapter 8.

Slides:



Advertisements
Similar presentations
מבוא למדעי המחשב לתעשייה וניהול
Advertisements

1 Formal Specifications for Complex Systems (236368) Tutorial #4 Refinement in Z: data refinement; operations refinement; their combinations.
יצירת קוד ASU פרק 9. 2 יצירת קוד syntax analysis semantic analysis code generation syntax tree intermediate code דרישות יצירת קוד בעל איכות טובה (ניצול.
טבלאות סמלים נכתב ע"י אלכס קוגן סמסטר חורף, תשס"ח.
Presentation by Dudu Yanay and Elior Malul 1.  מה משותף לכל אלגוריתם המשתמש ב -Bucket Elimination: ◦ נתון מודל הסתברותי ורשת ביסיאנית מתאימה. ◦ נתונה.
מכונת מצבים תרגול מס' 4 Moshe Malka.
תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב'
רקורסיות נושאי השיעור פתרון משוואות רקורסיביות שיטת ההצבה
משטר דינמי המשך – © Dima Elenbogen :55 חידה שכדאי לעבור עליה: 2011/ho/WCFiles/%D7%97%D7%99%D7%93%D7%94%20%D7%A2%D7%9D%20%D7%91%D7%95%D7%A0%D7%95%D7%A1.doc.
חורף - תשס " ג DBMS, Design1 שימור תלויות אינטואיציה : כל תלות פונקציונלית שהתקיימה בסכמה המקורית מתקיימת גם בסכמה המפורקת. מטרה : כאשר מעדכנים.
שאלות חזרה לבחינה. שאלה דיסקים אופטיים מסוג WORM (write-once-read-many) משמשים חברות לצורך איחסון כמויות גדולות של מידע באופן קבוע ומבלי שניתן לשנותו.
תכנות תרגול 4 שבוע : לולאות while לולאות while while (condition) { loop body } במקרה של קיום התנאי מתבצע גוף הלולאה ברגע שהתנאי לא מתקיים נצא.
עבודה סמינריונית Prelude to Ukkonen algorithm ON-LINE CONSTRUCTION OF SUFFIX TREES מגישים : עיד מוחמד טיבי פיראס.
אינטרפולציה רועי יצחק.
חורף - תשס " ג DBMS, צורות נורמליות 1 צורה נורמלית שלישית - 3NF הגדרה : תהי R סכמה רלציונית ותהי F קבוצת תלויות פונקציונליות מעל R. R היא ב -3NF.
Map-Reduce Input: a collection of scientific articles on different topics, each marked with a field of science –Mathematics, Computer Science, Biology,
A. Frank File Organization Indexed-Sequential File Introduction Thanks to Tamar Barnes.
1 Formal Specifications for Complex Systems (236368) Tutorial #5 Refinement in Z: data refinement; operations refinement; their combinations.
בהסתברות לפחות למצא בעיה במודל PAC עבור בהסתברות ε הפונקציה f טועה מודל ONLINE 1. אחרי כל טעות הפונקציה משתפרת 2. מספר הטעיות קטן.
א " ב, מילים, ושפות הפקולטה למדעי המחשב אוטומטים ושפות פורמליות ( ) תרגיל מספר 1.
1 יצירת קוד ASU פרק יצירת קוד syntax analysis semantic analysis code generation syntax tree intermediate code דרישות יצירת קוד בעל איכות טובה (ניצול.
1 סביבת זמן הריצה. 2 כשאת אומרת x, למה את מתכוונת? מה תדפיס התוכנית הבאה? var x: int; function foo(): int isreturn x; function bar(): int isvar x:int;
תורת הקבוצות חלק ב'. קבוצה בת מניה הגדרה: קבוצה אינסופית X היא ניתנת למניה אם יש התאמה חד-חד ערכית בין X לבין .
תכנות תרגול 6 שבוע : תרגיל שורש של מספר מחושב לפי הסדרה הבאה : root 0 = 1 root n = root n-1 + a / root n-1 2 כאשר האיבר ה n של הסדרה הוא קירוב.
1 חישוב ואופטימיזציה של שאילתות חלק 2 Query Evaluation and Optimization Part 2.
1 סביבת זמן הריצה Aho, Sethi, and Ullman – Chapter 7 Cooper and Torczon – Chapter 6.
Backpatching 1. תזכורת מתרגול קודם קוד ביניים - שפת הרביעיות שיטות לייצור קוד ביניים –שימוש בתכונת code –כתיבה ישירה ל-buffer של פקודות שיטות לתרגום מבני.
מערכות הפעלה ( אביב 2009) חגית עטיה ©1 מערכת קבצים log-structured  ה log הוא העותק היחיד של הנתונים  כאשר משנים בלוק (data, header) פשוט כותבים את הבלוק.
תהליכים  מהו תהליך ?  מבני הנתונים לניהול תהליכים.  החלפת הקשר.  ניהול תהליכים ע " י מערכת ההפעלה.
Multi-Cycle MIPS דוגמאות. דוגמה 1 נתון קטע הקוד הבא: begin:addi $v0, $zero, -1 loop:add $a0, $a0, $a0 addi$v0,$v0,1 bne $a0, $zero, loop הניחו כי בתחילת.
Optimization ד " ר בלהה מנדלסון
מבוא כללי למדעי המחשב תרגול 3. לולאות while לולאות while while (condition) { loop body } במקרה של קיום התנאי מתבצע גוף הלולאה ברגע שהתנאי לא מתקיים נצא.
ערכים עצמיים בשיטות נומריות. משוואה אופינית X מציין וקטור עצמי מציינת ערך עצמי תואם לוקטור.
קורס תכנות – סימסטר ב ' תשס " ח שיעור שישי: מערכים
Data Structures, CS, TAU, Perfect Hashing 1 Perfect Hashing בעיה : נתונה קבוצה S של n מפתחות מתחום U השוואה ל - Hash : * טבלה קבועה (Hash רגיל - דינאמי.
1 Data Structures, CS, TAU, Perfect Hashing בעיה: נתונה קבוצה S של n מפתחות מתחום U השוואה ל- Hash : * טבלה קבועה (Hash רגיל - דינאמי) * רוצים זמן קבוע.
משטר דינמי – © Dima Elenbogen :14. הגדרת cd ו -pd cd - הזמן שעובר בין הרגע שראשון אותות הכניסה יוצא מתחום לוגי עד אשר אות המוצא יוצא מתחום.
מערכים עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר int grade1, grade2, …, grade20; int grade1, grade2, …, grade20;
מודל הלמידה מדוגמאות Learning from Examples קלט: אוסף של דוגמאות פלט: קונסיסטנטי עם פונקציה f ב- C ז"א קונסיסטנטי עם S ז"א מודל הלמידה מדוגמאות Learning.
עקרון ההכלה וההדחה.
יחס סדר חלקי.
מבוא למדעי המחשב תרגול 3 שעת קבלה : יום שני 11:00-12:00 דוא " ל :
מבוא למדעי המחשב, סמסטר א ', תשע " א תרגול מס ' 1 נושאים  הכרת הקורס  פסאודו - קוד / אלגוריתם 1.
Markov Decision Processes (MDP) תומר באום Based on ch. 14 in “Probabilistic Robotics” By Thrun et al. ב"הב"ה.
מערכות הפעלה ( אביב 2004) חגית עטיה © 1 תהליכים  מהו תהליך ?  מבני הנתונים לניהול תהליכים.  החלפת הקשר.  ניהול תהליכים ע " י מערכת ההפעלה.
1 אופטימיזציה של קוד ASU פרק מה זה אופטימיזציה? שיפור ביצועי התוכנית. בניגוד למה שמשתמע מהשם, בדרך-כלל לא מגיעים לאופטימום.
מתמטיקה בדידה תרגול 2.
מה היום ? - - חזרה מהירה. - קריאה וכתיבה לקבצים. - בניית תוכנית כתיבה low-level - בניית ערוץ גלובלי והדגמה מול חומרה - low-level DAQ, פולימורפיזם וטריגר.
Points on a perimeter (Convex Hull) קורס – מבוא לעבוד מקבילי מבצעים – אריאל פנדלר יאיר ברעם.
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
1 ׃1998 Morgan Kaufmann Publishers פקודת ה- jump 4 bits 26 bits 2 bits 00 : כתובת קפיצה במילים : כתובת קפיצה בבתים … …
Structure. מה לומדים היום ? דרך לבנות מבנה נתונים בסיסי – Structure מייצר " טיפוס " חדש מתאים כאשר רוצים לאגד כמה משתנים יחד דוגמאות : עובד : שם, טלפון,
מבוא למדעי המחשב לתעשייה וניהול הרצאה 7. סברוטינות subroutines.
Practice session 3.  תחביר ממשי ( קונקרטי ) ותחביר מופשט ( אבסטרקטי )  שיטות חישוב : Applicative & Normal Evaluation.
תכנות מכוון עצמים ושפת ++C וויסאם חלילי. TODAY TOPICS: 1. Function Overloading & Default Parameters 2. Arguments By Reference 3. Multiple #include’s 4.
מבוא למדעי המחשב לתעשייה וניהול הרצאה 6. מפעל השעווה – לולאות  עד עכשיו  טיפלנו בייצור נרות מסוג אחד, במחיר אחיד  למדנו להתמודד עם טיפול במקרים שונים.
. Sequence Alignment Tutorial #3 © Ydo Wexler & Dan Geiger.
עקרונות תכנות מונחה עצמים תרגול 11: OOP in C++. Outline  Where do the objects live ?  Inheritance  Slicing  Overriding vs Shadowing.
Aho, Lam, Sethi and Ullman – Chapter 8
מספרים אקראיים ניתן לייצר מספרים אקראיים ע"י הפונקציה int rand(void);
Computer Architecture and Assembly Language
אינדקסינג והשינג (indexing & hashing)
ניתוח זמן ריצה (על קצה המזלג)
בעיות נוספות ב-NPC.
סוגי משתנים קרן כליף.
תזכורת על מה דיברנו שיעור שעבר? בנינו אתר אינטרנט עם כותרות
מערכים של מצביעים הקצאה דינאמית
Computer Programming תרגול 3 Summer 2016
Engineering Programming A
Computer Architecture and Assembly Language
Presentation transcript:

1 תורת הקומפילציה הרצאה 11 יצירת הקוד Code Generation Aho, Lam, Sethi and Ullman – Chapter 8

2 2 יצירת קוד syntax analysis semantic analysis code generation syntax tree intermediate code הגענו ל -back-end: מייצרים קוד עבור מכונה ספציפית. הדיון מתאים לקוד שעבר אופטימיזציה או קוד לפני אופטימיזציה. ההנחה היא שקוד הביניים לא מכיל שגיאות ( בשלב זה לא נהוג לחפש שגיאות ).

3 3 מטרות יצירת קוד בעל איכות טובה יעילות בזמן ריצה יעילות במקום הנדרש בזמן ריצה לאחרונה - יעילות בצריכת אנרגיה גודל קוד קטן ככל האפשר ניצול יעיל של משאבי המכונה ( למשל, ניצול טוב של הרגיסטרים, או ניצול פקודות מכונה מהירות ייחודיות ) יצירת קוד בזמן סביר מותר לקומפיילר לרוץ לאט כדי ליצור תכנית שרצה מהר.  אבל בגבולות הטעם הטוב. יצירת קוד אופטימלי היא NP-hard, לכן משתמשים באלגוריתמים היוריסטיים.

4 4 הקלט והפלט של ה -code generator קלט : קוד בשפת הביניים + מידע מטבלת הסמלים ( וכל מידע אחר שנרצה להעביר מה -front-end). פלט : שפת המטרה absolute machine code: מוכן להרצה מיידית ( מכיל כתובות אבסולוטיות ).  תוכניות com ב -DOS  לא ממש קיים בארכיטקטורות מודרניות relocatable code: כתובות יחסיות, מאפשר קומפילציה נפרדת.  דורש link-load לפני הביצוע.  קבצי obj ( קבצי tpu, וכו ') assembly language:  דורש ביצע assembly לפני הריצה.  יצירת קוד יותר קצר, מאפשר שימוש במקרו, פקודות סימבוליות.

5 5 אתגרים ניהול זיכרון - היכן נמצא משתנה במהלך הביצוע ? הבנת פקודות מכונה : אוסף רחב מצריך החלטה נבונה יותר באיזו אופציה עדיף להשתמש. מה העלות בזיכרון של כל פקודה ? צריכת אנרגיה, יעילות וכו '... הקצאת רגיסטרים בחירת סדר החישוב תוך התחשבות ב - pipelining וב - caching אנו נדבר על : עלות פקודות יצירת קוד לקפיצה לרוטינה ( וחזרה ) בלוקים בסיסיים, Control Flow Graph, ואופטימיזציות בסיסיות. ייצור קוד תוך כדי מעקב על מיקום המשתנים בזיכרון וברגיסטרים. הקצאת רגיסטרים.

6 6 מכונת מטרה לדוגמא byte addressability, 4-byte words, n רגיסטרים – R 0,... R n-1 מבנה הפקודות OP source, destination צורת האופרנדים addressformmode MMabsolute RRregister c + content ( R )c ( R )indexed content ( R )* Rindirect register content ( c + content ( R ) )* c ( R )indirect indexed c (constant – not an address) # cliteral

7 אורך הקוד שנוצר כל פקודה תופסת בין 1-3 מילים. אנו נניח שבמילה אחת אפשר להכניס : Op-code, שני מספרים של רגיסטרים, צורת האופרנד ( מיעון עקיף, ישיר, אינדקס וכיו " ב ). אבל לכל כתובת בזיכרון או קבוע יש להוסיף מילה ( ראה עמודה ימנית ). Length costaddressformmode 1MMabsolute 0RRregister 1c + content ( R )c ( R )indexed 0content ( R )* Rindirect register 1content ( c + content ( R ) )* c ( R )indirect indexed 1c (constant – not an address) # cliteral Op-code + info More for op 1 ? More for op 2 ?

8 8 דוגמאות MOV R 0,123 העתק את הערך של רגיסטר 0 לכתובת 123 בזכרון. אורך פקודה = 2. ADD 4(R 0 ),123 הוסף את הערך שבכתובת הזכרון {4 ועוד ערך רגיסטר 0}, לכתובת 123. אורך פקודה = 3. SUB *4(R 0 ),R 1 החסר את הערך שבתא הזכרון, שכתובתו נמצאת בכתובת R 0 +4, מ -R 1. (R 1 := R 1 - *(4+R 0 )) אורך פקודה = 2. MOV #1,R 0 כתוב את הערך "1" ל -R 0. אורך פקודה = 2.

9 ניהול הזיכרון אזור סטטי בזיכרון שמכיל קוד אזור סטטי שמכיל משתנים סטטיים ( גלובליים ) ה -heap: אזור שמנוהל דינאמית עבור אובייקטים שהתוכנית מקצה. ה -stack שבו מנוהלים רשומות ההפעלה של הרוטינות.

10 ניהול רשומות ההפעלה לפרוצדורות נפריד בין scoping סטטי ודינאמי. כזכור עבור scope דינאמי מנהלים מחסנית עבור כל שם משתנה. מייצרים כניסה חדשה במחסנית בכל פעם שנכנסים לבלוק שבו מוגדר המשתנה, עושים pop בכל פעם שיוצאים מבלוק כזה ( לכל משתנה המוגדר בו ). היתרון : אין צורך במחסנית של רשומות הפעלה, ולכל פרוצדורה יש רשומת הפעלה יחידה. המידע בטבלת הסמלים מפנה למחסנית של כל משתנה. את כתובות החזרה שומרים במחסנית ומעדכנים בכל כניסה ויציאה מרוטינה. נעבור ל -scoping סטטי. לא נדבר על ניהול המחסניות, אלא על איך נראית קריאה לרוטינה, חזרה מרוטינה, ורשומת ההפעלה.

11 Static scoping כאן המשתנים יושבים בתוך רשומת ההפעלה. הכתובות הן יחסיות ל -stack pointer. ראשית, נתייחס לקפיצה לרוטינה ולצעדים המתבצעים בקפיצה ובחזרה. בדוגמא שלנו ה -SP יצביע על ההתחלה של רשומת ההפעלה האחרונה ב - stack, ולכן ה -offset- ים יהיו חיוביים. כשנקפוץ לרוטינה, נקדם את ה -SP בגודל הרשומה של הרוטינה הקוראת. רשומת הפעלה קודמת רשומת הפעלה נוכחית SP כתובות עולות

12 ניהול מחסנית רשומות הפעלה ב -scoping סטטי main MOV #stackstart, SP … code for the main procedure … HALT calling a procedure ADD #caller.recordsize, SP MOV #here + 16, *SP GOTO callee.code_area SUB #caller.recordsize, SP return from a procedure GOTO *0 ( SP ) רגיסטר מיוחד, מצביע לראש המחסנית. יצביע לראש רשומת ההפעלה הנוכחית. נניח לשם פשטות שכתובת החזרה נמצאת בתחילת רשומת ההפעלה.

13 ניהול מחסנית – דוגמא /* code for main */ action 1 call q action 2 halt /* code for p */ action 3 return /* code for q */ action 4 call p action 5 call q action 6 call q return

14 code for qcode for main ACTION 4 300:initialize the stackMOVE #600,SP100: ADD #qsize,SP320:ACTION 1 108: push return addressMOV #344,*SP328:call sequence beginsADD #main_size,SP128: call pGOTO :push return addressMOV #152,*SP136: SUB #qsize,SP344:call qGOTO : ACTION 5 352:restore SPSUB #ssize,SP152: ADD #qsize,SP372:ACTION 2 160: push return addressMOV #396,*SP380:HALT180: call qGOTO :... SUB #qsize,SP396:code for p ACTION 6 404:ACTION 3 200: ADD #qsize,SP424:returnGOTO *0(SP)220: push return addressMOV #448,*SP432:... call qGOTO : SUB #qsize,SP448: returnGOTO *0(SP)456:... stack starts here600: ניהול מחסנית – דוגמא

15 דוגמא – נניח ש - x := 0 היא שורה בתוכנית המקור משתנים סטטיים נניח ש - x אמור להמצא בהיסט ( (offset12 בקוד ביניים נראה static [12] := 0 בקוד המכונה, אם האזור הסטטי מתחיל בכתובת 100, נקבל : MOV #0, 112 – קוד מכונה הקצאה של משתנים מקומיים במחסנית נניח ש - x משתנה מקומי הממוקם ברשומת ההפעלה המוצבעת ע " י SP t 1 := 12 + SP * t 1 := 0 בפקודות מכונה – MOV #0, 12 ( SP ) קוד ביניים ( רביעות ) חישוב כתובות עבור משתנים ( ב -scoping סטטי )

16 מבנה התוכנית המיוצרת הבנת ההקשר של הפקודה יכולה להואיל לייצור הקוד ( בפרט הקצאת רגיסטרים ובחירת הפקודות שבהן נשתמש ). מושג מאד חשוב בהבנת קוד הוא בלוק בסיסי Basic block -. בלוק בסיסי הוא סדרת פקודות עם כניסה יחידה ( לפקודה הראשונה ) – אין קפיצה בקוד הקופצת לאמצע בלוק. יציאה יחידה ( מהפקודה האחרונה ) – הקוד יתבצע ללא שום קפיצות עד הגעתו לפקודה האחרונה בבלוק, שעשויה להיות קפיצה או קפיצה מותנית, או פקודה שמהווה יעד של קפיצה ממקור אחר, או סיום התוכנית. הרעיון הוא שכאשר נכנסים לבלוק, עושים זאת מהפקודה הראשונה ואז עוברים את הפקודות בבלוק אחת אחת בלי לצאת. נגדיר קשת בין שני בלוקים אם הפקודה האחרונה של בלוק המקור עשויה לקפוץ אל הפקודה הראשונה של בלוק היעד.

17 Basic Blocks Example t 1 := 4 * i t 2 := a [ t 1 ] if t 2 <= 20 goto B 3 t 3 := 4 * i t 4 := b [ t 3 ] goto B 4 t 5 := t 2 * t 4 t 6 := prod + t 5 prod := t 6 goto B 4 False t 7 := i + 1 i := t 2 Goto B 5 B1B1 B2B2 B3B3 B4B4 True

18 פירוק תוכנית לבלוקים בסיסיים Input: A sequence of three-address statements Output: A list of basic blocks with each three-address statement in exactly one block Method We first determine the set of leaders (the first statements of basic blocks).  The first statement is a leader  Any statement that is the target of a conditional or unconditional jump is a leader  Any statement that immediately follows a goto or conditional jump statement is a leader For each leader, its basic block consists of the leader and all statements up to but not including the next leader or the end of the program

19 (Control) Flow Graph צמתי הגרף – הבלוקים הבסיסיים קשתות הגרף – קשת מקשרת שני בלוקים אם קיימת הפנית בקרה מהראשון לשני ( או פשוט המשך ישיר של זרימת הבקרה ) לולאה – קבוצה קשירה היטב של בלוקים בעלת כניסה יחידה לולאה פנימית – לולאה ללא תת - לולאות הערה – נהוג להשתמש בשמות הבלוקים הבסיסיים כמטרת הקפיצה ( ולא במספרים סידוריים של הרביעיות המתאימות ) על מנת להקל הזזות של הבלוקים בסיסיים B1B1 prod := 0 i := 1 B2B2 t 1 := 4 * i t 2 := a [ t 1 ] t 3 := 4 * i t 4 := b [ t 3 ] t 5 := t 2 * t 4 t 6 := prod + t 5 prod := t 6 t 7 := i + 1 i := t 7 if i <= 20 goto B 2

20 דוגמא מהספר לקוד, וגרף זרימת בקרה מתאים

21 אופטימיזציות אפשר לקבל שיפורים משמעותיים בזמן בקוד גם כשמתבוננים רק בתוך בלוקים בסיסיים. כלומר : מנתחים את המידע הנמצא בתוך הבלוק ולא מתחשבים במה שקורה מחוץ לבלוק עושים שינויים לוקליים בלבד רמת דיוק גבוהה יותר משתמשת בכל הבלוקים שבתוך פרוצדורה. אם יש פיצול בזרימת הבקרה, לא יודעים מה קורה בחישוב בפועל, וצריך לעבוד באופן שמרני או ליברלי, כתלות במטרת האופטימיזציה. שיטות אלו יותר מסובכות ונדבר עליהן בהמשך הקורס. ניתן לדייק עוד יותר אם מתחשבים בכל הבלוקים שבתוכנית אבל : לא תמיד כל הבלוקים ידועים ( קישור לספריות לאחר הקימפול, וכיו " ב ) 21

22 הגדרה, שימוש, וחַיוּת של משתנים הקצאת משתנים נכונה לרגיסטרים היא קריטית ליעילות הריצה. הידיעה מתי ערכים בתוכנית רלוונטיים או " חיים " היא קריטית להקצאה יעילה של רגיסטרים. משפט מהסוג x := y + z מגדיר את x ומשתמש ב - y ו - z משתנה הוא חי בנקודה נתונה אם נעשה שימוש בערך שלו לאחר הנקודה האמורה. אם משתנה x מוגדר בפקודה i, ופקודה j משתמשת ב -x, ויש מסלול חישוב מ -i ל -j ( שאינו משנה את x), אז נאמר שפקודה j משתמשת בערך של x שהוגדר בפקודה i. בפרט, x חי בפקודה i ובכל המסלול בין i ל -j. נחשב שימוש של משתנים במקרה הפשוט שהכול קורה בתוך בלוק בסיסי. ( עבודה עם כמה בלוקים תשתמש ב -Data Flow Analysis: בשיעור הבא ).

23 טבלת ה -next-use עבור כל שורה בבלוק נתון, נרצה לשמור ( עבור כל משתנה אליו מתייחסת שורה זו ): האם המשתנה חי ( כלומר יש בו שימוש בעתיד ), ואם הוא חי באיזו פקודה יקרה השימוש הבא במשתנה. החישוב נעשה על - ידי סריקה של הבלוק מסופו לעבר תחילתו הנחות שמרניות : כל המשתנים שאינם מקומיים בבלוק, חיים בסוף הבלוק ( כלומר, נעשה בהם שימוש בהמשך ). שימו לב שיש הרבה משתנים זמניים לוקליים ב - intermediate code, ולכן אפילו טיפול לוקלי הוא רלוונטי. נניח שהמידע מי לוקלי לבלוק מושג באיזושהי צורה יעילה. ( קל לבדוק את זה במעבר על התוכנית.)

24 חישוב ה -next use חישוב ה - next-use – ברמת הבלוק הבודד – מהסוף להתחלה. נעזר בטבלת הסמלים לשמור מידע על המשתנים. נניח שבטיפול מהסוף להתחלה הגענו לפקודה i: i: x := y op z 1. נצמיד ל - i את האינפורמציה שנאספה בטבלת הסמלים על y, x ו - z עד עתה. 2. נקבע בטבלת הסמלים ( עבור הפקודות המוקדמות יותר בבלוק ): x – " לא חי "; " אין שימוש בהמשך " 3. נקבע בטבלת הסמלים : y, z – " חיים "; " השימוש הבא – ב - i" הערה – הסדר בין 2 ו - 3 – חשוב כי x עשוי להיות y x := y := x z := x * x := y * z

25 טרנספורמציות פשוטות ( וחשובות ) בתוך בלוקים בסיסיים סילוק ביטויים משותפים ביטול " קוד מת " השמה למשתנה שלא חי לאחר מכן החלפת סדר בין פקודות שאינן תלויות אחת בשנייה לקיצור הזמן בו משתנה חי ( כלומר הזמן שהוא דורש רגיסטר ) לייעול pipeline או מקבול פנימי. := b + ca := a – db := b + cc := a – dd d := b

26 טרנספורמציות פשוטות ( וחשובות ) בתוך בלוקים בסיסיים פישוטים אלגבריים : שוויונות : x + 0 = 0 + x = x – 0 = x x * 1 = 1 * x = x / 1 = x שימוש בפקודות זולות יותר : x ^ 2 = x * x 2 i * x = shift-left(x,i) 2 * x = x + x x / 2 i = shift-right(x,i) וכולי...

27 תהליך פשוט ליצירת קוד נייצר את הקוד פקודה פקודה, נטפל בכל בלוק בנפרד. לכל פקודה נבדוק היכן נמצאים האופרנדים נניח, למען הפשטות מחשב RISC, שבו הפקודות עובדות על רגיסטרים, פרט ל -store ו -load.

28 מעקב אחרי משתנים ורגיסטרים (Descriptors) נתעלם כרגע מרגיסטרים שאנו עושים בהם שימוש גלובלי כמו stack- pointer וכיו " ב ונניח שישנם רגיסטרים לשימושינו בבלוק. לכל רגיסטר – נרשום ב -descriptor מה יש בו בתחילת כל בלוק כל הרגיסטרים ריקים במהלך ייצור הקוד, כל רגיסטר יכיל משתנה אחד או יותר פקודה העתקה מהסוג x := y תגרום לרגיסטר להחזיק ערך של יותר ממשתנה אחד. לכל משתנה של התוכנית יש address descriptor המחזיק את הכתובת ( או הכתובות ) בו הוא נמצא. רגיסטר, כתובת בזיכרון, מיקום ב -stack. בד " כ ה -descriptor נשמר בטבלת הסמלים.

29 אלגוריתם ל -code generation קלט : רצף של פקודות three-address מבלוק בסיסי מסוים. For each three-address statement x := y op z, perform the following: 1. Invoke getreg (x := y op z) to determine locations R x, R y, and R z. 2. If Ry does not contain y, issue: “LD R y, y’ ”, for a location y’ of y. 3. If Rz does not contain z, issue: “LD R z, z’ ”, for a location z’ of z. 4. Issue the instruction “OP R x,R y,R z ” 5. Update the address descriptors of x, y, z, if necessary. In particular, R x is the only location of x now, and R x contains only x (remove R x from other address descriptors).

30 יצירת קוד – פעולות אחרות הטיפול בפעולות אונריות – דומה x := y מצריך עדכון המתארים עם סיום העבודה ברמת הבלוק הבסיסי שומרים את ערכי המשתנים שלא נמצאים במקומם הטבעי ( למשל נמצאים רק בתוך רגיסטרים ). אלא אם יש לנו אינפורמציה מקיפה יותר של live-dead בין בלוקים.

31 הקצאת רגיסטרים ( הפונקציה getreg) קלט : x := y op z המטרה – הקצאת רגיסטר ל - x, y, ו -z. נתחיל ב -y, בחירת עבור z שקולה. 1. אם y ברגיסטר R, קבע R y =R. 2. אחרת, אם יש רגיסטר פנוי R, קבע R y =R. 3. אחרת, אם יש רגיסטר המכיל רק את x, וגם x אינו אופרנד (z במקרה זה ) אז קבע R y =R. 4. אחרת, אם יש רגיסטר R שהמשתנה שבו v אינו חי, קבע R y =R. 5. אחרת אם יש רגיסטר R שהמשתנה שבו v קיים גם במקום אחר, קבע R y =R. 6. אחרת, בחר רגיסטר R כלשהו שמייצג מספר מינימלי של משתנים {v1, v2, …, vm}. לכל משתנה שמיוצג רק ע " י R העתק את ערכו לזיכרון. קבע R y =R. 7. בכל מקרה עדכן את ה -descriptor של R, v, ( או v i אם רלוונטי ) בהתאם.

32 חלק שני : הקצאת רגיסטר ל -x קלט : x := y op z 1. אם x ברגיסטר R המכיל רק את x, קבע R x =R. ( זה בסדר גם אם y או z זהים ל -x). 2. אחרת, אם לא משתמשים ב -y ( או ב -z) לאחר הפקודה הנוכחית, והרגיסטר שנקבע לו מייצג אותו באופן יחיד, אז ניתן לקבוע את הרגיסטר של x להיות זהה לרגיסטר של y ( או z). ההמשך מאד דומה 3. אחרת, אם יש רגיסטר פנוי R אחרת, אם יש רגיסטר R שהמשתנה שבו v אינו חי אחרת, בחר רגיסטר R כלשהו שמייצג מספר מינימאלי של משתנים {v1, v2, …, vm}. לכל משתנה העתק את ערכו לזיכרון, וקבע R x =R. 6. בכל מקרה עדכן את ה -descriptor של R, v, ( או v i אם רלוונטי ) בהתאם.

33 הקצאת רגיסטרים : דוגמא address descriptorregister descriptorcode generatedstatements registers empty a in R1, a in a, b in b, c in c, d in d, t in R2 R1 contains a R2 contains t LD R1, a LD R2, b SUB R2, R1, R2 t := a – b a in a, b in b, c in c, c in R3, d in d, t in R2, u in R1 R1 contains u R2 contains t R3 contains c LD R3, c SUB R1, R1, R3 u := a – c a in a, b in b, c in c, c in R3, d in d, t in R2, u in R1, v in R3 R1 contains u R2 contains t R3 contains v ADD R3, R2, R1v := t + u a in a, b in b, c in c, d in d, c in R3, d in d, t in R2, d in R1, v in R3 R1 contains d R2 contains t R3 contains v ADD R1, R1, R3 ST d, R1 d := v + u d := (a – b) + (a – c) + (a – c)

34 Register Allocation and Assignment Register allocation: איזה ערכים יישמרו ברגיסטרים. Register assignment: איזה ערך יישמר באיזה רגיסטר. ההחלטות על מיקום ערכים ברגיסטרים הן מהחשובות באופטימיזציה של קוד. הסיבה : פקודות הניגשות לרגיסטרים הן קצרות יותר ומהירות יותר. ההחלטה על register allocation היא NP- קשה ( אפילו אם יש רק רגיסטר יחיד במכונה ). לכן משתמשים בהיוריסטיקות. לעיתים ההיוריסטיקות מסתבכות עוד יותר בשל אילוצי חומרה. למשל מכונות מסויימות משתמשות ב pairing-. Mul R2,R3 מכניס את המכפלה של המספר ב -R2 והמספר ב -R3 אל הזוג R2,R3 כאשר R2 ו -R3 מוגדרים מראש כצמד. 34

35 Register Allocation and Assignment שתי גישות קיצוניות אפשריות : 1. הקצאה גלובלית : כל רגיסטר יכול להכיל כל משתנה. 2. לחלק את הרגיסטרים לקבוצות, כשלכל קבוצה אחראית על נושא מסוים.  למשל, קבוצה אחת מחזיקה רק פוינטרים, אחרת מטפלת בחישובים אריתמטיים, שלישית משמשת רק ככתובות בסיס ( למערכים, ל - stack, וכו '.), עוד רגיסטר ישמש להחזרת פרמטר מרוטינות וכיו " ב. הגישה השלטת היא גישת ביניים : יש רגיסטרים ספציפיים שיוקצו ל -stack pointer, לשימוש כבסיס וכו ', אבל הרוב מוקצים באופן גלובלי. 35

36 הקצאת רגיסטרים גלובלית עד עתה דיברנו רק על הקצאה בתוך בלוק בסיסי, והנחנו שערכם של משתנים נכתב חזרה לזיכרון בסוף כל בלוק. על - מנת לחסוך חלק מה -loads וה -stores נרצה לעיתים לבחור משתנים שיש אליהם גישה תדירה ולהקצות להם רגיסטר שנשמר במעבר בין בלוקים. ההעדפה הראשונה ניתנת למשתנים " הכי פעילים " המופיעים בתוך הלולאות הפנימיות ביותר : אלו קטעי הקוד שמתבצעים ( בד " כ ) הכי הרבה. נקצה רגיסטרים עבור משתנים אלה ; השאר ישמשו להקצאה לוקלית בבלוק. הערכת התועלת של שמירת משתנה v מבלוק B ברגיסטר נעשית ע " י ספירה : לכל מופע של v ב -B שבו ניתן להשתמש ברגיסטר נוסיף נקודה. לכל מופע של v בבלוק עוקב שמשתמש בערך ( בלי להציב ב -v ערך חדש ) נוסיף שתי נקודות על כך שלא בצענו store ו -load במעבר בין הבלוקים. לאחר שנעריך תועלת לכל משתנה בלולאה הפנימית, נקצה רגיסטרים למשתנים שעבורם התועלת גבוהה ביותר.

37 Spilling ו -Graph Coloring כאשר צריך להקצות רגיסטר וכל הרגיסטרים תפוסים, צריך לבחור רגיסטר לשימוש, ולשפוך (spill) את ערכו הקודם לשמירה בזיכרון. המצב האידיאלי הוא שמקצים רגיסטר חדש כאשר ערך ברגיסטר קודם " מת " וניתן להשתמש ברגיסטר הקודם ללא spilling. מציאת הקצאת רגיסטרים שמביאה למינימום spilling היא NP- קשה. לכן משתמשים בהיוריסטיקות הקשורות לצביעת גרפים. נסתכל על תמונת הערכים החיים בתוכנית : חי v 1 חי v 2 חי v 3 חי v 4 חי v 5 חי v 6 חי v 7 חי v 8 זמן ריצה

38 בניית גרף מתאים נקצה צומת לכל משתנה, וקשת בין שני משתנים " מתנגשים ". צמתים מתנגשים אם יש חפיפה בזמן חייהם. משמעות : אם נקצה להם אותו רגיסטר אז יידרש spill. זמן ריצה חי v 1 חי v 2 חי v 3 חי v 4 חי v 5 חי v 6 חי v 7 חי v 8 V1V1 V1V1 V8V8 V8V8 V2V2 V2V2 V4V4 V4V4 V7V7 V7V7 V6V6 V6V6 V5V5 V5V5 V3V3 V3V3

39 בניית גרף מתאים נקצה צומת לכל משתנה, וקשת בין שני משתנים " מתנגשים ". צמתים מתנגשים אם יש חפיפה בזמן חייהם. משמעות : אם נקצה להם אותו רגיסטר אז יידרש spill. V1V1 V1V1 V8V8 V8V8 V2V2 V2V2 V4V4 V4V4 V7V7 V7V7 V6V6 V6V6 V5V5 V5V5 V3V3 V3V3 מטרתנו : להקצות k רגיסטרים למשתנים כך ששני משתנים יוקצו לרגיסטרים שונים אם יש ביניהם קשת. בעיית הצביעה : להקצות k צבעים לצמתים כך שני צמתים שכנים יקבלו צבע שונה. בעיית ה -k צביעה NP- קשה עבור k>2. אבל כאן מדובר בגרפים מאד ספציפיים : גרפי אינטרוואלים, שעבורם מציאת צביעה ב -k ניתנת לפיתרון יעיל. מצד שני, התוכנית האמיתית אינה גרף אינטרוואלים פשוט, בשל ה -control flow האמיתי.

40 היוריסטיקה 1. נמצא צביעה לגרף באופן הבא. 2. באופן איטרטיבי נעיף מהגרף כל צומת שדרגתה קטנה מ -k ( עם כל קשתותיה ). 3. הסבר : לא משנה אילו צבעים נבחר לצמתים האחרים, תמיד נוכל לצבוע צומת זאת בצבע חוקי. V1V1 V1V1 V8V8 V8V8 V2V2 V2V2 V4V4 V4V4 V7V7 V7V7 V6V6 V6V6 V5V5 V5V5 V3V3 V3V3 4. נשארנו עם צמתים שכולם מדרגה גדולה או שווה ל -k, או עם גרף ריק. 5. אם הגרף ריק, נחזיר את הצמתים שהעפנו אחת אחת ונצבע אותן. אחרת, 6. נבחר צומת כלשהו ונעיף אותו מהגרף. המשמעות : משתנה זה לא יקבל רגיסטר אלא יוקצה מהזיכרון. נחזור על שלב זה עד שייוצר צומת עם דרגה קטנה מ -k ואז נתחיל מהתחלה.

41 היוריסטיקה 1. נמצא צביעה לגרף באופן הבא. 2. באופן איטרטיבי נעיף מהגרף כל צומת שדרגתה קטנה מ -k ( עם כל קשתותיה ). 3. הסבר : לא משנה אילו צבעים נבחר לצמתים האחרים, תמיד נוכל לצבוע צומת זאת בצבע חוקי. V1V1 V1V1 V8V8 V8V8 V2V2 V2V2 V4V4 V4V4 V7V7 V7V7 V6V6 V6V6 V5V5 V5V5 V3V3 V3V3 4. נשארנו עם צמתים שכולם מדרגה גדולה או שווה ל -k, או עם גרף ריק. 5. אם הגרף ריק, נחזיר את הצמתים שהעפנו אחת אחת ונצבע אותן. אחרת, 6. נבחר צומת כלשהו ונעיף אותו מהגרף. המשמעות : משתנה זה לא יקבל רגיסטר אלא יוקצה מהזיכרון. נחזור על שלב זה עד שייוצר צומת עם דרגה קטנה מ -k ואז נתחיל מהתחלה. הפעולה ההיוריסטית העיקרית כאן היא בחירת הצומת להעיף בעת ביצוע שלב 6, והיא קובעת כמה spills באמת יהיו.

42 שימו לב שלא השגנו פיתרון אופטימאלי ראשית, יתכן שיש פיתרון אחר שבו מוותרים בהיוריסטיקה על צמתים אחרים ומתקבלים פחות spills. שנית, יצרנו את הגרף מתוך הנחות שמרניות של חפיפה בזמן החיים של משתנים. תיתכנה תלויות של גרף הזרימה כך ששני משתנים לעולם לא באמת חיים יחד, אבל אנחנו לא מודעים לכך בניתוח השמרני הפשוט. אבל – אם מצאנו צביעה מלאה של הגרף, כלומר, לא דרושים spills וכל המשתנים יכולים לחיות ברגיסטרים, אז הפיתרון שמצאנו הוא ( כמובן ) אופטימאלי.

43 לסיכום : יצירת קוד מעבר משפת ביניים לשפת מטרה (back-end) מכונת מטרה לדוגמא. אורך הקוד ויעילותו תלוי בניצול יעיל של הרגיסטרים. ייצור קוד לניהול רשומות הפעלה בלוקים בסיסיים, control flow graph, חַיוּת של משנים. טרנספורמציות פשוטות בתוך בלוקים בסיסיים. ייצור קוד תוך כדי מעקב על מיקום המשתנים בזיכרון וברגיסטרים. הקצאת רגיסטרים.