320 likes | 392 Views
Lecture #3, April 11, 2007. Boolean expressions Positional encoding Short circuit evaluation Conditional move Array expressions. Assignments. Reading Read chapter 7 sections 7.6 7.7 and 7.8 Possible Quiz Wednesday on the reading.
E N D
Lecture #3, April 11, 2007 • Boolean expressions • Positional encoding • Short circuit evaluation • Conditional move • Array expressions
Assignments • Reading • Read chapter 7 sections 7.6 7.7 and 7.8 • Possible Quiz Wednesday on the reading. • Programming assignment #2 is now available on the class website under the assignments link.
Boolean Expressions • Boolean expressions can be treated just like arithmetic expressions. • Need to represent True and False, some possibilities • False = 0000n True = 0001n • False = 0000n True = 1111n for a n-bit representations • Some machines have special instructions for manipulating booleans in addition to boolean operations • Special hardware called the condition code • One to several bits (pattern encodes the conditions LT, GT etc) • Set by arithmetic and boolean operations • Special instructions that interrogate the condition code • Some compilers use an implicit representation using the location of the program counter to encode True or False.
By example • We will illustrate this by example • Add new instructions to our IR • Translate code from CS321 expressions into the new IR instructions • Illustrate the approaches by defining a different translation for each approach. • Approaches • Numerical encoding • Register based boolean operators • cmp_LT rx,ry => ra • Conditional Branches and condition codes • Comp rx,ry => cc1 • Positional Encoding • Short Circuit evaluation
New IR instruction type Reg = int; type Label = int; type CC = int; datatype IR = LoadI of (string * Reg) | LoadAO of (Reg * Reg * Reg) | Arith of (BINOP * Reg * Reg * Reg) | Comp of (Reg * Reg * CC)
Register based boolean encodings fun expr dict node = case node of | Binop(m,x,y) => let val t1 = expr dict x val t2 = expr dict y val result = NextRegister() in emit (Arith(m,t1,t2,result)); result end | Relop(m,x,y) => let val rx = expr dict x val ry = expr dict y val r2 = NextRegister() in emit (Cmp(m,rx,ry,r2)) Notice the similarity between arithmetic and relational operators, Depends upon machine operations that leave boolean values in registers
New Concepts • Condition codes • type CC = int; • fun showCC n = "cc"^Int.toString n; • Labels • type Label = int; • fun showLab n = "L"^Int.toString n;
Managing Condition Codes val firstCC = 1; val CCCount = ref firstCC; fun resetCC () = CCCount := firstCC; fun NextCC() = let val n = !CCCount in (CCCount := n+1; n) end;
Managing Labels We often generate multiple labels all at once. val firstLabel = 1; val LabelCount = ref firstLabel; fun resetLabel () = LabelCount := firstLabel; fun NextLabel m = let val n = !LabelCount fun f n 0 = [] | f n m = n :: (f (n+1) (m-1)) in (LabelCount := n+m; f n m) end; - NextLabel 4; val it = [10,11,12,13] : int list
Emitting labeled code • fun emitAt l x = emit(Lab(l,x)); emit (Comp(rx,ry,cc)); emit (Cbr(LT,cc,l1,l2); emitAt l1 (LoadI("true",r2)); emit (JumpI l3); emitAt l2 (LoadI("false",r2)); emit (JumpI l3); emitAt l3 Nop
Additions to the IR datatype IR = LoadI of (string * Reg) | LoadAO of (Reg * Reg * Reg) | Arith of (Op * Reg * Reg * Reg) | Cmp of (Op * Reg * Reg * Reg) | Comp of (Reg * Reg * CC) | Neg of (Reg * Reg) | Cbr of ( RELOP * CC * Label * Label) | JumpI of Label | Lab of (Label * IR) | Nop;
Condition codes • Operations set special hardware called condition codes. • Some operations depend upon condition codes. loadI @x => r1 loadAO rA,r1 => r2 loadI @y => r3 loadAO rA,r3 => r4 comp r2,r4 => cc1 cbr_Ltcc1 -> L1,L2 L1: loadI true => r5 jumpI -> L3 L2: loadI false => r5 jumpI -> L3 L3: nop Conditional branch. L1 and L2 are labels
loadI @x => r1 loadAO rA,r1 => r2 loadI @y => r3 loadAO rA,r3 => r4 comp r2,r4 => cc1 cbr_Ltcc1 -> L1,L2 L1: loadI true => r5 jumpI -> L3 L2: loadI false => r5 jumpI -> L3 L3: nop | Relop(m,x,y) => let val rx = expr dict x val ry = expr dict y val r2 = NextRegister() val cc = NextCC() val [l1,l2,l3] = NextLabel 3 in emit (Comp(rx,ry,cc)); emit (Cbr(m,cc,l1,l2)); emitAt l1 (LoadI("true",r2)); emit (JumpI l3); emitAt l2 (LoadI("false",r2)); emit (JumpI l3); emitAt l3 Nop r2 end
Choosing between a style | Relop(m,x,y) => let val rx = expr dict x val ry = expr dict y val r2 = NextRegister() in (case !style of Numerical => emit (Cmp(m,rx,ry,r2)) | CondCode => let val cc = NextCC() val [l1,l2,l3] = NextLabel 3 in emit (Comp(rx,ry,cc)); emit (Cbr(m,cc,l1,l2)); emitAt l1 (LoadI("true",r2)); emit (JumpI l3); emitAt l2 (LoadI("false",r2)); emit (JumpI l3); emitAt l3 Nop end); r2 end
loadI @a => r1 loadAO rA,r1 => r2 // r2=a loadI @b => r3 loadAO rA,r3 => r4 // r4=b comp r2,r4 => cc1 // a<b cbr_Lt cc1 -> L1,L2 L1: loadI true => r5 jumpI -> L3 L2: loadI false => r5 jumpI -> L3 L3: nop loadI @c => r6 loadAO rA,r6 => r7 // r7=c loadI @d => r8 loadAO rA,r8 => r9 // r9=d comp r7,r9 => cc2 // c<d cbr_Lt cc2 -> L4,L5 L4: loadI true => r10 jumpI -> L6 L5: loadI false => r10 jumpI -> L6 L6: nop loadI @e => r11 loadAO rA,r11 => r12 // r11=e loadI @f => r13 loadAO rA,r13 => r14 // r14=f comp r12,r14 => cc3 // e<f cbr_Lt cc3 -> L7,L8 L7: loadI true => r15 jumpI -> L9 L8: loadI false => r15 jumpI -> L9 L9: nop And r10,r15 => r16 Or r5,r16 => r17 a<b or c<d and e<f
Positional Rather than load a boolean into a register use the position in the code to indicate the result of the test. loadI @x => r1 loadAO rA,r1 => r2 loadI @y => r3 loadAO rA,r3 => r4 comp r2,r4 => cc1 cbr_Lt cc1 -> L1,L2 L1: ____cc1 is true here__ jumpI -> L3 L2: ___cc1 is false here__ jumpI -> L3 L3: nop
Use functions as parameters • Suppose we were translating • if x<y then z := 0 else z := z+1 loadI @x => r1 loadAO rA,r1 => r2 loadI @y => r3 loadAO rA,r3 => r4 comp r2,r4 => cc1 cbr_Lt cc1 -> L1,L2 L1: ____ z := 0here__ jumpI -> L3 L2: ___ z := z+1 here__ jumpI -> L3 L3: nop
Break translation into 2 parts | Relop(m,x,y) => let val rx = expr dict x val ry = expr dict y val r2 = NextRegister() in (case !style of Positional => let val [trueL,falseL] = NextLabel 2 in compare m rx ry trueL falseL; fillRelSlot trueL (fn () => emit (LoadI("true",r2))) falseL (fn () => emit (LoadI("false",r2))) end ); emits comparison code
compare & fillRelSlots fun compare oper rx ry trueL falseL = let val cc = NextCC() in emit (Comp(rx,ry,cc)); emit (Cbr(oper,cc,trueL,falseL)) end; fun fillRelSlot trueL truef falseL falsef = let val [resultL] = NextLabel 1 in tag trueL truef; emit (JumpI resultL); tag falseL falsef; emit (JumpI resultL); emitAt resultL Nop end;
Short Circuit Evaluation loadI @a => r2 loadAO rA,r2 => r3 loadI @b => r4 loadAO rA,r4 => r5 L1: comp r3,r5 => cc1 cbr_Lt cc1 -> L2,L5 L5: loadI @c => r6 loadAO rA,r6 => r7 loadI @d => r8 loadAO rA,r8 => r9 comp r7,r9 => cc2 cbr_Lt cc2 -> L6,L3 L6: loadI @e => r10 loadAO rA,r10 => r11 loadI @f => r12 loadAO rA,r12 => r13 comp r11,r13 => cc3 cbr_Lt cc3 -> L2,L3 L2: loadI true => r1 jumpI -> L4 L3: loadI false => r1 jumpI -> L4 L4: nop a<b or c<d and e<f
Coding it up fun short dict (Relop(m,x,y)) start trueL falseL = let val _ = emitAt start Nop val rx = expr dict x val ry = expr dict y val cc = NextCC() in emit (Comp(rx,ry,cc)); emit (Cbr(m,cc,trueL,falseL)) end | short dict (Binop(AND,r1,r2)) start trueL falseL = let val [start2] = NextLabel 1 in short dict r1 start start2 falseL; short dict r2 start2 trueL falseL end | short dict (Binop(OR,r1,r2)) start trueL falseL = let val [start2] = NextLabel 1 in short dict r1 start trueL start2; short dict r2 start2 trueL falseL end
Driving short fun shortCircuit dict exp = let val [start,l1,l2,l3] = NextLabel 4 val r2 = NextRegister() in short dict exp start l1 l2; emitAt l1 (LoadI("true",r2)); emit (JumpI l3); emitAt l2 (LoadI("false",r2)); emit (JumpI l3); emitAt l3 Nop; r2 end;
Incorporation into expr fun expr dict node = case node of Binop(AND,_,_) => shortCircuit dict node | Binop(OR,_,_) => shortCircuit dict node | Binop(m,x,y) => let val t1 = expr dict x val t2 = expr dict y val result = NextRegister() in emit (Arith(m,t1,t2,result)); result end
Conditional Move • Some machines have conditional move instructions • Mov_GT cc,r1,r2, => r3 • Mostly we use these to avoid branching or jumps • if x<y then a <- c+d else a <- e+f • comp rx,ry => cc1 • add rc,rd => r1 • add re,rf => r2 • mov_LT cc1,r1,r2 => ra • Note the speculative evaluation (we need only one of the branches)
Array Access • Arrays addresses have two components • Base • Offset • For 1-dimensional, zero-based arrays, with elements of 1 byte things are straight forward. • X[3] X[0] = 2341 x[3] = 2341 + 3 23 14 2 2 X = 2341
1 dimensional address calculation • X[y] • Address of x[y] = address of x + y loadI @y => r1 loadA0 ra,r1 => r1 loadI @x => r2 add r1,r2 => r3 load r3 => r4
1 dimensional Non zero indexing • Array [ low .. High ] • Address x[y] = address x + y - low
1 dimensional non unit size • Array [ 0 .. n ] of Float // where float = size bytes • Address x[y] = address x + y * size
Combined • Array [ low .. High ] of Float // where float = size bytes • Address x[y] = address x + (y – low) * size • Optimization • Address x[y] = address x + (y * size) – (low * size) • Address x[y] = address x – (low * size) + (y * size) Performed with a shift if size is a power of 2 Perhaps this is known at compile-time?
(1,2) (1,2) (1,3) (2,2) (2,2) (1,3) (2,3) (2,3) 2 dimensional arrays • Array[1..2; 2..3] • Row major • Column major (1,2) (1,3) (2,2) (2,3)
Lets work out the formula • Array[ l1..h1; l2..h2 ]
Assignment #2 CS322 Prog Lang & Compilers Prog Assignment #2 Assigned Monday April 10, 2006. Due Wednesday, April 12, 2006 • This assignment is to extend the expr program discussed in class • (and available for download) so that it can translate array accesses, where the array is a variable: i.e. x[34+j] • fun expr dict (ArrayElm(Var(loc,nm),index,SOME typ)) = . . . • See the assignment directory for for details.