יצירת קוד asu פרק 9. 2 יצירת קוד syntax analysis semantic analysis code...
Post on 18-Dec-2015
222 views
TRANSCRIPT
יצירת קוד
ASU 9פרק
2
יצירת קוד
syntax analysis
semantic analysis
code generation
syntax tree
intermediate code
דרישות)יצירת קוד בעל איכות טובה )ניצול יעיל של משאבי המכונה האלגוריתמים ליצירת קוד צריכים להיות יעילים במידה סבירה
, עושים שימוש NP-complete)מכיוון שחלק מהבעיות הן באלגוריתמים היוריסטיים(
3
code generatorשיקולים עיקריים בבניית
תכנון נאות של שפת הביניים, כולל העברה של )הנחה – אין שגיאות בקוד front endאינפורמציה מה-
הביניים(
שפת המטרהabsolute machine code
תוכניותcom-ב DOSלא ממש קיים בארכיטקטורות מודרניות
relocatable code קבציobj קבצי( tpu)'וכו ,
assembly language
4
code generatorשיקולים עיקריים בבניית
ניהול זיכרון?היכן נמצא משתנה במהלך הביצועמיפוי התוכנית לזיכרון; חישוב תוויות
בחירת פקודות מכונה
( pairing, assignment, allocation)הקצאת רגיסטרים
וב- pipeliningבחירת סדר החישוב תוך התחשבות ב- caching
5
מבנה מכונת המטרה
הנחות לצורך הדיוןbyte addressability4-byte wordsn – רגיסטרים R0, . . . Rn-1
מבנה הפקודותOP source, destination
צורת האופרנדים
modeformaddressadded cost
absoluteMM1
registerRR0
indexedc ) R (c + content ) R (1
indirect register* Rcontent ) R (0
indirect indexed* c ) R (content ) c + content ) R ( ( 1
literal# cc )constant – not an address(1
6
דוגמאות
MOV R0,123
בזכרון.123 לכתובת 0העתק את הערך של רגיסטר .2עלות כוללת =
ADD 4)R0(,123
.123{, לכתובת 0 ועוד ערך רגיסטר 4הוסף את הערך שבכתובת הזכרון }.3עלות כוללת =
SUB *4)R0(,R1
.R1, מ-R0+4החסר את הערך שבתא הזכרון, שכתובתו נמצאת בכתובת )R1:= R1 - *)4+R0(( = 2 עלות כוללת.
MOV #1,R0
.R0" ל-1כתוב את הערך ".2עלות כוללת =
7
run time storage management
call, return, haltנתרכז בפקודות
הקצאה סטטית )לא ע"ג מחסנית(
three address code
/* code for c */
action1
call p
action2
halt/* code for p */
action3
return
activation record for c )64 bytes(
activation record for p )88 bytes(
0:return address0:return address8:arr4:buf
56:i60:j
84:n
goto *callee.static_area
move #here + 20 , callee.static_area
goto callee.code_area
8
run time storage managementדוגמא –
/* code for c */100:ACTION1
120:MOV # 140 , 364/* save return address 140 */132:GOTO 200/* call P */140:ACTION2
160:HALT. . .
/* code for p */200:ACTION3
220:GOTO *364/* return to address saved in location 364 */. . .
/* 300-363 hold activation record for c */300:/* return address */304:/* local data for c */
. . ./* 364-451 hold activation record for p */
364:/* return address */368:/* local data for p */
9
run time storage managementניהול מחסנית –
main
MOV #stackstart , SP
… code for the first 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 (
הוא ערך סטטיcaller.recordziseהנחה סמויה –
רגיסטר מיוחד, מצביע לראש המחסנית. יצביע לראש רשומת ההפעלה הנוכחית.
10
ניהול מחסנית – דוגמא
three address code
/* code for s */
action1
call q
action2
halt
/* code for p */
action3
return
/* code for q */
action4
call p
action5
call q
action6
call q
return
11
code for scode for q100:MOVE #600,SPinitialize the stack300:ACTION4conditional jump108:ACTION1320:ADD #qsize,SP128:ADD #ssize,SPcall sequence begins328:MOV #344,*SPpush return address136:MOV #152,*SPpush return address336:GOTO 200call p144:GOTO 300call q344:SUB #qsize,SP152:SUB #ssize,SPrestore SP352:ACTION5
160:ACTION2372:ADD #qsize,SP180:HALT380:MOV #396,*SPpush return address
. . .388:GOTO 300call qcode for p396:SUB #qsize,SP
200:ACTION3404:ACTION6
220:GOTO *0)SP(return424:ADD #qsize,SP. . .432:MOV #448,*SPpush return address
440:GOTO 300call q448:SUB #qsize,SP456:GOTO *0)SP(return
. . .600:stack starts here
ניהול מחסנית – דוגמא
12
המקור תוכנית היא שורה בx := 0דוגמא – נניח ש-
הקצאה סטטית -נניח שx( אמור להמצא בהיסט ( offset12static [12] := 0( רביעיה – קוד ביניים) נקבל:100אם האזור הסטטי מתחיל בכתובת ,
MOV #0, 112קוד מכונה –
הקצאה מקומית במחסנית -נניח שx משתנה מקומי ה'חי' ברשומה המוצבעת ע"י
SP
t1 := 12 + SP
* t1 := 0– בפקודות מכונה MOV #0, 12 ) SP (
קוד ביניים )רביעות(
MOV #0, 112קוד מכונה –
חישוב כתובות עבור משתנים
13
basic blocks and flow graphs
– סדרת פקודות עם כניסה יחידה )לפקודה הראשונה( בלוק בסיסיויציאה יחידה )מהפקודה האחרונה(.
היציאה היא אולי הפניה או הפניה מותנה של הבקרה
z ו- y- ב משתמש וx את מגדיר x := y + zמשפט מהסוג בנקודה נתונה אם נעשה שימוש בערך שלו לאחר חימשתנה הוא
הנקודה האמורה.
t1:= a * a
t2:= a * b
t3:= 2 * t2
t4:= t1 + t3
t5:= b * b
t6:= t4 + t5
14
פירוק תוכנית לבלוקים בסיסיים
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 rules we use are the following: The first statement is a leader Any statement that is the target of a conditional of
unconditional goto is a leader Any statement that immediately follows a goto or
conditional goto statement is a leader For each leader, its basic block consists of a leader and
all statements up to but not including the next leader or the end of the program
15
פירוק תוכנית לבלוקים בסיסיים– דוגמא פשוטה 'מהחיים'
int fib(int n){ if (n<=1) return 1; return fib(n-1) + fib(n-2);}
“gcc –S fib.c” creates fib.s:
.fib: mflr 0 ; r0 := lr stw 29,-12(1) ; *r1-12 := r29 stw 31,-4(1) ; *r1-4 := r31 stw 0,8(1) ; *r1+8 := r0 (lr) stwu 1,-72(1) ; r1 := r1-72, *r1=r1 mr 31,1 ; r31 := r1 stw 3,96(31) ; *r31+96 := r3 (‘n’) lwz 0,96(31) ; r0 := *r31+96 (‘n’) cmpwi 0,0,1 ; cr0 := r0 ~ 1 bgt 0,L..3 ; if cr0.gt goto L..3
li 3,1 ; r3 := 1 b L..2 ; goto L..2 (return 1)L..3:
L..3: lwz 9,96(31) ; r9 := *r31+96 (‘n’) addi 0,9,-1 ; r0 := r9 - 1 mr 3,0 ; r3 := r0 bl .fib ; call fib(n-1) mr 29,3 ; r29 := r3 lwz 9,96(31) ; r9 := *r31+96 (‘n’) addi 0,9,-2 ; r0 := r9 - 2 mr 3,0 ; r3 := r0 bl .fib ; call fib(n-2) mr 9,3 ; r9 := r3 add 0,29,9 ; r0 := r29 + r9 mr 3,0 ; r3 := r0 b L..2 ; goto L..2L..2: lwz 1,0(1) ; r1 := *r1 lwz 0,8(1) ; r0 := *r1+8 mtlr 0 ; lr := r0 lwz 29,-12(1) ; r29 := *r1-12 lwz 31,-4(1) ; r31 := *r1-4 blr ; goto lr (return)
16
טרנספורמציות בתוך בלוקים בסיסיים
ביטויים משותפים
ביטול "קוד מת"השמה למשתנה שלא חי לאחר מכן
החלפת שם של משתנה זמני אפשר תמיד להשתמש בשמות חדשים ולקבל בלוק בצורה
נורמליתצריך לשמור על הטיפוס
החלפת סדר בין פקודות
פישוטים אלגבריים
a:= b + cb:= a – dc:= b + cd:= a – d
:= y ^ 2x:= x * 1x:= x + 0x
d := b
x := y * y
17
(control )flow graph
– הבלוקים הבסיסייםצמתי הגרף
– קשת מקשרת שני בלוקים קשתות הגרףאם קיימת הפנית בקרה מהראשון לשני
)או פשוט המשך ישיר של זרימת הבקרה(
– קבוצה קשירה היטב בעלת לולאהכניסה יחידה
– טבעת ללא תת-טבעותלולאה פנימית
הערה – עושים שימוש בשמות הבלוקים הבסיסיים ולא במספרים סידוריים של
הרביעיות המתאימות )על מנת לאפשר הזזה של הבלוקים בסיסיים(
B1
prod := 0
i := 1
B2
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i
t4 := b [ t3 ]
t5 := t2 * t4
t6 := prod + t5
prod := t6
t7 := i + 1
i := t7
if i <= 20 goto B2
18
next-use information
עבור כל שורה בבלוק נתון, נרצה לשמור )עבור כל משתנה אליו מתייחסת שורה זו(:
האם המשתנה חי.מתי השימוש הבא במשתנה
, j בשורה x ואם משתמשים ב- x מבצעים השמה ל- iאם בשורה , אזי x ללא השמה נוספת ל- j ל- iואם יש אפשרות לזרימת בקרה מ-
i שחושב ב- xשימוש ב- ישנו jב-
קריאות לפרוצדורות...( החישוב נעשה ברמת הבלוק הבודד )זהירות:
החישוב נעשה על-ידי סריקה של הבלוק מסופו לעבר תחילתו
כל המשתנים שאינם מקומיים בבלוק, חיים בסוף הנחות שמרניות:הבלוק )כלומר, נעשה בהם שימוש בהמשך(.
.סריקות מתקדמות יותר מאפשרות דיוק רב יותר
19
next use information
– ברמת הבלוק הבודד – מהסוף להתחלה. next-useחישוב ה- . נניח שבטיפול מהסוף להתחלה הגענו symbol tableנעזר ב- למשפט
i: x := y op z
z ו- y, x על symbol table את האינפורמציה שנאספה ב- iנצמיד ל-
symbol tableנקבע ב-
x"לא חי"; "אין שימוש בהמשך" –
symbol tableנקבע ב-
y, z -חיים"; "השימוש הבא – ב" – i"
– חשוב3 ו- 2הערה – הסדר בין 1.
xyלמשל, במקרה בו 1.
20
תהליך פשוט ליצירת קוד
הגישה – ניצור קוד כך שעבור כל פקודה נזכור היכן נמצאים האופרנדים
הנחותהתאמה טובה בין שפת הרביעיות לשפת המכונהנשמור תוצאות ברגיסטרים אלא אם
יש צורך ברגיסטר למטרה אחרתצריך לסגור את הבלוק
a := b + cדוגמאות
...next-useלפי מידע ה- איך יודעים אם "אפשר לוותר"?
ADD Rj, Ri אםb -ו c ברגיסטרים ואפשר לוותר על b ולהשאיר במקומו aאת
ADD C, Ri אםRi מכיל את b ואפשר לוותר עליו, אבל cבזכרון
MOV C, Rj
ADD Rj, Ri
שובcאם נצטרך את
21
מעקב אחרי משתנים ורגיסטרים
(descriptorsעבור רגיסטרים – רושמים מה יש בכל רגיסטר )בתחילת כל בלוק כל הרגיסטרים ריקיםבמהלך ייצור הקוד, כל רגיסטר יכיל משתנה אחד או יותר
מתאר הכתובות עוקב היכן נמצא כל משתנה )רגיסטר, מחסנית, , משתנה ימצא store או loadמקום בזיכרון...(. כשיש פקודת
במספר מקומות
22
code generation algorithm
Input: A sequence of three-address statements constituting a basic block.
For each three-address statement x := y op z we perform the following:
1. Invoke the function getreg to determine the location L where the result of the computation y op z should be stored. L will usually be a register, but it could also be a memory location.
2. Consult the address descriptor for y to determine y', )one of( the current location)s( of y. Prefer the register for y' if the value of y is currently both in memory and a register. If the value of y is not already in L, generate the instruction MOV y', L to place a copy of y in L.
3. Generate the instruction OP z', L, where z' is the current location of z. Again, prefer a register to a memory location if z is in both. Update the address descriptor of x to indicate that x is in location L. If L is a register, update its descriptor to indicate that it contains the value of x.
4. If the current values of y and/or z have no next uses, are not live on exit from the block, and are in registers, alter the register descriptor to indicate that, after execution of x:= y op z, those registers no longer will contain y and/or z, respectively.
23
יצירת קוד – הערות
הטיפול בפעולות אונריות – דומה
x := yמצריך עדכון המתארים
עם סיום העבודה ברמת הבלוק הבסיסי שומרים את ערכי המשתנים (live-dead)אלא אם יש לנו אינפורמציה של
24
(getregהקצאת רגיסטר )הפונקציה
x := y op zנתון –
xהמטרה – הקצאת רגיסטר ל-
שאינו משמש לאכסון משתנים נוספים, ואם ל- L ברגיסטר yאם 1.y אין שימוש בהמשך, החזר את L עדכן את מתארי הכתובת ,
והרגיסטר. זכרו כי הוראות מסוגx := y גורמות לרגיסטר להחזיק את
הערך של כמה משתנים בו-זמנית.
והחזר אותו.L נכשל, מצא רגיסטר פנוי 1אם 2.
. L יש שימוש בהמשך, מצא רגיסטר תפוס x נכשל, ואם ל- 2אם 3. בזיכרון )אם אינו נמצא שם(, עדכן את Lשמור את הערך של
.Lמתארי הכתובת והרגיסטר והחזר את -המשתנה )או משתנים( שהיה לפני-כן בL שמור עכשיו בזכרון
בלבד. איך בוחרים איזה רגיסטר לפנות לטובתx?
בהמשך הבלוק, או אם אין בנמצא xאם לא נעשה שימוש ב- 4..xרגיסטר מתאים, החזר את כתובתו בזיכרון של
25
הקצאת רגיסטרים
statementscode generatedregister descriptoraddress descriptor
registers empty
t := a – bMOV a, R0
SUB b, R0
R0 contains tt in R0
u := a – cMOV a, R1
SUB c, R1
R0 contains t
R1 contains u
t in R0
u in R1
v := t + uADD R1, R0R0 contains v
R1 contains u
u in R1
v in R0
d := v + uADD R1, R0
MOV R0, d
R0 contains dd in R0
d in R0 and memory
d := )a – b( + )a – c( + )a – c(
26
יצירת קוד לטיפול במערכים
statementi in register Rii in memory Mii in stack
codecostcodecostcodecost
a:= b [ i ]MOV b)Ri(, R2MOV Mi, R
MOV b)R(, R4
MOV Si)A(, R
MOV b)R(, R4
a [ i ] := bMOV b, a)Ri(3MOV Mi, R
MOV b, a)R(5
MOV Si)A(, R
MOV b, a)R(5
offset -יחסית לתחילת ה activation record
activation recordתחילת ה-
הוא משתנה סטטיaמניחים ש-
27
טיפול במצביעים
statementp in register Rpp in memory Mpp in stack
codecostcodecostcodecost
a:= * pMOV *Rp, a2MOV Mp, R
MOV *R, R3
MOV Sp)A(, R
MOV *R, R4
* p := aMOV a, *Rp2MOV Mp, R
MOV a, *R4
MOV a, R
MOV R, *Sp)A(5
28
register allocation and assignment
allocation?איזו אינפורמציה תאוכסן ברגיסטר –
assignment?למה בדיוק יוקצה כל רגיסטר –
חשיבות הנושאהקטנת הקודייעול התוכנית
גישות עיקריותהקצאה קבועה של רגיסטרים לצרכים מיוחדים
כתובת חזרהערך מוחזראכסון מצביע לראש המחסנית
הקצאה גלובלית
29
global register allocation
המטרה – הימנעות משמירת ערכים המצויים ברגיסטרים בסוף כל בלוק על ידי מעקב גלובלי
.גלובלי" עשוי עדיין להיות מקומי – בתוך אותה פרוצדורה, למשל"
דגש מיוחד על הלולאות הפנימיות
(C בשפת registerהמלצות המתכנת )המלה השמורה
usage countגישה כמותית – מקצים מקום ברגיסטר למשתנה בו נעשה שימוש נרחבחשיבות מיוחדת לאינדקס הרץ של לולאותמטפלים בלולאות הפנימיות תחילהלאחר מכן, הקצאת רגיסטרים ללולאות החיצוניות
השיטה דומה. אם אין מספיק רגיסטרים הן ללולאה חיצונית לפני הכניסה ללולאה הפנימיתspillוהן לפנימית, מבצעים
30
הקצאת רגיסטרים באמצעות צביעה של גרפים
(מכונה אבסטרקטיתנניח שמספר הרגיסטרים לא חסום ונייצר קוד )1.
תהיה קטנהspillנקצה רגיסטרים כך שעלות ה- 2.
register interference graphבניה וניתוח של ה-
הצמתים – הרגיסטרים הסימבוליים1.
במקום בו השני חיקשת בגרף מקשרת שני צמתים אם אחד מהם 2.מוגדר
נצבע את הגרף במספר קטן של צבעים – כמספר הרגיסטרים 3.הפיזיים
הבעיה היאNP Completeמשתמשים באלגוריתמים היוריסטיים
לעניבות הפנימיותspill codeהערה – צריך להשתדל להימנע מלהכניס
31
DAGייצוג החישוב של בלוק בסיסי בעזרת
עלים – משתנים )שונים( או קבועים )שונים(
צמתים פנימיים מסומנים על ידי האופרטורים המתאימים
לצמתים נצמיד שמות משתנים על פי התקדמות החישוב
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i
t4 := b [ t3 ]
t5 := t2 * t4
t6 := prod + t5
prod := t6
t7 := i + 1
i := t7
if i <= 20 goto )1(
)1(
1i04ba
20t7, i+t1, t3 *
)1(<=t4[ ]t2[ ]
t5*prod0
t6, prod+
32
DAGבנית ה-
מטפלים בכל משפט בבלוק
x := y + z
z ו- yמוצאים איפה נמצא הערך הנוכחי של
ומחברים אותו לשני הבנים )אם לא +בונים צומת חדש המסומן xקיים כזה(; מסמנים אותו ב-
( כבר מסומן, יש לבטל את הסימון הקודם x0 )לאxאם
אין יוצרים צומת חדש עבור משפטי השמה פשוטים
x := y
33
DAGsייצוג בלוקים בסיסיים כ-
עלים – משתנים )שונים( או קבועים )שונים(
צמתים פנימיים מסומנים על ידי האופרטורים המתאימים
לצמתים נצמיד שמות משתנים על פי התקדמות החישוב
t1 := 4 * i
t2 := a [ t1 ]
t3 := 4 * i
t4 := b [ t3 ]
t5 := t2 * t4
t6 := prod + t5
prod := t6
t7 := i + 1
i := t7
if i <= 20 goto )1(
)1(
1i04ba
20t7, i+t1, t3 *
)1(<=t4[ ]t2[ ]
t5*prod0
t6, prod+
t1
prod := prod + t5
i := i + 1
34
כייצוג של בלוקים בסיסייםDAGsשימושים של
זיהוי אוטומטי של ביטויים משותפים
זיהוי המשתנים בהם נעשה שימוש בבלוק
זיהוי הפקודות בהן חושבו ערכים בעלי שימוש בסוף הבלוק
ייצור קוד יעיל )בפרט – אין צורך בהשמות(
זיהוי המשתנים החיים
סדר חישוב קביל – באמצעות מיון טופולוגי
35
side effects
aliasingהקושי –
הפתרון – השמה לאיבר של מערך מבטלת את האפשרות להשתמש בצמתים המכילים התייחסות אליו
הערה – בעיה דומה נגרמת על ידי מצביעים
הערה – בעיה דומה נגרמת על ידי פרוצדורות
הוא מכשול מרכזי לאופטימיזציה של תוכניותaliasingנושא ה-
x := a [ i ]
a [ j ] := y
z := a [ i ]
x := a [ i ]
a [ j ] := y
z := x