נושאים קוד מותנה setting testing control flow if-then-else varieties of loops switch...
TRANSCRIPT
נושאיםנושאיםקוד מותנה
SettingTesting
Control FlowIf-then-elseVarieties of LoopsSwitch Statements
שפת מכונה – מבוא
שפת מכונה – מבוא
של של 33מבוסס על פרק מבוסס על פרק Computer Systems – a programmers perspective / Bryant & O’hallrronComputer Systems – a programmers perspective / Bryant & O’hallrron
– 2 –
קוד מותנהקוד מותנהרגיסטרים ייעודיים בני סיבית אחת:רגיסטרים ייעודיים בני סיבית אחת:
CF Carry Flag SF Sign Flag
ZF Zero Flag OF Overflow Flag
מופעלים בעת חישוב פעולות אריתמטיות. למשל:מופעלים בעת חישוב פעולות אריתמטיות. למשל:add Src,Dest
C analog: t = a + bCF = 1 אם יש גלישה בחישוב UnsignedZF = 1 אם t == 0SF = 1 אם t < 0OF = 1 אם גלישה בחישוב signed
:למשל, ראינו שבחיבור יש גלישה אם
(a>0 && b>0 && t<0) || (a<0 && b<0 && t>=0)
– 3 –
קוד מותנה )השמה מפורשת(קוד מותנה )השמה מפורשת(
ניתן להשים ערך לסיביות אלה גם באופן מפורש, על ידי ניתן להשים ערך לסיביות אלה גם באופן מפורש, על ידי ..comparecompareפקודת פקודת
compare Src2,Src1
compare b,a –כמו חישובכמו חישוב a-b .בלי יעד.בלי יעד
test Src2,Src1
test b,a -כמו חישובכמו חישוב a&b בלי יעדבלי יעדZF כאשר a&b == 0SF כאשר a&b < 0
– 4 –
(jumping)קפיצות (jumping)קפיצות
jX Condition Descriptionjmp 1 Unconditional
je ZF Equal / Zero
jne ~ZF Not Equal / Not Zero
js SF Negative
jns ~SF Nonnegative
jg ~(SF^OF)&~ZF Greater )Signed(
jge ~(SF^OF) Greater or Equal )Signed(
jl (SF^OF) Less )Signed(
jle (SF^OF)|ZF Less or Equal )Signed(
ja ~CF&~ZF Above )unsigned(
jb CF Below )unsigned(
jX InstructionsjX Instructionsקפיצה מותנית
– 5 –
Conditional Branch דוגמה: Conditional Branch דוגמה:
int max(int x, int y){ if (x > y) return x; else return y;}
max:
move 8(R1),R3move 12(R1),R4compare R4,R3jle L9move R3,R4
L9:
Body
x
x-y signed
. R4תוצאת הפונקציה נשמרת ב
המקרה שלreturn y
– 6 –
המשך דוגמההמשך דוגמה
move 8(R1),R3 # R3 = xmove 12(R1),R4 # R4 = ycompare R4,R3 # x : yjle L9 # if <= goto L9move R3,R4 # R4 = x
L9: # Done:
int goto_max(int x, int y){ int tmp = x; int return_val = y; int ok = (x <= y); if (ok) goto done; return_val = x;done: return return_val;}
C מאפשר פקודת goto!לא מומלץ - .תוב של התוכנית הקודמת בדומה יותר לקוד היעד Sכ Tנראה ש
– 7 –
C Codeint fact_do (int x){ int result = 1; do { result *= x; x = x-1; } while (x > 1); return result;}
Goto Versionint fact_goto(int x){ int result = 1;loop: result *= x; x = x-1; if (x > 1) goto loop; return result;}
דוגמה עם לולאהדוגמה עם לולאה
– 8 –
Goto Versionint fact_goto (int x){ int result = 1;loop: result *= x; x = x-1; if (x > 1) goto loop; return result;}
אחרי הידור...אחרי הידור...
RegistersRegistersR3 x
R4 result
fact_goto:move $1,R4 # R4 = 1move 8(R1),R3 # R3 = x
L11:multiply R3,R4 # result *= xdecrement R3 # x--compare $1,R3 # Compare x : 1jg L11 # if > goto loop
– 9 –
C Codedo Body while (Test);
Goto Versionloop: Body if (Test) goto loop
Do-Whileהתבנית הכללית לתרגום Do-Whileהתבנית הכללית לתרגום
הגוף יכול להיות כל statement שלC בדר"כ פעולה מורכבת (compound):
הtestהוא ביטוי המחזיר מספר שלם = 0 false 0 true
{ Statement1; Statement2; … Statementn;}
– 10 –
C Codeint fact_while(int x){ int result = 1; while (x > 1) { result *= x; x = x-1; }; return result;}
First Goto Versionint fact_while_goto(int x){ int result = 1;loop: if (!(x > 1)) goto done; result *= x; x = x-1; goto loop;done: return result;}
whileדוגמה ללולאת whileדוגמה ללולאת
האם שקול לתוכנית הקודמת שהייתה מבוססת עלdo-while? .לא! בגלל האיטרציה הראשונה
– 11 –
C Codeint fact_while(int x){ int result = 1; while (x > 1) { result *= x; x = x-1; }; return result;}
Second Goto Versionint fact_while_goto2(int x){ int result = 1; if (!(x > 1)) goto done; loop: result *= x; x = x-1; if (x > 1) goto loop;done: return result;}
אותה לולאה פנימית .בדיקה נוספת בכניסה ללולאה כלומר, כמוdo-while.מלבד הבדיקה הראשונה
whileהתרגום האמיתי של whileהתרגום האמיתי של
– 12 –
C Codewhile (Test) Body
Do-While Version
if (!Test) goto done; do Body while(Test);done:
whileהתבנית הכללית לתרגום whileהתבנית הכללית לתרגום
Goto Version if (!Test) goto done;loop: Body if (Test) goto loop;done:
– 13 –
forלולאות forלולאות
אלגוריתםאלגוריתם :סיבוכיותO(log p)
/* Compute x raised to nonnegative power p */int pwr(int x, unsigned p) {int result; for (result = 1; p != 0; p = p>>1) { if (p & 0x1) result *= x; x = x*x; } return result;}
Example
310 = 32 * 38 = 32 * ))32( 2( 2
– 14 –
pwrדוגמה לחישוב של pwrדוגמה לחישוב של
/* Compute x raised to nonnegative power p */int pwr(int x, unsigned p) {int result; for (result = 1; p != 0; p = p>>1) { if (p & 0x1) result *= x; x = x*x; } return result;}
result x p1 3 101 9 59 81 29 6561 1
531441 43046721 0
– 15 –
Forדוגמה ללולאת Forדוגמה ללולאת
for (Init; Test; Update )
Body
int result; for (result = 1; p != 0; p = p>>1) { if (p & 0x1) result *= x; x = x*x; }
צורה כללית
Initresult = 1
Testp != 0
Updatep = p >> 1
Body { if (p & 0x1) result *= x; x = x*x; }
– 16 –
“For” “While”“For” “While”
for (Init; Test; Update )
Body
Init;while (Test ) { Body Update ;}
Goto Version
Init; if (!Test) goto done;loop: Body Update ; if (Test) goto loop;done:
While VersionFor Version
Do-While Version
Init; if (!Test) goto done; do { Body Update ; } while (Test)done:
– 17 –
”for“הידור של לולאת ”for“הידור של לולאת
Initresult = 1
Testp != 0
Updatep = p >> 1
Body { if (p & 0x1) result *= x; x = x*x; }
Goto Version
Init; if (!Test) goto done;loop: Body Update ; if (Test) goto loop;done:
result = 1; if (p == 0) goto done;loop: if (p & 0x1) result *= x; x = x*x; p = p >> 1; if (p != 0) goto loop;done:
– 18 –
Switch פקודות Switch פקודות
מחדל. באג בדוגמה: אין ברירת
typedef enum {ADD, MULT, MINUS, DIV, MOD, BAD} op_type;
char unparse_symbol(op_type op){ switch (op) { case ADD : return '+'; case MULT: return '*'; case MINUS: return '-'; case DIV: return '/'; case MOD: return '%'; case BAD: return '?'; }}
– 19 –
Jump Tableהמבנה של ה Jump Tableהמבנה של ה
Code Block0
Targ0:
Code Block1
Targ1:
Code Block2
Targ2:
Code Blockn–1
Targn-1:
•••
Targ0
Targ1
Targ2
Targn-1
•••
jtab:
target = JTab[op];goto *target;
switch(op) { case val_0: Block 0 case val_1: Block 1 • • • case val_n-1: Block n–1}
Switch Form
Approx. Translation
Jump Table Jump Targets
– 20 –
Switchדוגמה: Switchדוגמה: Branching PossibilitiesBranching Possibilities
unparse_symbol:move 8(R1),R4 # R4 = opcompare $5,R4 # Compare op : 5
ja .L49 # If > goto donejmp *.L57(,R4,4) # goto Table[op]
Enumerated ValuesADD 0MULT 1MINUS 2DIV 3MOD 4BAD 5
typedef enum {ADD, MULT, MINUS, DIV, MOD, BAD} op_type;
char unparse_symbol(op_type op){ switch (op) { • • • // returns ASCII of op }}
תזכורת:•compare מבצע R4 – 5• cf = 1 אם יש גלישה על פי unsigned .
& cf~ הוא ja התנאי של •~zf
– 21 –
הסברהסבר
LabelsLabels תוויות מהצורה.Lxx מתורגם לכתובת על ידי ה assembler
מבנה הטבלהמבנה הטבלה בתים.4כל יעד דורש ( הבסיסBase address ב )L57
קפיצות: קפיצות: jmp .L49
היעד מסומן על ידי תוית.L49
jmp *.L57(,R4,4) כתובת תחילת הטבלה .L57R4 מחזיק את op 4. משם - קפיצות של היעד נמצא ב .L57 + op*4:בפעולה אחת נמצא את הכתובת של הקוד לביצוע ! כלומר
– 22 –
Jump TableJump Table
.section .rodata .align 4.L57:.long .L51 #Op = 0.long .L52 #Op = 1.long .L53 #Op = 2.long .L54 #Op = 3.long .L55 #Op = 4.long .L56 #Op = 5
Table Contents.L51:
move $43,R4 # ’+’jmp .L49
.L52:move $42,R4 # ’*’jmp .L49
.L53:move $45,R4 # ’-’jmp .L49
.L54:move $47,R4 # ’/’jmp .L49
.L55:move $37,R4 # ’%’jmp .L49
.L56:move $63,R4 # ’?’# Fall Through to .L49
Targets & Completion
43 is the ASCII value
of ‘+’
..R4R4הפרוצדורה תחזיר את הערך ב הפרוצדורה תחזיר את הערך ב
– 23 –
חידהחידה
חידהחידה אםop? לא נמצא בטבלה ואין ברירת מחדל – איזה ערך מוחזר
תשובהתשובההערך שלop .עצמו למה ? כי בהתחלת הפרוצדורה ביצענו השמה שלop ל R4 .
– 24 –
switch לעומת if switch לעומת if
Jump TableJump Table היתרון של היתרון של יכול לבצעk-way branch - ב O)1(.
Jump TableJump Table החיסרון של החיסרון של .גודל הטבלה כגודל הטווח בין הערך המינימאלי למקסימאלי כלומר, לא בהכרח פרופורציוני למספר הכניסות בswitch.
switch- טוב כשהמקרים הם קבועים
יחסית קטניםמ - conditionalsנמנע
ifשורה של תנאי - טוב אם יש מספר קטן
- איטי מדי אם יש מספר גדול של תנאים.
בוחר לבד לפי המבנה: GCCאופטימיזציה של
– 25 –
'דליל' Switchדוגמה ל 'דליל' Switchדוגמה ל
לא מעשי ליישם כjump table
1000 ידרוש טבלה של כניסות.
התרגום לif-then-else בדיקות.9ידרוש
/* Return x/111 if x is multiple && <= 999. -1 otherwise */int div111(int x){ switch(x) { case 0: return 0; case 111: return 1; case 222: return 2; case 333: return 3; case 444: return 4; case 555: return 5; case 666: return 6; case 777: return 7; case 888: return 8; case 999: return 9; default: return -1; }}
– 26 –
'דליל' Switchקוד של 'דליל' Switchקוד של המהדר הפך לרשימתif משווה לערכים שונים של x.וקופץ למקומות שונים בהתאם לתוצאה
move 8(R1),R4 # get xcompare $444,R4 # x:444je L8jg L16compare $111,R4 # x:111je L5jg L17testl R4,R4 # x:0je L4jmp L14
. . .
. . .L5:
move $1,R4jmp L19
L6:move $2,R4jmp L19
L7:move $3,R4jmp L19
L8:move $4,R4jmp L19. . .
jump table ללא אופטימיזציות: בעקבות אופטימיזציה של המהדרifקוד
? מדוע דווקא הסדר הזה
– 27 –
-1
-1 -1-1
דלילSwitchמבנה של קוד דלילSwitchמבנה של קוד
.מארגן את המקרים לפי עץ בינארי.זמן חיפוש לוגריתמי
.כיצד נוצר החיסכון ? המיון נעשה בשלב ההידור במקום בזמן ריצה
444
111 777
0 222 555 888
333 666 9990
1
4
7
5 8
9
2
3 6
<
=
>=
< >=
< >=
< >=
= = =
= =
– 28 –
1סיכום 1סיכום C ControlC Control
if-then-else do-while while switch
Assembler ControlAssembler Control jump Conditional jump
כדי לממש פקודות כדי לממש פקודות assemblyassembly המהדר חייב לשלב פקודות המהדר חייב לשלב פקודות •מורכבות יותר. מורכבות יותר.
– 29 –
2סיכום 2סיכום
טכניקות סטנדרטיות:טכניקות סטנדרטיות: כל הלולאות מתורגמות לdo-while פעולותswitch מתורגמות ל jump tables
CISCCISC תנאים ב תנאים ב בדר"כ מחשביCISC מכילים רגיסטרים מיוחדים לתנאים
RISCRISCתנאים ב תנאים ב משתמשים ברגיסטרים כלליים פקודות מיוחדות להשוואה
למשל, על מחשביAlpha:
comparee $16,1,$1Sets register $1 to 1 when Register $16 <= 1