Download presentation
Presentation is loading. Please wait.
1
מבוסס על פרק 7 בספר של Allen and Kennedy
סמינר במדעי המחשב תלויות בקרה (Control Dependence) מבוסס על פרק 7 בספר של Allen and Kennedy 18 ספטמבר 18
2
מבוא בהרצאות הקודמות ראינו כיצד מבצעים טרנפורמציות ללולאות, ומקבלים במקומם הוראות ווקטוריות או מקביליות המנצלות את היכולות של המעבדים המודרנים. למדנו למצוא תלויות מידע בין הוראות בתוך גוף הלולאה ע"י בניית גרף התלויות, ולמדנו להסיק מהגרף מתי ואלו אופטימיזציות מותר לבצע. עד עתה התעלמנו לחלוטין מתלויות בקרה, הנגרמות מהוראות של control (כמו קפיצות מותנות) העלולות להופיע בגוף הלולאה.
3
מבוא S1 S2 נתבונן למשל בקטע הקוד הבא:
DO 100 I = 1, N S1 IF (A(I-1) > 0) GOTO 100 S2 A(I) = A(I) + B(I)*C 100 CONTINUE אם נתבונן בתלויות המידע בקוד בלבד, נקבל את גרף התלויות: S1 S2 -1 ולכן בהתייחס לתלויות מידע בלבד ניתן לבצע אופטימיזציה ולקבל: P
4
קוד לא שקול - בקוד שקיבלנו S2 מבוצע ללא תנאי!
מבוא DO 100 I = 1, N S1 IF (A(I-1) > 0) GOTO 100 S2 A(I) = A(I) + B(I)*C 100 CONTINUE S2 A(1:N) = A(1:N) + B(1:N)*C DO 100 I = 1, N S1 IF (A(I-1) > 0) GOTO 100 100 CONTINUE קוד לא שקול - בקוד שקיבלנו S2 מבוצע ללא תנאי!
5
איפה טעינו? אנו התייחסנו רק לתלויות מידע, ופספסנו תלות אחרת בין S1 ל-S2 שהיתה יוצרת מעגל בגרף התלויות ומונעת מאיתנו להחליף את סדר ההוראות. ? S1 S2 -1 תלות זו היא תלות בקרה – Control dependent.
6
התמודדות עם תלויות בקרה
ניתן כמובן פשוט להחליט שאנו לא מבצעים אופטימיזציות על לולאות עם הוראות בקרה בתוכם, אך הוראות בקרה בלולאות זה דבר נפוץ וההפסד יהיה גדול מאוד. אנו נראה שני דרכים לטיפול בתלויות בקרה: א. If conversion – בדרך זו ננסה להחליף את כל תלויות הבקרה בתלויות מידע רגילות, בכך שננסה להחליף את כל הוראות הקפיצה המותנית בהוראות if. ב. CDG (control dependence graph) – בדרך זו נכניס את כל תלויות הבקרה לגרף (בדומה לגרף תלויות המידע) ונסיק מהגרף אלו אופטימיזציות מותר לבצע.
7
IF Conversion
8
דוגמא לחיזוק האינטואיציה
נתבונן בקטע הקוד הבא. האם ניתן למקבלו? DO 100 I = 1, N S1 IF (A(I-1) > 0) GOTO 100 S2 A(I) = A(I) + B(I)*C S3 B(I) = B(I) + A(I) 100 CONTINUE אם נצליח להיפטר מהוראה S1 נקבל קוד המכיל תלויות מידע בלבד – אותו אנו כבר יודעים לנתח. ברור כי לא ניתן להוציא "סתם" את ההוראה – בתוכנית המקורית הוראות S2, S3 מתבצעות רק כאשר A(I-1) גדול מאפס.
9
דוגמא לחיזוק האינטואיציה (המשך)
נתבונן בקטע הקוד הבא. האם ניתן למקבלו? DO 100 I = 1, N S1 IF (A(I-1) > 0) GOTO 100 S2 A(I) = A(I) + B(I)*C S3 B(I) = B(I) + A(I) 100 CONTINUE לכן נרצה להוסיף תנאי (if) להוראות S2, S3, שיבטיח כי הן יתבצעו רק אם היא הן היו מתבצעות בתוכנית המקורית. נקבל את הקוד השקול הבא (הפעם ללא תלויות בקרה):
10
דוגמא לחיזוק האינטואיציה (המשך)
נתבונן בקטע הקוד הבא. האם ניתן למקבלו? DO 100 I = 1, N S1 IF (A(I-1) > 0) GOTO 100 S2 A(I) = A(I) + B(I)*C S3 B(I) = B(I) + A(I) 100 CONTINUE DO 100 I = 1, N IF (A(I-1) >= 0) A(I) = A(I) + B(I)*C IF (A(I-1) >= 0) B(I) = B(I) + A(I) 100 CONTINUE
11
דוגמא לחיזוק האינטואיציה (המשך)
DO 100 I = 1, N S3 IF (A(I-1) >= 0) A(I) = A(I) + B(I)*C S4 IF (A(I-1) >= 0) B(I) = B(I) + A(I) 100 CONTINUE נשם לב כי הערכים של A(I) ו-B(I) בהוראות S3 ו-S4 נקבעים עתה כפונקציה של A(I-1) (בנוסף לתלויות המקוריות האחרות). קיבלנו לולאה עם תלויות מידע רגילות, שהגרף שלהם הוא: S3 S4
12
דוגמא לחיזוק האינטואיציה (המשך)
DO 100 I = 1, N S3 IF (A(I-1) >= 0) A(I) = A(I) + B(I)*C S4 IF (A(I-1) >= 0) B(I) = B(I) + A(I) 100 CONTINUE ולכן ניתן למקבל את S4 ולקבל: DO 100 I = 1, N S3 IF (A(I-1) >= 0) A(I) = A(I) + B(I)*C 100 CONTINUE S4 WHERE (A(0:N-1) <= 0) B(1:N) = B(1:N)+A(1:N)
13
קפיצות מותנות – הפרדה לסוגים
נהוג לחלק את הקפיצות המותנות שיכולות להופיע בתוכנית לשלושה סוגים: א) Forward Branch – קפיצה מנקודה אחת בלולאה, קדימה לנקודה אחרת בלולאה (אותה רמת קינון). ב) Backward Branch - קפיצה מנקודה אחת בלולאה, אחורה לנקודה אחרת בלולאה (אותה רמת קינון). ג) Exit branch – קפיצה מגוף הלולאה אל מחוץ ללולאה (לפני הלולאה או אחריה). ד) שיקוצים שונים - קפיצות לתוך לולאות, assign gotos...
14
סוגי קפיצות מותנות – דוגמאות
Forward branch DO 100 I = 1, N H: IF (A(I-1) > 0) GOTO L A(I) = A(I) + B(I)*C IF (A(I) < 0) GOTO H L: B(I) = B(I) + A(I) IF (B(I) > 0) GOTO R 100 CONTINUE R: C = C + D; Backward branch Exit branch P P P
15
קפיצות קדימה
16
הגיע זמן להגדרה... הגדרה – guard של הוראה בתוכנית הוא תנאי לוגי, כך שההוראה מבוצעת אם ורק אם ערך ה-guard שלה (כאשר השליטה בתוכנית מגיעה אליה) מוערך ל-true. מטרתנו: להוציא מהתוכנית את כל הקפיצות המותנות, ובמקומם להתנות (IF) ביצוע כל הוראה בסיפוק ה-guard שלה.
17
שקף לחיזוק האינטואיציה
S5 (G5) S6 (G6) S7 (G7) S8 (G8) S9 (G9) S10 (G10) S11 (G11) S12 (G12) S13 (G13) G5=G6=G7=G8 G9=(G8 AND NOT(M1)) G10=G11=G9 G12=(G8 AND M1) OR G11 M1 G13=G12 P P P P P
18
קפיצות קדימה – המקרה הקל ביותר
עוברים על קוד התוכנית, הוראה אחרי הוראה ע"פ סדר ביצוע. בכל שלב נחזיק בזיכרון: א. ביטוי לוגי נוכחי (Current) שיבטא את התנאי הדרוש כדי שנגיע להוראה ישירות מההוראה הקודמת. ב. לכל הוראה נשמור ביטוי לוגי נוסף (פרטי שלה) שיציין התנאים להגיע אל ההוראה ע"י קפיצות אליה. ה-current יאותחל ל-true (הוראה ראשונה מבוצעת תמיד) וכל הביטויים הפרטיים של ההוראות יאותחלו ל-false. P P P
19
קפיצות קדימה – המקרה הקל ביותר
ה-guard המתאים לכל הוראה יחושב ע"י ביצוע OR בין ה-current לבין הביטוי הפרטי הנוכחי שלה. נעדכן ערך ה-current בהתאם. אינטואיציה: ההוראה מבוצעת אם הגענו אליה ישירות מההוראה הקודמת (אז ה-current יתקיים) או אם קפצנו אליה מקפיצה שהיא כתובתה (אז אחד התנאים הפרטיים של ההוראה יתקיימו).
20
קפיצות קדימה – המקרה הקל ביותר
ה-guard המתאים לכל הוראה יחושב ע"י ביצוע OR בין ה-current לבין הביטוי הנוכחי שלה. נעדכן ערך ה-current בהתאם. אם ההוראה הנוכחית היא קפיצה מותנית לכתובת L: * עדכן התנאי הפרטי של הוראה L ע"י ביצוע OR לוגי בין התנאי הפרטי לתנאי שהקפיצה תתרחש. תנאי להתרחשות הקפיצה: AND לוגי בין ה-CURRENT (תנאי להתרחשות הוראת הקפיצה) לבין תנאי הקפיצה.
21
זהו התנאי לביצוע ההוראה הבאה
קפיצות קדימה – המקרה הקל ביותר ה-guard המתאים לכל הוראה יחושב ע"י ביצוע OR בין ה-current לבין הביטוי הנוכחי שלה. נעדכן ערך ה-current בהתאם. אם ההוראה הנוכחית היא קפיצה מותנית לכתובת L: * עדכן התנאי הפרטי של הוראה L ע"י ביצוע OR לוגי בין התנאי הפרטי לתנאי שהקפיצה תתרחש. * עדכן ה-current ע"י ביצוע AND לוגי עם ערך ה-NOT של תנאי הקפיצה. זהו התנאי לביצוע ההוראה הבאה
22
קפיצות קדימה – המקרה הקל ביותר
ה-guard המתאים לכל הוראה יחושב ע"י ביצוע OR בין ה-current לבין הביטוי הנוכחי שלה. נעדכן ערך ה-current בהתאם. אם ההוראה הנוכחית היא קפיצה מותנית לכתובת L: * עדכן התנאי הפרטי של הוראה L ע"י ביצוע OR לוגי בין התנאי הפרטי לתנאי שהקפיצה תתרחש. * עדכן ה-current ע"י ביצוע AND לוגי עם ערך ה-NOT של תנאי הקפיצה. * החלף הוראת הקפיצה המותנית במשתנה בוליאני ייחודי המקבל את תנאי הקפיצה. כמעט לפני כל הוראה, הוסף תנאי IF המכיל את CURRENT. P
23
קפיצות קדימה – דוגמא (current) C = C + 1 true guard: DO 100 I = 1, N
IF (A(I) > 10) GOTO 60 20 A(I) = A(I) + 10 IF (B(I) > 10) GOTO 80 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; true guard: (current) שורה 80 מתבצעת תמיד
24
לפני הוראות לולאה לא מוסיפים תנאים (IF)
קפיצות קדימה – דוגמא IF (true) C = C + 1 DO 100 I = 1, N IF (A(I) > 10) GOTO 60 A(I) = A(I) + 10 IF (B(I) > 10) GOTO 80 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; true guard: לפני הוראות לולאה לא מוסיפים תנאים (IF) P
25
קפיצות קדימה – דוגמא IF (true) C = C + 1 true guard: DO 100 I = 1, N
IF (A(I) > 10) GOTO 60 A(I) = A(I) + 10 IF (B(I) > 10) GOTO 80 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; true guard:
26
לתנאי הפרטי של שורה 60 יש להוסיף את הביטוי לקפיצה "מוצלחת"
קפיצות קדימה – דוגמא if (true) C = C + 1 DO 100 I = 1, N IF (A(I) > 10) GOTO 60 A(I) = A(I) + 10 IF (B(I) > 10) GOTO 80 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; IF (A(I) > 10) GOTO 60 -> m1=(A(I)>10) guard: לתנאי הפרטי של שורה 60 יש להוסיף את הביטוי לקפיצה "מוצלחת" P
27
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) A(I) = A(I) + 10 IF (B(I) > 10) GOTO 80 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard:
28
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (B(I) > 10) GOTO 80 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard:
29
לתנאי הפרטי של שורה 80 יש להוסיף את הביטוי לקפיצה מוצלחת
קפיצות קדימה – דוגמא IF (true) C = C + 1 DO 100 I = 1, N IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (B(I) > 10) GOTO 80 -> m2 = (B(I)>10) 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard: לתנאי הפרטי של שורה 80 יש להוסיף את הביטוי לקפיצה מוצלחת
30
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 B(I) = B(I) + 10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard:
31
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard: התנאי הפרטי של שורה 60 אינו FALSE ולכן הוא יש להוסיפו ב-OR ל-guard הנוכחי. P
32
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard:
33
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 IF (… OR (true AND m1)) A(I) = B(I) + A(I) 80 B(I) = A(I) - 5 100 CONTINUE C = C + D; guard: הביטוי גדול מכדי להיכנס למצגת! שוב תנאי פרטי אינו FALSE P
34
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 IF (… OR (true AND m1)) A(I) = B(I) + A(I) 80 IF (… OR (true AND NOT(m1) AND m2)) B(I)=A(I)-5 100 CONTINUE C = C + D; guard: ה-guard שקול לוגית ל-true נימנע מלהוסיף תנאי לפני CONTINUE (טעות קומפילציה) P
35
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 IF (… OR (true AND m1)) A(I) = B(I) + A(I) 80 IF (… OR (true AND NOT(m1) AND m2)) B(I)=A(I)-5 100 CONTINUE C = C + D; guard:
36
קפיצות קדימה – דוגמא IF (true) C = C + 1 guard: DO 100 I = 1, N
IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 IF (… OR (true AND m1)) A(I) = B(I) + A(I) 80 IF (… OR (true AND NOT(m1) AND m2)) B(I)=A(I)-5 100 CONTINUE IF (…) C = C + D; guard:
37
צא בחוץ!! קפיצות החוצה
38
קפיצות החוצה – מתחיל להסתבך
אינטואיציה: המקרה של קפיצה החוצה מסובך יותר שכן מרגע שהקפיצה מתרחשת הלולאה מפסיקה להתבצע: DO I = 1, N S1 IF (p(I)) GOTO 100 S2 END 100 S3 בפרט במקרה זה גם ביצוע S1, שלא בטווח הקפיצה, תלוי בתוצאת הקפיצה המותנת.
39
תחילה נטפל בשתי הקפיצות החוצה בלולאה הפנימית
קפיצות החוצה – דוגמא DO 200 I = 1, 100 50 S1 DO 100 J = 1, 100 S2 IF (X(I,J) > 300) GOTO 300 S3 IF (Y(I,J) < 50) GOTO 50 S4 100 CONTINUE S5 200 CONTINUE 300 S6 תחילה נטפל בשתי הקפיצות החוצה בלולאה הפנימית P
40
הוספת משתנים בוליאנים מתאימים לקפיצות
קפיצות החוצה – דוגמא DO 200 I = 1, 100 50 S1 Ex1 = TRUE Ex2 = TRUE DO 100 J = 1, 100 S2 IF (X(I,J) > 300) GOTO 300 S3 IF (Y(I,J) < 50) GOTO 50 S4 100 CONTINUE S5 200 CONTINUE 300 S6 הוספת משתנים בוליאנים מתאימים לקפיצות
41
קביעת תלות בין ביצוע כל הוראות הלולאה למשתנים הללו
קפיצות החוצה – דוגמא DO 200 I = 1, 100 50 S1 Ex1 = TRUE Ex2 = TRUE DO 100 J = 1, 100 IF (Ex1 AND Ex2) S2 IF (Ex1 AND EX2) IF (X(I,J) > 300) GOTO 300 IF (Ex1 AND Ex2) S3 IF (Ex1 AND Ex2) IF (Y(I,J) < 50) GOTO 50 IF (Ex1 AND Ex2) S4 100 CONTINUE S5 200 CONTINUE 300 S6 קביעת תלות בין ביצוע כל הוראות הלולאה למשתנים הללו
42
קפיצות החוצה – דוגמא DO 200 I = 1, 100 50 S1 Ex1 = TRUE Ex2 = TRUE
DO 100 J = 1, 100 IF (Ex1 AND Ex2) S2 IF (Ex1 AND EX2) Ex1 = NOT (X(I,J) > 300) IF (Ex1 AND Ex2) S3 IF (Ex1 AND Ex2) Ex2 = NOT (Y(I,J) < 50) IF (Ex1 AND Ex2) S4 100 CONTINUE S5 200 CONTINUE 300 S6 שינוי הוראות הקפיצה המקוריות להוראות שיבטיחו שהמשתנים יקבלו FALSE ברגע שהקפיצה התרחשה.
43
העברת הקפיצות אל מחוץ ללולאה
קפיצות החוצה – דוגמא DO 200 I = 1, 100 50 S1 Ex1 = TRUE Ex2 = TRUE DO 100 J = 1, 100 IF (Ex1 AND Ex2) S2 IF (Ex1 AND EX2) Ex1 = NOT (X(I,J) > 300) IF (Ex1 AND Ex2) S3 IF (Ex1 AND Ex2) Ex2 = NOT (Y(I,J) < 50) IF (Ex1 AND Ex2) S4 100 CONTINUE IF (NOT Ex1) GOTO IF (NOT Ex2) GOTO 50 S5 200 CONTINUE 300 S6 העברת הקפיצות אל מחוץ ללולאה
44
קפיצות החוצה – דוגמא DO 200 I = 1, 100
50 S1 Ex1 = TRUE Ex2 = TRUE J’ = 1 DO 100 J = 1, IF (Ex1 AND Ex2) J’ = J IF (Ex1 AND Ex2) S2 IF (Ex1 AND EX2) Ex1 = NOT (X(I,J) > 300) IF (Ex1 AND Ex2) S3 IF (Ex1 AND Ex2) Ex2 = NOT (Y(I,J) < 50) IF (Ex1 AND Ex2) S4 100 CONTINUE J = J’ IF (NOT Ex1) GOTO IF (NOT Ex2) GOTO 50 … מוסיפים משתנה עזר ש-"יזכור" באיזה איטרציה קפצנו החוצה על מנת שנוכל לשחזר את המשתנה האיטרציה המקורי כשהקפיצה "התרחשה". עתה ניתן לחזור על התהליך עבור הלולאה החיצונית ולהוציא גם ממנה את הקפיצות החוצה P
45
קפיצות החוצה – סקירת האלגוריתם
עבור כל הוראת קפיצה החוצה: נגדיר משתנה בוליאני חדש שיאותחל ל-true. נתנה את ביצוע הוראות הלולאה בכך שערכו של המשתנה הוא true. נחליף את הוראת הקפיצה בהשמה של ה-NOT של תנאי הקפיצה אל המשתנה. בכך נבטיח כי המשתנה יקבלfalse בפעם הראשונה שהקפיצה אמורה להתרחש. את הוראת הקפיצה נעביר לאחרי הלולאה, והיא תתבצע בתלות במשתנה החדש שהוספנו.
46
קפיצות החוצה – סקירת האלגוריתם
ייתכן כי קוד מחוץ ללולאה עושה שימוש במשתנה האיטרציה, ולכן להוסיף הוראה שתשחזר את ערכו ברגע שהקפיצה היתה אמורה להתבצע (ע"י שימוש במשתנה זמני(.
47
קפיצות החוצה – נקודות חשובות
תהליך הוצאת קפיצות החוצה מלולאה נקרא Branch Relocation. תוצר התהליך כפי שאנחנו יצרנו אותו "רע למיקבול" – יצרנו משתנה סקלרי (Ex1) המופיע בכל קוד הלולאה ולכן יוצר תלויות לאורך כל הקוד. פתרון – Scalar Expansion.
48
קפיצות החוצה – נקודות חשובות
לדוגמא הקוד: DO J = 1, M DO I = 1, N A(I,J) = B(I,J) + X IF (L(I,J)) GOTO L C(I,J) = A(I,J) + Y ENDDO D(J) = A(N,J) L: F(J) = C(10,J) ENDDO
49
קפיצות החוצה – נקודות חשובות
יהפוך ל: מערך חדש נוסף, האיבר ה-i בו הוא הערך של Ex1 באיטרציה ה-i ואיברו הראשון מאותחל ל-true. DO J = 1, M am(0,J) = TRUE DO I = 1, N IF (lm(I-1, J)) A(I,J) = B(I,J) + X IF (lm(I-1, J)) m1 = NOT(L(I,J)) am(I, J) = am(I-1, J) AND m1 IF (lm(I,J)) C(I,J) = A(I,J) + Y ENDDO IF (NOT)am(I,J)) goto L D(J) = A(N,J) L: F(J) = C(10,J) ENDDO m1 משתנה זמני המקבל את NOT של תנאי הקפיצה (זהו התנאי שלא קפצנו) מרגע הקפיצה הראשונה, כל אברי המערך יקבלו false P P P
50
קפיצות החוצה – נקודות חשובות
עתה כל ההוראות בלולאה תלויות בחישוב המערך (תלות לא מעגלית) ולכן ניתן לווקטר ולקבל: DO J = 1, M lm(0,J) = TRUE DO I = 1, N IF (lm(I-1, J)) m1 = NOT(L(I,J)) lm(I, J) = lm(I-1, J) AND m1 IF (lm(I,J)) C(I,J) = A(I,J) + Y ENDDO ENDDO WHERE (lm(0:N-1, 1:M)) A(1:N,1:M)=B(1:N,1:M)+X WHERE (lm(0:N-1, 1:M)) C(1:N,1:M)=A(1:N,1:M)+Y WHERE (lm(N,1:M)) D(1:M) = A(N, 1:M) F(1:M) = C(10, 1:M)
51
קפיצות החוצה – נקודות חשובות
ישנן ארכיטקטורות בהן קיימות הפקודות FirstTrueX, FirstFalseX המוצאות את ערך האמת (השקר) הראשון בווקטור בוליאני (כלומר מחזירות את האינדקס שלו). שימוש בפונקציות אלו יכול לחסוך לנו מספר גדול של פעולות חישוב. קיים אלגוריתם לזיהוי מצבים בהם ניתן להשתמש בפונקציות הללו, אך הוא מחוץ לתחום הרצאה זו.
52
קפיצות החוצה – נקודות חשובות
אחרי שימוש ב-FirstFalseX, נקבל: DO J = 1, M lm(0,J) = TRUE DO I = 1, N IF (lm(I-1, J)) m1 = NOT(L(I,J)) lm(I, J) = lm(I-1, J) AND m1 IF (lm(I,J) C(I,J) = A(I,J) + Y ENDDO X = FirstFalseX(lm(J)) A(J, 1:X-1) = B(J, 1:X-1) C(J, 1:X-1) = A(J, 1:X-1) ENDDO … נשם לב כי השימוש ב-FirstFalseX "עלה" לנו בצורך להכניס הפעולות הווקטוריות חזרה ללולאה החיצונית. P
53
קפיצות אחורה
54
שקול ללולאת DO-WHILE של C
קפיצות אחורה כל קפיצה אחורה יוצרת בעצם לולאה (do-while) נסתרת. L: A = A – 1 IF (A > 2) GOTO L שקול ללולאת DO-WHILE של C ברור כי לא נוכל פשוט להחליף הקוד הנ"ל בהוראות IF שכן אין הוראת IF הגורמת לקוד להתבצע (מספר לא מוגדר) של פעמים. יש אלגוריתמים המנסים להפוך קפיצות אחורה ללולאות DO רגילות, אך האלגוריתמים הנ"ל מסובכים ובמרבית המקרים התוצאות אינן מצדיקות את הרצתם. P
55
קפיצות אחורה הדרך המקובלת לטיפול בקפיצות לאחור, היא פשוט לא לטפל בהם ולקבוע שאסור לשנות את כל המשפטים שבטווח הלולאה. הבעיה שדרך זו יוצרת היא שאיננו יכולים לבצע if conversion גם לקפיצות קדימה, שכתובות הקפיצה שלהם בטווח של הקפיצה אחורה. אנו נראה שע"י התאמת משתנה בוליאני ייחודי לכל קפיצה אחורה, ניתן לעקוף בעיה זאת ונוכל להמשיך לבצע if conversions לקפיצות קדימה, גם אם כתובת הקפיצה נופלת בתחום של קפיצה אחורה.
56
קפיצות אחורה נתבונן למשל בקוד:
IF (X) GOTO S1 200 S2 IF (Y) GOTO 100 קל לראות שהפעם ההוראה בכתובת 100 יכולה להתבצע גם אם הקפיצה קדימה הראשונה נלקחת. מכאן ברור שאלגוריתם Branch removal שראינו מקודם להסרת קפיצות קדימה לא יעבוד כאן.
57
קפיצות אחורה נתבונן למשל בקוד:
IF (X) GOTO > BR1 = X BB1 = FALSE 100 IF (NOT BR1 OR (BR1 AND BB1)) THEN S1 200 IF (NOT BR1 OR (BR1 AND BB1) OR BR1) THEN S2 IF (Y) THEN DO BB1 = TRUE GOTO 100 ENDIF משתנה בוליאני האומר האם הגענו לכתובת מסויימת דרך קפיצה אחורה. יוסף תמיד בדיוק לפני תחום הלולאה. ל-guard של כתובת המטרה של הקפיצה אחורה מוסיפים (ב-OR) את האפשרות שהקפיצה קדימה נלקחה ואנו הגענו לשורה דרך הקפיצה אחורה. שינינו את הקוד כך שהוראה 100 מבוצעת רק אם הקפיצה לא נלקחה או נלקחה הקפיצה אחורה. P P P
58
אנו נתייחס לקפיצה לא מותנית כאל קפיצה מותנית שהתנאי שלה הוא TRUE
קפיצות אחורה נתבונן על מקרה מסובך יותר: IF (X) GOTO S1 GOTO 300 200 S2 IF (Y) GOTO S3 אנו נתייחס לקפיצה לא מותנית כאל קפיצה מותנית שהתנאי שלה הוא TRUE נשם לב כי אין אפשרות ש-S2 יתבצע אם הקפיצה אחורה נלקחה.
59
איבדנו את התנאי ש-S2 אינו מתבצע כאשר הקפיצה אחורה נלקחת!
קפיצות אחורה נחזור על הטריק שראינו קודם ונקבל: BR1 = X BB1 = FALSE 100 IF (NOT BR1 OR (BR1 AND BB1)) THEN S1 IF (NOT BR1 OR (BR1 AND BB1)) BR2 = TRUE 200 IF (BR1 OR BB1) THEN S2 IF (Y) THEN DO BB1 = TRUE GOTO 100 ENDIF 300 S3 איבדנו את התנאי ש-S2 אינו מתבצע כאשר הקפיצה אחורה נלקחת! P
60
קפיצות אחורה נזכור כי באלגוריתם המקורי של סילוק קפיצות קדימה, אנו מוסיפים לתנאי הפרטי של כתובת הקפיצה את התנאי עבורו הקפיצה התרחשה. מעתה בנוסף לתנאי שהקפיצה התרחשה נדרוש גם שאף קפיצה אחורה (שהקפיצה קדימה קופצת לתחומה) לא התרחשה. אלגוריתם פורמלי והוכחתו מופיעים במאמר של ALLEN: “Conversion of control dependence to data dependence”
61
קפיצות ללולאות ושיקוצים אחרים
62
פינת הקוד המטורלל כפי שנלמד בקורס "שפות תכנות", לכל control flow של תוכנית אמורה להיות כניסה יחידה ומספר כלשהו של יציאות. יחד עם זאת, יתכן שנמצא מתכנת שיחליט לבצע קפיצה אל תוך לולאה. הוראה שכזאת אומנם אסורה ב-FORTRAN אך חוקית בשפות אחרות כמו C.
63
במקרים הנ"ל נמנע מלבצע טרנפרומציות
פינת הקוד המטורלל הקוד הבא לעומת זאת כן חוקי ב-FORTRAN: INTEGER RETURN_LABEL ASSIGN 100 TO RETURN_LABEL GOTO 9000 S1 … 9000 GOTO RETURN_LABEL במקרים הנ"ל נמנע מלבצע טרנפרומציות P
64
אלגוריתם סימפליפיקציה
65
למה זה טוב? עבור קפיצות אחורה והחוצה, משתנה העזר שאנו מוסיפים מופיע רק בתחום הפונקציה. לעומת זאת, עבור קפיצות קדימה הוספת התנאים ל-guard אינה מוגבלת והיא מופיעה מהוראת הקפיצה עד סוף התוכנית. דוגמא ראינו כי הקוד: DO 100 I = 1, N IF (A(I) > 10) GOTO 60 20 S1 IF (B(I) > 10) GOTO 80 40 S2 60 S3 80 S4 100 CONTINUE הערה: ביצוע שורה 60 תלוי הן בקפיצה הראשונה והן בשניה, ולכן לא ניתן פשוט "להעלים" את משתנה הקפיצה כאשר מגיעים לכתובת הקפיצה P
66
למה זה טוב? הופך לקוד: DO 100 I = 1, N IF (true) m1 = (A(I) > 10) IF (true AND NOT (m1)) A(I)=A(I)+10 IF (true AND NOT (m1)) m2 = (B(I)>10) 40 IF (true AND NOT (m1) AND NOT (m2)) B(I)=B(I)+10 60 IF (… OR (true AND m1)) A(I) = B(I) + A(I) 80 IF (… OR (true AND NOT(m1) AND m2)) B(I)=A(I)-5 100 CONTINUE מכאן ברור כי יש צורך באלגוריתם שיקבל ביטוי בוליאני ויחזיר ביטוי בוליאני קטן יותר (מינימלי?). תזכורת: בקורס חישוביות למדנו כי אם קיים אלגוריתם כזה, אזי P=NP.
67
בחזרה לעבר... כל סטודנט לתואר ראשון כבר למד אלגוריתם מינימיזציה עוד בסמסטר הראשון ללימודיו. תזכורת: נכניס 1 לכל משבצת בטבלה המתאימה לערך בו הביטוי מקבל 1. ננסה להקיף את האחדים בעיגולים מקסימליים. לאחר מכן נבחר כמות מינימלית של עיגולים כך שכל האחדים יכוסו. באופן מפתיע מפות קרנו לא יעבדו בשבילנו הפעם (אפילו אם היינו יודעים לטפל בעזרתם ביותר מ-6 משתנים)
68
אלגוריתם Quine-McCluskey
האינטואיציה מאחורי האלגוריתם היא אותה אינטואיציה העומדת מאחורי מפות קרנו. תחילה הופכים את הביטוי ל-DNF (סכום מכפלות). אם יש שני מכפלות המזדהים על כל הליטרלים מלבד ליטרל אחד, והליטרל הנ"ל בביטוי הראשון הוא השלילה של זה מהביטוי השני, ניתן לאחדם למכפלה יחידה: פעולה זאת מזכירה הקפה בעיגול של אחדים סמוכים במפת קרנו.
69
אלגוריתם Quine-McCluskey
נציג כל Term (מכפלה) ב-DNF כווקטור בינארי, כך שהביט ה-i בווקטור יציין האם המשתנה ה-i מופיע במכפלה בפאזה חיובית או שלילית. הוקטור יציין המכפלה: הוקטור יציין המכפלה:
70
אלגוריתם Quine-McCluskey
נציג כל Term (מכפלה) ב-DNF כווקטור בינארי, כך שהביט ה-i בווקטור יציין האם המשתנה ה-i מופיע במכפלה בפאזה חיובית או שלילית. אם קיים TERM שאינו מכיל את כל המשתנים, נשכפלו ונוסיף לעותקיו את כל צירופי הליטרלים החסרים.
71
אלגוריתם Quine-McCluskey
נציג כל Term (מכפלה) ב-DNF כווקטור בינארי, כך שהביט ה-i בווקטור יציין האם המשתנה ה-i מופיע במכפלה בפאזה חיובית או שלילית. אם קיים TERM שאינו מכיל את כל המשתנים, נשכפלו ונוסיף לעותקיו את כל צירופי הליטרלים החסרים. נעבור על כל הזוגות האפשריים של המכפלות, כל פעם שנפגוש זוג המזדהה על כל הליטרלים מלבד אחד נסמן הזוג כ-"שומש" ונרשום בצד את "מכפלת התוצאה". נחזור על התהליך עד ל-fix point.
72
דוגמא 000- 01-1 10-- 1-1- קבוצת משתנים מקורית קבוצת מצומצמת א קבוצת מצומצמת ב סה"כ 9 סה"כ 10 סה"כ 2
73
דוגמא נותרנו המכפלות הבאות (לא סומנו). 000- 01-1 10-- 1-1- -111
74
אלגוריתם Quine-McCluskey
בסוף שלב זה ניוותר עם קבוצה של מכפלות שלא סומנו - נקראות גם prime terms. כל שנותר הוא לבחור תת קבוצה מינימלית של אותם prime terms, שתחסה את כל המכפלות המקוריות. נהוג להיעזר בטבלה ששורותיה הם המכפלות המקוריות, עמודותיה הם ה-prime terms, והתא המתאים מכיל X אם ורק אם ה-prime term מחסה את המכפלה המקורית. במידה שיש שורה המכילה X אחד בלבד, הרי שרק prime term אחד מחסה את המכפלה הנידונה. למכפלה כזאת נקרא essential prime term וחייבים לבחור אותה.
75
בחזרה לדוגמא שלנו... נבנה את הטבלה שמתקבלת:
מכפלות שלא סומנו נבנה את הטבלה שמתקבלת: TERMים מקוריים במקרה שלנו ’01-1’ ו-’10--’ הם דוגמאות ל-essential prime terms.
76
סיבוכיות Quine-McCluskey
נעזוב בנתיים את אופן קבלת ה-DNF. מעבר על כל זוגות המכפלות בשלב השני לוקח על פניו זמן אקספונציאלי. * קיים אלגוריתם המבצע זאת בזמן פולינומיאלי במספר המשתנים אך דרישת מקום אקספוננציאלית. מציאת הביטוי המינימלי בשלב האחרון מה-prime terms שקיבלנו אורך גם כן זמן אקספוננציאלי. זהו האלגוריתם המקורי שנוסה כאלגוריתם סימפליפיקציה ל-IF Conversion ונמצא איטי מידי.
77
סימפליפיקציה ל-IF CONVERSION
תזכורת: אנו נבצע סימפליפיקציה רק עבור קפיצות קדימה. בקפיצות קדימה אנו "מוסיפים" ל-guard משתנים כאשר: 1) החל מהוראת הקפיצה עצמה, מבצעים AND בין guard נוכחי והשלילה של תנאי הקפיצה. 2) בכתובת הקפיצה, מוסיפים (OR) לתנאי הפרטי: (<guard בשלב הקפיצה> AND <תנאי הקפיצה>). לכן קל לשמור את ה-guard במצב DNF לכל אורך הריצה:
78
סימפליפיקציה ל-IF CONVERSION
מאחר שהגעה לביטוי מינימלי זו שאיפה כבדה מידי, אנו נסתפק בשאיפה בכל רגע נתון להישאר עם מספר מינימלי של משתנים. תזכורת - בקוד: DO 100 I = 1, N IF (A(I) > 10) GOTO 60 20 S1 IF (B(I) > 10) GOTO 80 40 S2 60 S3 80 S4 100 CONTINUE שורה 60 תלויה בתוצאות שני הקפיצות. שורה 80 מתבצעת תמיד. לכן לא נוכל להעיף משתנים משורה 60, נאלץ להמתין לכתובת הקפיצה של הקפיצה השנייה (שורה 80).
79
סימפליפיקציה ל-IF CONVERSION
משפט: ניתן לסלק משתני קפיצה בסדר הפוך בלבד לסדר בו פגשנו בהם. הוכחת המשפט אינה טריוויאלית ולא תינתן.
80
סימפליפיקציה ל-IF CONVERSION
מתוך משפט זה ואלגוריתם Quine-McCluskey מקבלים אלגוריתם סימפליפיקציה נוח עבור IF CONVERSION: א. בכל שלב נחזיק DNF בו כל TERM מכיל את כל משתני הקפיצה שעוד לא הצלחנו להעיף. ב. סדר המשתנים בכל TERM יהיה בסדר הפוך לסדר בו פגשנו את ה-branchים המתאימים להם. ג. נבדוק האם לכל TERM בו מופיע המשתנה brn קיים בן זוג (TERM) בו המשתנה מופיעה בשלילה. אם כן נסלק את המשתנה מה-guard.
81
סימפליפיקציה ל-IF CONVERSION
בספר מובא מימוש של אלגוריתם זה המוציא מה-guard את כל המשתנים שניתן בזמן ליניארי. נשם לב כי האלגוריתם עדיין עובד בסיבוכיות מקום אקספוננציאלית במספר המשתנים. אנו נותרים עם מספר גדול של משתנים רק במקרים בהם כתובת הקפיצה של הוראת הקפיצה האחרונה היא אחרי הכתובות של כל הוראות הקפיצה הקודמות. מקרה זה נדיר (יחסית) ובמקרים כאלו בכל מקרה גודל ה-guard הוא אקספוננציאלי במספר המשתנים גם עם סימליפיקציה אופטימלית.
82
IF Reconstruction
83
IF Reconstruction ביצוע IF Conversion כרוך במאמצים לא מבוטלים מצד ה-compiler, למשל בביצוע סימפליפיקציות. יתכן כי גם אחרי שכל המאמצים הושקעו, וכל תלויות הבקרה נהפכו לתלויות מידע, עדיין לא ניתן למקבל את הלולאה, למשל: DO 100 I=1, N IF (A(I) > 0) GOTO 100 B(I) = A(I) * A(I+1) = B(I) + 1 100 CONTINUE
84
IF Reconstruction ביצוע IF Conversion כרוך במאמצים לא מבוטלים מצד ה-compiler, למשל בביצוע סימפליפיקציות. יתכן כי גם אחרי שכל המאמצים הושקעו, והפכנו כל תלויות הבקרה לתלויות מידע, עדיין לא ניתן לווקטר את הלולאה. למצב זה שני חסרונות עיקריים: א. IF Conversion גורם לניפוח קוד מיותר. ב. לולאות בהם קיימת קפיצה החוצה, שבעבר ייתכן שהייתה נלקחת לקראת תחילת ביצוע הלולאה, עתה בהכרח יתבצעו עד סופם.
85
IF Reconstruction לצערנו, אין בידינו אלגוריתם הקובע מראש את הכדאיות של If Conversion (האם ניתן יהיה למקבל את התוצאה). גם אם הצלחנו למקבל את הלולאה, ייתכן שהקוד ירוץ לאט יותר! ניתן כמובן פשוט לשחזר את המצב ההתחלתי במידה וגילינו כי התוצאה אינה ניתנת למיקבול.
86
IF Reconstruction קיימים אלגוריתם מתוחכמים יותר, אשר יודעים לקחת את התוצאה של If conversion ולהפוך אותה חזרה לקפיצות מותנות בדרך יעילה כך ש-branchים מיותרים שהיו בקוד המקור אינם מופיעים עוד בתוצאה. משפחת אלגוריתמים אלו נקראת IF Reconstruction והיא לא בתחום של הרצאה זאת.
87
תלויות בקרה של לולאות
88
תלויות בקרה של לולאות הרעיון: קיימת תלות בקרה בין ההוראות בגוף הלולאה לבין תחום הלולאה. לדוגמא, נתבונן בקטע הקוד הבא: DO 120 I=1, L = 2*I DO 100 J=1, L A(I,J) = 0 100 ENDDO 120 ENDDO בחינה מהירה של הקוד מראה כי אין בו תלויות מידע או קפיצות מותנות.
89
תלויות בקרה של לולאות קטע קוד לא שקול
DO 120 I=1, L = 2*I DO 100 J=1, L A(I,J) = 0 100 ENDDO 120 ENDDO אם נווקטר את הקוד כפי שביצענו עד היום נקבל התוצאה הבאה: DO 120 I=1, L = 2*I 120 ENDDO A(1:100,1:L) = 0 קטע קוד לא שקול P
90
תלויות בקרה של לולאות כאמור, הבעיה בדוגמא היא שהחמצנו תלות הקיימת בין תחום הלולאה הראשונה לבין ההוראות שלה. הפתרון הוא שנהפוך גם תלות זאת לתלות מידע. נוסיף משתנה "תחום", ונאתחל את ערכו לתחום הלולאה בדיוק לפני חישוב תחום הלולאה בתוכנית המקורית. נוסיף לגרף התלויות קשתות המציינות שכל הוראה בלולאה תלויה (תלות מידע) במשתנה התחום של הלולאה.
91
תלויות בקרה של לולאות הקוד של הדוגמא: DO 120 I=1, 100 L = 2*I
DO 100 J=1, L A(I,J) = 0 100 ENDDO 120 ENDDO
92
תלויות בקרה של לולאות יהפוך ל: עתה נבצע constant propagation ונקבל:
irange1 = (1,100) DO 120 I=1, L = 2*I (irange1) irange2 = (1,L) (irange1) DO 100 J=1, L A(I,J) = 0 (irange2) (irange1) 100 ENDDO 120 ENDDO יהפוך ל: עתה נבצע constant propagation ונקבל: P
93
תלויות בקרה של לולאות 20 DO 120 I=1, L = 2*I (1,100) 60 DO 100 J=1, L 80 A(I,J) = 0 (1,L) (1,100) 100 ENDDO 120 ENDDO מצאנו תלות loop independent dependent בין הוראות 40 ו-80 ולכן הויקטור היחיד שנוכל לעשות הוא של שורה 80. 20 DO 120 I=1, L = 2*I A(I, 1:L) = ENDDO
94
גרף התלויות
95
רקע כללי כאמור, החיסרון העיקרי של IF conversion הוא שאיננו יודעים מראש האם ניתן יהיה למקבל את התוצאה – ייתכן שנעבוד לחינם. גרף התלויות הוא פתרון אחר לבעיית תלויות הבקרה. הוא יאמר לנו מתי מותר לבצע כל הוראה, מה שיאפשר לנו לבצע הוראות במקביל.
96
קצת הגדרות... הגדרה – בלוק בסיסי הוא אוסף מקסימלי של הוראות כך שכל הוראה באוסף מתבצעת אם ורק אם כל יתר ההוראות מתבצעות. למען הפשטות, אנו נתייחס לכל הוראה בקוד כאל בלוק בסיסי.
97
קצת הגדרות... הגדרה – גרף הזרימה עבור תוכנית יוגדר: * קבוצת הצמתים תכיל צומת התחלה יחיד וצומת סיום יחיד + צומת עבור כל בלוק בסיסי. * כל קשת בין שני צמתים (x,y) מציינת שקיים מסלול בקרה בו בלוק y מבוצע אחרי בלוק x. למען הפשטות, אנו נניח מרגע זה ועד סוף המצגת כי אנו מתמודדים רק עם קפיצות קדימה.
98
דוגמא לגרף זרימה צומת 1 – צומת הכניסה צומת 7 – צומת היציאה
צומת 1 – צומת הכניסה צומת 7 – צומת היציאה בבלוק 1 יש הוראת קפיצה שתוביל אותנו לבלוק 2 אם הקפיצה נלקחה ולבלוק 3 אחרת. נשם לב כי העובדה שאנו עוסקים רק בקפיצות קדימה מבטיחה שאין מעגלים בגרף. 1 2 3 5 6 4 7
99
קצת הגדרות... הגדרה – אנו נאמר כי צומת y נשלטת (postdominated) ע"י צומת x בגרף הזרימה אם ורק אם כל מסלול בין צומת x לצומת הסיום עובד דרך צומת y.
100
דוגמא לתכונת השליטה צומת 6 נשלטת ע"י צמתים 3,4.
צומת 5 אינו נשלט ע"י צומת 2. צומת 7 נשלט ע"י כל הצמתים האחרים. צומת 2 לא נשלט ע"י אף צומת. 1 2 3 4 5 6 7
101
קצת הגדרות... הגדרה – אנו נאמר כי צומת y נשלטת מיידית (imidiate postdominated) ע"י צומת x אם ורק אם y הוא הצאצא הראשון של x הנשלט על ידו בגרף הזרימה. צאצא ראשון – מרחק מינימלי. ההגדרה מוגרת היטב שכן אין מעגלים בגרף הזרימה. בפרט, כל צומת שולט מיידית על צומת אחד לכל היותר.
102
בניית "עץ" שליטה מיידית 1 1 2 3 2 3 4 4 5 6 5 6 "עץ" הפוך 7 7 קיים אלגוריתם לבניית "עץ" שליטה מיידית בזמן "כמעט ליניארי" (עד כדי פונקצית ארקמן בגודל העץ).
103
קצת הגדרות... הגדרה – אנו נאמר כי לצומת y תלות בקרה (control dependence) בצומת x אם ורק אם קיים מסלול מ-x ל-y כך שלכל צומת z≠x במסלול y נשלטת ע"י z, וכן y אינה נשלטת ע"י x. אינטואיציה: לצומת y יש תלות בקרה בצומת x אם צומת x יכול לקבוע האם צומת y יתבצע. כלומר יש מסלול מ-x בו y בהכרח מתבצע, ויש מסלול מ-x בו y לא בהכרח יתבצע. P
104
אלגוריתם מציאת תלויות בקרה
בצע מיון טופולוגי על "עץ" השליטה המיידית. עבור על הצמתים ע"פ הסדר במיון. יהי x הצומת הנוכחי במיון: א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y: ב. עבור כל צומת z כך ש-x נשלט מיידית ע"י z, עבור על כל צומת y ש-z תלוי בה (CD(z)), אם x לא נשלט מיידית ע"י y אזי x תלוי ב-y: P P
105
אלגוריתם לבניית גרף בקרה
1 1 ה ב 2 3 2 3 ג 4 4 ו ד 5 6 5 6 ז 7 7 בצע מיון טופולוגי על "עץ" השליטה המיידית ועבור על הצמתים ע"פ סדר המיון.
106
אלגוריתם לבניית גרף בקרה
1 1 ה ב 2 3 2 3 ג 4 4 ו ד 5 6 5 6 ז 7 7 א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y.
107
אלגוריתם לבניית גרף בקרה
1 1 ה ב 2 3 2 3 ג 4 4 ו ד 5 6 5 6 ז 7 7 ב. עבור כל צומת z כך ש-x נשלט מיידית ע"י z, עבור על כל צומת y ש-z תלוי בה (CD(z)), אם x לא נשלט מיידית ע"י y אזי x תלוי ב-y.
108
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג 4 4 ו ד 5 6 5 6 ז 7 7 א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y.
109
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג 4 4 ו ד 5 6 5 6 ז 7 7 ב. עבור כל צומת z כך ש-x נשלט מיידית ע"י z, עבור על כל צומת y ש-z תלוי בה (CD(z)), אם x לא נשלט מיידית ע"י y אזי x תלוי ב-y.
110
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג {2,3} 4 4 ו ד 5 6 5 6 ז 7 7 א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y.
111
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג {2,3} 4 4 ו ד 5 6 5 6 ז 7 7 ב. עבור כל צומת z כך ש-x נשלט מיידית ע"י z, עבור על כל צומת y ש-z תלוי בה (CD(z)), אם x לא נשלט מיידית ע"י y אזי x תלוי ב-y.
112
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג {2,3} 4 4 ו ד 5 6 5 6 ז 7 7 א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y.
113
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג {2,3} 4 4 ו ד {1,2} 5 6 5 6 ז 7 7 ב. עבור כל צומת z כך ש-x נשלט מיידית ע"י z, עבור על כל צומת y ש-z תלוי בה (CD(z)), אם x לא נשלט מיידית ע"י y אזי x תלוי ב-y.
114
אלגוריתם לבניית גרף בקרה
1 1 {1} ה ב 2 3 2 3 ג {2,3} 4 4 ו ד {1,2} 5 6 5 6 ז 7 7 דוגמא לתלות צומת 6: עבור צומת 1, אם נבחר בקשת הצהובה מובטח שנבקר ב-6, אחרת יתכן שנבקר ב-6 וייתכן שלא
115
תוצאת האלגוריתם עבור הדוגמא
1 1 {1} {1} ה ב 2 3 2 3 ג {2,3} 4 4 ו ד {2} {1,2} 5 6 5 6 ז 7 7
116
עוברים על כל קשת בגרף הזרימה פעם אחת בדיוק
סיבוכיות האלגוריתם בצע מיון טופולוגי על "עץ" השליטה המיידית. עבור על הצמתים ע"פ הסדר במיון. א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y. יהי x הצומת הנוכחי במיון: נשם לב כי כל צומת שולטת מיידית בצומת אחת לכל היותר, לכן ניתן להכיל את "עץ" השליטה מיידית במערך עוברים על כל קשת בגרף הזרימה פעם אחת בדיוק P P P
117
סיבוכיות האלגוריתם בצע מיון טופולוגי על "עץ" השליטה המיידית.
עבור על הצמתים ע"פ הסדר במיון. יהי x הצומת הנוכחי במיון: א. עבור כל אב y של x בגרף הזרימה, אם x לא נשלט מיידית על ידי y אזי x תלוי ב-y ב. עבור כל צומת z כך ש-x נשלט מיידית ע"י z, עבור על כל צומת y ש-z תלוי בה (CD(z)), אם x לא נשלט מיידית ע"י y אזי x תלוי ב-y. כל צומת שולטת מיידית על צומת אחת בדיוק, ולכן הבדיקה הראשונה מבוצעת V פעמים. הבדיקה השנייה חסומה ע"י מספר תלויות הבקרה. P
118
סיבוכיות האלגוריתם הסיבוכיות הכוללת יוצאת:
זוהי סיבוכיות ליניארית בגודל הקלט והפלט, ולכן מובטח כי לא קיים אלגוריתם טוב יותר מבחינה אסימפטותית. נשם לב כי קבוצת התלויות CD יכולה להיות ריבועית בגודל גרף הזרימה:
119
סיבוכיות האלגוריתם 1 {1} {1,2} 2 3 {2} {1,2,4} 4 5 ... ... {2n-2}
120
בניית גרף תלויות עבור לולאות
הראנו אלגוריתם שמוצא את כל תלויות הבקרה שיש להוראה x בהוראות אחרות בתוכנית. מהתלויות הללו ניתן לבנות את גרך תלויות הבקרה (The control dependence graph) שצמתיו הם הבלוקים הבסיסיים של התוכנית, ובין שני בלוקים קיימת קשת אם הם תלויים זה בזה, שכיוונה מהמקור ל-sink. בהינתן לולאה בקוד נוסיף לגרף צומת שייצג את גוף הלולאה, ונוסיף קשת (תלות) בין צומת זאת לבין כל הוראה בלולאה שביצוע לא תלוי בהוראה אחרת בלולאה.
121
בניית גרף תלויות עבור לולאות
דוגמא: 1 DO I=1, A(I) = A(I) + B(I) 3 IF (A(I) > 0) GOTO A(I) = -A(I) 5 B(I) = A(I) + C(I) ENDDO 1 2 5 4 3 F צומת מס' 1 היא צומת הלולאה. ה-F על קשת (3,4) מציינת שהוראה 4 מבוצעת רק אם תנאי הקפיצה בהוראה 3 מוערך ל-false.
122
מודל לביצוע מקבילי
123
מודל לביצוע מקבילי לכל הוראה (בלוק בסיסי) בקוד נתאים דגל ביצוע בוליאני. לכל הוראה שלא תלויה בהוראות אחרות, נאתחל דגל הביצוע ל-true. לכל יתר ההוראות יאותחל הדגל ל-false. הדגל של הוראה x ישונה מ-false ל-true כאשר קיימת הוראה y כך ש-x תלויה ב-y, וחישוב תנאי התלות ב-y מחייבת את ביצוע של x. ניתן לבצע במקביל את כל ההוראות שהדגל שלהם נקבע ל-true, וכל ההוראות שהם תלויות בהן מקיימות: או שהדגל שלהם false או שהם התבצעו כבר.
124
מודל לביצוע מקבילי כאשר מגיעים לביצוע ראש של לולאה נפריד לשני מקרים: א. תחום הלולאה קבוע - נקבע את הדגל של הראש הלולאה ל-true לכל צומת (הוראה) בלולאה נכין N עותקים (כאשר N הוא מספר האיטרציות הצפוי). - קבע את הדגלים של כל הצמתים התלויים ישירות בראש הלולאה ל-true.
125
מודל לביצוע מקבילי בדוגמא הקודמת (תחום לולאה קבוע):
הדגל הבוליאני של 1 יקבע ל-true. צמתים 2,3,5 "ישוכפלו" 100 פעמים, וכל צומת יקבל ערך true. צומת 4 ישוכפל 100 פעמים והדגל שלו יאותחל ל-false וישונה ל-true רק אם בחישוב הוראה 3 מתאימה נקבל כי תנאי הקפיצה הוא false. 1 2 3 5 F 4 1 DO I=1, A(I) = A(I) + B(I) 3 IF (A(I) > 0) GOTO A(I) = -A(I) 5 B(I) = A(I) + C(I) ENDDO
126
מודל לביצוע מקבילי כאשר מגיעים לביצוע ראש של לולאה נפריד לשני מקרים:
ב. תחום הלולאה אינו קבוע - ניצור i עותקים מכל הוראה בלולאה, כאשר i זה התחום שאנו יודעים שהלולאה תתבצע בה בזמן ביצוע הצומת. - נקבע ערך true לדגלים של כל העתקים שיצרנו. - נקבע ערך true לדגל של צומת הלולאה אם היא תלויה data dependence באחד הצמתים בלולאה ו-false אחרת. נכונות המודל מושגת באינדוקציה על סדר ביצוע הצמתים. P
127
שימוש במודל לביצוע מקבילי
נזכור כי אנו מסתכלים רק על לולאות עם קפיצות קדימה. קפיצה קדימה יוצרת loop independent dependence. בהנחה שאיננו משנים סדר ביצוע ההוראות בלולאה, loop fusion ו-loop distribution הם הטרנספורמציות היחידות המושפעות מהתלות. מאחר שאנו לא מתייחסים לקפיצות החוצה, loop fusion מתבצעת באופן נכון שכן מובטח שכתובת הקפיצה (ולכן כל ההוראות המושפעות ממנה) נמצאים בלולאה המקורית.
128
הבעיה: control dependence חוצה את שני קטעי הלולאה המחולקת
שימוש במודל לביצוע מקבילי המצב שונה עבור loop distribution. ברור כי הטרנספורמציה הבאה שגויה: DO I=1, N 1 IF (A(I) < B(I)) GOTO B(I) = B(I) + C(I) 3 CONTINUE DO I=1, N 1 IF (A(I) < B(I)) GOTO 3 ENDDO DO I=1, N 2 B(I) = B(I) + C(I) ENDDO 3 CONTINUE הבעיה: control dependence חוצה את שני קטעי הלולאה המחולקת P
129
פתרון אפשרי: נתפוס את תנאי הקפיצה, בדומה ל-IF Conversion
שימוש במודל לביצוע מקבילי המצב שונה עבור loop distribution: DO I=1, N 1 IF (A(I) < B(I)) GOTO B(I) = B(I) + C(I) 3 CONTINUE פתרון אפשרי: נתפוס את תנאי הקפיצה, בדומה ל-IF Conversion DO I=1, N 1 E(I) = (A(I) < B(I) ENDDO DO I=1, N 2 IF (NOT(E(I))) B(I) = B(I) + C(I) ENDDO 3 CONTINUE P
130
שימוש במודל לביצוע מקבילי
ב-IF Conversion ניסינו להפוך כל תלויות בקרה לתלויות מידע ואז למקבל. עתה אנו קודם מנסים למקבל, ומתבוננים בתוצאה. אם במהלך המיקבול פיצלנו לולאה למספר תתי לולאות כך שיש תלות בקרה שחוצה עתה שני לולאות, נשמור את משתני ההחלטה במקור של התלות בווקטור חדש שנוסיף, ונקרא המשתנים כשנזדקק להם בלולאה השנייה.
131
שימוש במודל לביצוע מקבילי
דוגמא: DO I=1, N 1 IF (A(I) < 0) THEN 2 IF (B(I)-A(I)>1) GOTO 4 ENDIF 3 A(I)=B(I) GOTO 8 4 IF (A(I) > T) THEN 5 T = B(I) – A(I) + T ELSE 6 T = T + B(I) - A(I) 7 B(I) = A(I) ENDIF 8 C(I)=B(I)+C(I) ENDDO 1 2 6 4 3 F 5 8 7 T גרף הזרימה
132
שימוש במודל לביצוע מקבילי
דוגמא: DO I=1, N 1 IF (A(I) < 0) THEN 2 IF (B(I)-A(I)>1) GOTO 4 ENDIF 3 A(I)=B(I) GOTO 8 4 IF (A(I) > T) THEN 5 T = B(I) – A(I) + T ELSE 6 T = T + B(I) - A(I) 7 B(I) = A(I) ENDIF 8 C(I)=B(I)+C(I) ENDDO 6 7 "עץ" שליטה מיידית 8 5 4 3 2 1
133
שימוש במודל לביצוע מקבילי
דוגמא: DO I=1, N 1 IF (A(I) < 0) THEN 2 IF (B(I)-A(I)>1) GOTO 4 ENDIF 3 A(I)=B(I) GOTO 8 4 IF (A(I) > T) THEN 5 T = B(I) – A(I) + T ELSE 6 T = T + B(I) - A(I) 7 B(I) = A(I) ENDIF 8 C(I)=B(I)+C(I) ENDDO גרף תלויות בקרה 1 2 6 4 3 F 5 7 T
134
שימוש במודל לביצוע מקבילי
דוגמא אחרי חלוקת לולאות והוספת תלויות מידע: DO I=1, N 1 IF (A(I) < 0) THEN 2 IF (B(I)-A(I)>1) GOTO 4 ENDIF 3 A(I)=B(I) GOTO 8 4 IF (A(I) > T) THEN 5 T = B(I) – A(I) + T ELSE 6 T = T + B(I) - A(I) 7 B(I) = A(I) ENDIF 8 C(I)=B(I)+C(I) ENDDO לולאה 1 מקבילית 1 F T F 2 3 T לולאה 2 לא מקבילית 4 T F 5 6 F לולאה 3 מקבילית 7 8 P
135
שימוש במודל לביצוע מקבילי
דוגמא אחרי חלוקת לולאות והוספת תלויות מידע: הוראה 4, תלויה בהוראה 2 ולכן עלינו להעביר את תוצאות הקפיצות בהוראה 2 להוראה 4. כאשר מתבוננים בהוראה 2 רואים שיש שלוש אפשרויות: א. הוראה 2 מבוצעת והקפיצה להוראה 4 נלקחת. ב. הוראה 2 מבוצעת והקפיצה להוראה 4 אינה נלקחת. ג. הוראה 2 אינה מבוצעת כלל. מכאן אנו למדים כי המערך שעלינו להעביר להוראה 4 צריך להכיל 3 ערכים אפשריים: TRUE (תנאי הקפיצה היה אמת), FALSE או UNDEFINED. 1 F לולאה 1 T F 2 3 T 4 T לולאה 2 F 5 6 F 7 לולאה 3 8
136
אלגוריתם לטיפול בפיצול לולאות
נסמן ב-P את קוד הלולאה המקורי ונניח כי Pi זו הלולאה ה-i שהתקבלה מהלולאה המקורית. עבור על כל ה-Piים ע"פ הסדר, לכל Pi בדוק בגרף תלויות הבקרה האם קיימת תלות מהוראה ב-Pi להוראה ב-Pj כך ש-j≠i. לכל תלות כזאת: א. אתחל מערך של משתנים בוליאנים בגודל תחום הלולאה ל-undefined. ב. החלף את הוראת הקפיצה בהוראה בה המשתנה הבוליאני שהוספנו מקבל את הערך של תנאי הקפיצה. ג. נסמן ב-u את צומת מקור התלות בגרף התלויות. לכל צומת v כך שהקשת (u,v) בגרף התלויות, הוסף לפני ההוראה המתאימה לה בקוד הוראת if הבודקת האם התא המתאים במערך שווה לערך הרשום על הקשת (בגרף התלויות). ד. מחק הקשתות (u,v) מגרף התלויות, הוסף צומת v’ לפני כל צומת v, קבע תלות מידע בין הצמתים u ו-v’ ותלות בקרה בין צמתי v’ ו-v.
137
שימוש במודל לביצוע מקבילי
PARALLEL DO I=1, N E2(I) = UNDEFINED 1 IF (A(I) < 0) THEN 2 E2(I) = (B(I)-A(I)>1) ENDIF 3 IF (NOT(E2(I)) A(I)=B(I) ENDDO DO I=1, N E4(I) = UNDEFINED IF (E2(I)) THEN E4(I) = (A(I) > T) 4 IF (E4(I)) THEN 5 T = B(I) – A(I) + T ELSE 6 T = T + B(I) - A(I) ENDIF ENDIF ENDDO PARALLEL DO I = 1, N IF (NOT(E4(I)) 7 B(I) = A(I) ENDIF 8 C(I)=B(I)+C(I) ENDDO DO I=1, N 1 IF (A(I) < 0) THEN 2 IF (B(I)-A(I)>1) GOTO 4 ENDIF 3 A(I)=B(I) GOTO 8 4 IF (A(I) > T) THEN 5 T = B(I) – A(I) + T ELSE 6 T = T + B(I) - A(I) 7 B(I) = A(I) ENDIF 8 C(I)=B(I)+C(I) ENDDO תוצאת האלגוריתם
138
שימוש במודל לביצוע מקבילי
2 6 4 3 F 5 7 T 8 ‘4 7’ 1 לולאה 1 לולאה 2 לולאה 3 1 F לולאה 1 T F 2 3 תוצאת האלגוריתם T 4 T לולאה 2 F 5 6 F 7 לולאה 3 8
139
ייצור קוד
140
לצומת 5 נכנסות שני תלויות בקרה!
ייצור קוד דוגמא: DO I=1, N 1 IF (p1) GOTO 3 2 S2 GOTO 5 3 IF (p3) THEN 4 S4 GOTO 6 ENDIF 5 S5 6 S6 ENDDO 1 6 לולאה 1 F 2 1a 1b T F 3 5 לצומת 5 נכנסות שני תלויות בקרה! לולאה 2 4
141
ייצור קוד קוד להפעלת צומת 5 צריך להיראות כך: 1 6 2 1a 1b 3 5 4
DO I=1, N p1a3 = (E1(I) AND NOT p3) IF (p1a3) S4 IF (NOT)p3) OR NOT(E1(I)) S5 ENDDO 1 6 לולאה 1 F 2 DO I=1, N 1 IF (p1) GOTO 3 2 S2 GOTO 5 3 IF (p3) THEN 4 S4 GOTO 6 ENDIF 5 S5 6 S6 ENDDO 1a 1b T F F 3 5 קוד מקורי לולאה 2 4
142
ייצור קוד בדוגמא הקודמת רואים כי יותר פשוט ליצר קוד כאשר תלויות הבקרה מהווים יער – כלומר לכל צומת נכנסת קשת אחת בדיוק. בספר מוגדרת צורה קנונית להצגת תלויות בקרה: א. לכל צומת נכנסת קשת של תלות בקרה אחת בדיוק. ב. ניתן לבצע מיון טופולוגי על העצים, כך שקשתות של תלויות מידע יופיעו רק מעץ i לעץ j במיון כאשר i<j. ניתן להבטיח כי לכל צומת תכנס תלות בקרה יחידה ע"י שכפול כל צומת v אליה נכנסת יותר מקשת אחת (הוספת v’), ולחשב ב-v’ את OR על כל התנאים הלוגיים שהיו דורשים ביצוע של v. עתה v תהיה תלויה תלות בקרה ב-v’ בלבד, ו-v’ תהיה תלויה בכל הצמתים שקדמו לה.
143
ייצור קוד האלגוריתם שמבטיח מיון טופולוגי של העצים ביער (תחת תלויות מידע) מסובך יותר ומבוסס על ורסיה על loop fusion שנלמד בהרצאה הקודמת. עתה קיבלנו את הצורה הקנונית של גרף התלויות ואנו מוכנים לייצר את הקוד. בספר יש תיאור של אלגוריתם המשתרע על פני 3 עמודים המבצע את העבודה. הוא על המיון הטופולוגי, ו-"מחליט" באיזו הוראת IF לעטוף כל בלוק בסיסי ע"פ תלות הבקרה היחידה שיש לו (לכל היותר).
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.