Handling Assignment in Compilers: Strategies and Optimizations - Prof. Marvin V. Zelkowitz, Study notes of Computer Science

The handling of assignment in compilers, including strategies for evaluating and converting types, optimizing address calculations, and using condition codes. It also covers the use of conditional moves and predication for simplifying code.

Typology: Study notes

Pre 2010

Uploaded on 02/13/2009

koofers-user-4c7
koofers-user-4c7 🇺🇸

10 documents

1 / 15

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1
CMSC430 Spring 2007 1
Handling Assignment
(just another operator)
lhs rhs
Strategy
Evaluate
rhs
to a value
(an rvalue)
Evaluate
lhs
to a location
(an lvalue)
>
lvalue
is a register move rhs
>
lvalue
is an address store rhs
If
rvalue
&
lvalue
have different types
>Evaluate
rvalue
to its “
natural
”type
>Convert that value to the type of *
lvalue
Unambiguous scalars go into registers
Ambiguous scalars or aggregates go into memory
Let hardware
sort out the
addresses !
CMSC430 Spring 2007 2
Handling Assignment
What if the compiler cannot determine the type of the rhs?
This is a property of the language & the specific program
If type-safety is desired, compiler must insert run-time checks
Add a
tag
field to the data items to hold type information
Code for assignment becomes more complex
evaluate rhs
if type(lhs) rhs.tag
then
convert rhs to type(lhs)
or
signal a run-time error
lhs rhs
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff

Partial preview of the text

Download Handling Assignment in Compilers: Strategies and Optimizations - Prof. Marvin V. Zelkowitz and more Study notes Computer Science in PDF only on Docsity!

CMSC430 Spring 2007 (^1)

Handling Assignment (just another operator)

lhs ← rhs

Strategy

  • Evaluaterhs to a value (an rvalue)
  • Evaluatelhs to a location (an lvalue)

> lvalue is a register ⇒ move rhs

> lvalue is an address ⇒ store rhs

  • Ifrvalue &lvalue have different types

> Evaluatervalue to its “natural” type

> Convert that value to the type of *lvalue

Unambiguous scalars go into registers Ambiguous scalars or aggregates go into memory

Let hardware sort out the addresses!

CMSC430 Spring 2007 (^2)

Handling Assignment

What if the compiler cannot determine the type of the rhs?

  • This is a property of the language & the specific program
  • If type-safety is desired, compiler must insert run-time checks
  • Add atag field to the data items to hold type information

Code for assignment becomes more complex

evaluate rhs if type(lhs) ≠ rhs.tag then

convert rhs to type(lhs)or

signal a run-time error lhs ← rhs

CMSC430 Spring 2007 (^3)

Handling Assignment

Compile-time type-checking

  • Goal is to eliminate both the check & the tag
  • Determine, at compile time, the type of each subexpression
  • Use compile-time types to determine whether check is needed

Optimization strategy

  • If compiler knows the type, move the check to compile-time
  • If tags are not needed for garbage collection, eliminate the tags
  • If check is unavoidable, try to overlap it with other computation

Can design the language so all checks are static

CMSC430 Spring 2007 (^4)

Handling Assignment (with reference counting)

The problem with reference counting

  • Must adjust the count on each pointer assignment
  • Overhead is significant, relative to assignment Code for assignment becomes

This adds1 +, 1 -, 2 loads, & 2 stores

With extra functional units & large caches, this may become free …

evaluate rhs lhs→count ← lhs →count - 1 lhs ← addr(rhs) rhs →count ← rhs →count + 1

Plus a check for zero at the end

CMSC430 Spring 2007 (^7)

Computing an Array Address

A[ i ]

  • @A + ( i – low ) x sizeof(A[1])
  • In general: base(A) + ( i – low ) x sizeof(A[1])

What about A[i 1 ][i 2 ]?

Row-major order, two dimensions

@A + (( i 1 – low 1 ) x (high 2 – low 2 + 1) + i 2 – low 2 ) x sizeof(A[1])

Column-major order, two dimensions

@A + (( i 2 – low 2 ) x (high 1 – low 1 + 1) + i 1 – low 1 ) x sizeof(A[1])

Indirection vectors, two dimensions

*(A[i 1 ])[i 2 ] — where A[i 1 ] is, itself, a 1-d array reference

This stuff looks expensive! Lots of implicit +, -, x ops

int A[1:10] ⇒ low is 1 Make low 0 for faster access (save a – )

Almost always a power of 2, known at compile-time ⇒ use a shift for speed

CMSC430 Spring 2007 (^8)

Optimizing Address Calculation for A[ i ][ j ]

In row-major order @A + (i–low 1 )(high 2 –low 2 +1) x w + (j – low 2 ) x sizeof(A[1][1]) Which can be factored into @A + i x (high 2 –low 2 +1) x sizeof(A[1][1]) + j x sizeof(A[1][1])

  • (low 1 x (high 2 –low 2 +1) x sizeof(A[1][1] + low 2 x sizeof(A[1][1]) If low (^) i, high (^) i, and w are known, the last term is a constant Define @A 0 as @A – (low 1 x (high 2 –low 2 +1) x sizeof(A[1][1]) + low 2 x sizeof(A[1][1]) And len 2 as (high 2 -low 2 +1)

Then, the address expression becomes @A 0 + (i x len 2 + j ) x sizeof(A[1][1]) Compile-time constants

CMSC430 Spring 2007 (^9)

Array References

What about arrays as actual parameters?

Whole arrays, as call-by-reference parameters

  • Need dimension information ⇒ build adope vector
  • Store the values in the calling sequence
  • Pass the address of the dope vector in the parameter slot
  • Generate complete address polynomial at each reference

Some improvement is possible

  • Save len (^) i and low (^) i rather than low (^) i and high (^) i
  • Pre-compute the fixed terms in prolog sequence (a win if used)

What about call-by-value?

  • Most c-b-v languages pass arrays by reference
  • This is a language design issue

@A low 1 high 1 low 2 high 2

CMSC430 Spring 2007 (^10)

Array References

What about A[12] as an actual parameter?

If corresponding parameter is a scalar, it’s easy

  • Pass the address or value, as needed
  • Must know about both formal & actual parameter
  • Language definition must force this interpretation

What is corresponding parameter is an array?

  • Must know about both formal & actual parameter
  • Meaning must be well-defined and understood
  • Cross-procedural checking of conformability

⇒ Again, we’re treading on language design issues

CMSC430 Spring 2007 (^13)

Example: Array Address Calculations in a Loop

DO J = 1, N A[I,J] = A[I,J] + B[I,J] END DO

  • Sophisticated: Move comon calculations out of loop

R1 = I x floatsize c = len 1 x floatsize! Compile-time constant R2 = @A 0 + R R3 = @B 0 + R DO J = 1, N a = J x c R4 = R2 + a R5 = R3 + a MEM(R4) = MEM(R4) + MEM(R5) END DO

CMSC430 Spring 2007 (^14)

Example: Array Address Calculations in a Loop

DO J = 1, N A[I,J] = A[I,J] + B[I,J] END DO

  • Very sophisticated: Convert multiply to add (Strength Reduction)

R1 = I x floatsize c = len 1 x floatsize! Compile-time constant R2 = @A 0 + R1 ; R3 = @B 0 + R DO J = 1, N R2 = R2 + c R3 = R3 + c MEM(R2) = MEM(R2) + MEM(R3) END DO

CMSC430 Spring 2007 (^15)

Boolean & Relational Values

How should the compiler represent them?

  • Answer depends on the target machine

Two classic approaches

  • Numerical representation
  • Positional (implicit) representation Correct choice depends on both context and ISA

CMSC430 Spring 2007 (^16)

Boolean & Relational Values

Numerical representation

  • Assign values to TRUE and FALSE
  • Use hardware AND, OR, and NOT operations
  • Use comparison to get a boolean from a relational expression

Examples

x < y becomes cmp_LT^ r^ x ,r^ y ⇒r^1

if (x < y)

then stmt 1 becomes

else stmt 2

cmp_LT r (^) x ,r (^) y ⇒r (^1) cbr r1→_stmt 1 ,_stmt 2

CMSC430 Spring 2007 (^19)

Boolean & Relational Values

The last example actually encodes result in the PC If result is used to control an operation, this may be enough

Condition code version does not directly produce (x < y) Boolean version does Still, there is no significant difference in the code produced

VARIATIONS ON THE I LOC B RANCH STRUCTURE

Straight Condition Codes Boolean Compares

comp r (^) x ,r (^) y⇒cc 1 cmp_LT r (^) x ,r (^) y⇒r (^1) cbr _LT cc 1 →L 1 ,L 2 cbr r 1 →L 1 ,L (^2) L 1 : add r (^) c ,r (^) d⇒r (^) a L 1 : add r (^) c ,r (^) d⇒r (^) a br →LOUT br →LOUT L 2 : add r (^) e ,r (^) f ⇒r (^) a L 2 : add r (^) e ,r (^) f ⇒r (^) a br (^) →LOUT br (^) →LOUT LOUT : nop LOUT : nop

if (x < y) then a ← c + d else a ← e + f

Example

CMSC430 Spring 2007 (^20)

Boolean & Relational Values

Conditional move & predication both simplify this code

Both versions avoid the branches Both are shorter than CCs or Boolean-valued compare

Are they better?

OTHER A RCHITECTURAL V ARIATIONS

Conditional Move Predicated Execution

comp r (^) x,r (^) y⇒cc 1 cmp LT r (^) x,r (^) y⇒r (^1) add r (^) c ,r (^) d⇒r 1 (r 1 )? add r (^) c ,r (^) d⇒r (^) a add r (^) e ,r (^) f ⇒r 2 (¬r 1 )? add r (^) e ,r (^) f ⇒r (^) a i2i< cc 1 ,r 1 ,r 2 ⇒r (^) a

if (x < y) then a ← c + d else a ← e + f

Example

CMSC430 Spring 2007 (^21)

Boolean & Relational Values

Consider the assignment x ← a < b ∧ c < d

Here, the boolean compare produces much better code

VARIATIONS ON THE I LOC B RANCH STRUCTURE

Straight Condition Codes Boolean Compare

comp r (^) a ,r (^) b⇒cc 1 cmp_LT r (^) a ,r (^) b⇒r (^1) cbr _LT cc 1 →L 1 ,L 2 cmp_LT r (^) c ,r (^) d⇒r (^2) L 1 : (^) comp r (^) c ,r (^) d⇒cc 2 and r 1 ,r 2 ⇒r (^) x cbr _LT cc 2 →L 3 ,L (^2) L 2 : loadI 0 ⇒ rx br →L^ OUT L 3 : (^) loadI 1 ⇒ rx br →L^ OUT L (^) OUT : (^) nop

CMSC430 Spring 2007 (^22)

Boolean & Relational Values

Conditional move & predication help here, too

Conditional move is worse than Boolean compares Predication is identical to Boolean compares

Context & hardware determine the appropriate choice

OTHER A RCHITECTURAL VARIATIONS

Conditional Move Predicated Execution

comp r (^) a ,r (^) b ⇒cc 1 cmp_LT r (^) a ,r (^) b⇒r (^1) i2i_< cc 1 ,r (^) T ,r (^) F ⇒r 1 cmp_LT r (^) c ,r (^) d⇒r (^2) comp r (^) c ,r (^) d ⇒cc 2 and r 1 ,r 2 ⇒r (^) x i2i_< cc 2 ,r (^) T ,r (^) F ⇒r (^2) and r 1 ,r 2 ⇒r (^) x

CMSC430 Spring 2007 (^25)

Control Flow

Case Statements 1 Evaluate the controlling expression 2 Branch to the selected case 3 Execute the code for that case 4 Branch to the statement after the case Parts 1, 3, & 4 are well understood, part 2 is the key

Strategies

• Linear search (nested if-then-else constructs)

• Build a table of case expressions & binary search it

• Directly compute an address (requires dense case set)

Surprisingly many compilers do this for all cases!

CMSC430 Spring 2007 (^26)

Activation record structure

  • R9 Link register
  • R8 Activation Record ptr
  • R7 Temporary Act Rec ptr
  • R6 End of stack
  • R2-R5 Four arithmetic Regs
  • R0-R1 Mult-Div registers
  • Registers 2-5 used for + and –
  • Multiply code pattern: L R0, arg M R0, arg LI Ri, (R1)0 where Ri = allocated reg.

Assume a procedure at level 3 calls a function with 2 arguments at static level 3: X(A,B)

Dynamic Link

End of Stack

Return Address

Display[2]

Variable 2

Display[1]

Variable 1

Variables …

Argument 1

Argument 2

R8 Æ

R6 Æ

CMSC430 Spring 2007 (^27)

Activation record structure

  • Function call code: X(A,B) Code: LI R0, A Get first arg address ST R0, (R6)0 Save address in stack LI R0, B Get second arg address ST R0, (R6)1 Save address in stack JSRI R9,X Goto Function R9=retn addr ST R0,X Save function value in Stack

Dynamic Link

End of Stack

Return Address

Display[2]

Variable 2

Display[1]

Variable 1

Variables …

Æ A

Æ B

R8 Æ

R6 Æ

CMSC430 Spring 2007 (^28)

Activation record structure

  • Function X(integer: I, J) Prolog Code: ST R8, (R6)2 New Dyn Link ST R9, (R6)3 New Retn Addr L R0, (R6)0 Get arg 1 ST R0, (R6)I+2 Store in I in new AR L R0, (R6)1 Get arg 2 ST R0, (R6)J+2 Store in J in new AR AI R6, 2 New AR start L R0, (R8)3 Calling Disp[1] ST R0, (R6)3 New Disp[1] L R0, (R8)4 Calling Disp[2] ST R0, (R6)4 New Disp[2] ST R6, (R6)5 New Disp[3] LI R8, (R6)0 Set new Act Rec Ptr AI R6,sizeof(X) Set new end stack ST R6, (R8)2 Save end stack

Dynamic Link

End of Stack

Return Address

Display[2]

Variable 2

Display[1]

Variable 1

Variables …

Æ A

Æ B

R8 Æ

R6 Æ

R8 Æ X Dynamic Link

X End of Stack

X Return Address

X Display[2]

X Display[1]

X Display[3]

R