diff --git a/docs/lectures/03-adder.html b/docs/lectures/03-adder.html index fa7061e..ef7e1c2 100644 --- a/docs/lectures/03-adder.html +++ b/docs/lectures/03-adder.html @@ -676,7 +676,7 @@

Example: Let-bindings and Stacks

, y = add1(x) -- [x |-> 1] , z = add1(y) -- [y |-> 2, x |-> 1] in - add1(z) -- [z |- 3, y |-> 2, x |-> 1] + add1(z) -- [z |-> 3, y |-> 2, x |-> 1]

QUIZ

At what position on the stack do we store variable c ?

                          -- []
diff --git a/docs/lectures/04-boa.html b/docs/lectures/04-boa.html
index f0e767e..4d2c162 100644
--- a/docs/lectures/04-boa.html
+++ b/docs/lectures/04-boa.html
@@ -267,17 +267,17 @@ 

Example: If1

  • Since 10 is not 0 we evaluate the “then” case to get 22
  • Example: If2

    -
    if sub(1):
    +
     
      -
    • Since sub(1) is 0 we evaluate the “else” case to get -1
    • +
    • Since sub1(1) is 0 we evaluate the “else” case to get -1

    QUIZ: If3

    if-else is also an expression so we can nest them:

    What should the following evaluate to?

    -
    let x = if sub(1):
    +
    let x = if sub1(1):
               22
             else:
               sub1(0)
    @@ -325,7 +325,7 @@ 

    QUIZ

    Which of the following is a valid x86 encoding of

    QUIZ: Compiling if-else
    QUIZ: Compiling if-else
    @@ -502,7 +502,7 @@

    Transforms: CodeGen

    , IJe (BranchFalse i) -- if-zero then jump to 'False'-block ] ++ compile env eTrue ++ -- code for `True`-block - [ IJmp lExit ] -- jump to exit (don't execute `False`-block!) + [ IJmp (BranchExit i) ] -- jump to exit (don't execute `False`-block!) ++ ILabel (BranchFalse i) -- start of `False`-block : compile env eFalse ++ -- code for `False`-block @@ -763,74 +763,77 @@

    QUIZ

    Use the above function to test our ANF conversion.

    immArg :: Env -> ImmExpr -> Arg
     immArg env (Number n _) = Const n
    -immArg env (Id x _)     = RegOffset EBP (lookupEnv env x)
    -
    -compileImm :: Env -> ImmExpr Tag -> [Instruction]
    -compileImm env v  = [IMov (Reg EAX) (immArg env v) ]
    +immArg env (Id x _)     = RegOffset EBP i
    +  where
    +    i                   = fromMaybe err (lookupEnv env x)
    +    err                 = error (printf "Error: Variable '%s' is unbound" x)
     
    -compile :: Env -> AnfExpr Tag -> [Instruction]
    -compile env v@(Number {})  = compileImm env v
    -compile env v@(Id _ _)     = compileImm env v 
    -compile env (Prim1 op e)   = compile env e
    -                          ++ [ (prim1Asm op (Reg EAX) (Const 1)]
    -compile env (Prim2 op v1 v2) = [ compileImm env v1 
    -                               , prim2asm o (Reg EAX) (immArg env v2) 
    -                               ]
    -
    -prim2Asm Add2 = IAdd
    -prim2Asm Sub2 = ISub
    -prim2Asm Mul2 = IMul
    -
    -prim1Asm Add1 = IAdd
    -prim1Asm Sub1 = ISub
    +compileImm :: Env -> ImmExpr Tag -> [Instruction]
    +compileImm env v  = [IMov (Reg EAX) (immArg env v) ]
    +
    +compile :: Env -> AnfExpr Tag -> [Instruction]
    +compile env v@(Number {})  = compileImm env v
    +compile env v@(Id _ _)     = compileImm env v 
    +compile env (Prim1 op e)   = compile env e
    +                          ++ [ (prim1Asm op (Reg EAX) (Const 1)]
    +compile env (Prim2 op v1 v2) = [ compileImm env v1 
    +                               , prim2Asm o (Reg EAX) (immArg env v2) 
    +                               ]
    +
    +prim2Asm Add2 = IAdd
    +prim2Asm Sub2 = ISub
    +prim2Asm Mul2 = IMul
     
    -
    -anf :: Int -> Expr a -> (Int, AnfExpr a)
    -anf i p@(Number {}) = (i, p)
    -anf i v@(Id {})     = (i, v)
    -anf i (Prim1 o e)   = (i', Prim1 o e') 
    -  where 
    -    (i', e')        = anf i e
    -
    -anf i (Prim2 o e1 e2) = (i2, mkLet (bs1 ++ bs2) (Prim2 o v1 v2))
    -  where
    -     (i1, (bs1, v1))  = imm i  e1
    -     (i2, (bs2, v2))  = imm i1 e2
    -
    -anf i (Let x  e1 e2)  = (i2, Let x e1' e2')
    -  where 
    -     (i1, e1')        = anf i e1
    -     (i2, e2')        = anf i1 e2
    -
    -anf i (If  e1 e2 e3)  = (i3, If e1' e2' e3')
    -  where 
    -     (i1, e1')        = anf i e1
    -     (i2, e2')        = anf i1 e2
    -     (i3, e3')        = anf i2 e3
    -
    -imm :: Int -> Expr a -> (Int, ([(Id , AnfExpr a)] , ImmExpr a))
    -imm i e@(Number {}) = (i, ([], e))
    -imm i e@(Id {})     = (i, ([], e))
    -imm i e@(Prim1 {})  = immExp i e
    -imm i e@(If {})     = immExp i e
    -imm i e@(Let {})    = immExp i e
    -
    -imm i (Prim2 o e1 e2) = (i2+1, ((v, Prim2 o v1 v2) : bs2 ++ bs1, Id v))
    -  where
    -    (i1, (bs1, v1)) = imm i e1
    -    (i2, (bs2, v2)) = imm i1 e2
    -    v               = mkTmpVar i2
    -
    -mkTmpVar i = "tmp" ++ show i
    -
    -mkLet :: [(Id , AnfExpr a)] -> AnfExpr a -> AnfExpr a
    -mkLet []              e = e
    -mkLet ((x1, e1) : bs) e = Let x1 e1 (mkLet bs e)
    -
    -immExp i e  = (i' + 1, ([(v, e')], v))
    -  where
    -    (i',e') = anf e
    -    v       = mkTmpVar i'
    +prim1Asm Add1 = IAdd +prim1Asm Sub1 = ISub + + +anf :: Int -> Expr a -> (Int, AnfExpr a) +anf i p@(Number {}) = (i, p) +anf i v@(Id {}) = (i, v) +anf i (Prim1 o e) = (i', Prim1 o e') + where + (i', e') = anf i e + +anf i (Prim2 o e1 e2) = (i2, mkLet (bs1 ++ bs2) (Prim2 o v1 v2)) + where + (i1, (bs1, v1)) = imm i e1 + (i2, (bs2, v2)) = imm i1 e2 + +anf i (Let x e1 e2) = (i2, Let x e1' e2') + where + (i1, e1') = anf i e1 + (i2, e2') = anf i1 e2 + +anf i (If e1 e2 e3) = (i3, If e1' e2' e3') + where + (i1, e1') = anf i e1 + (i2, e2') = anf i1 e2 + (i3, e3') = anf i2 e3 + +imm :: Int -> Expr a -> (Int, ([(Id , AnfExpr a)] , ImmExpr a)) +imm i e@(Number {}) = (i, ([], e)) +imm i e@(Id {}) = (i, ([], e)) +imm i e@(Prim1 {}) = immExp i e +imm i e@(If {}) = immExp i e +imm i e@(Let {}) = immExp i e + +imm i (Prim2 o e1 e2) = (i2+1, ((v, Prim2 o v1 v2) : bs2 ++ bs1, Id v)) + where + (i1, (bs1, v1)) = imm i e1 + (i2, (bs2, v2)) = imm i1 e2 + v = mkTmpVar i2 + +mkTmpVar i = "tmp" ++ show i + +mkLet :: [(Id , AnfExpr a)] -> AnfExpr a -> AnfExpr a +mkLet [] e = e +mkLet ((x1, e1) : bs) e = Let x1 e1 (mkLet bs e) + +immExp i e = (i' + 1, ([(v, e')], v)) + where + (i',e') = anf e + v = mkTmpVar i'

    Types & Strategy

    Writing the type aliases:

    type BareE   = Expr ()
    @@ -993,8 +996,8 @@ 

    ANF: Making Arguments Immediate
  • anf the relevant expressions,
  • bind them to a fresh variable.
  • -
    imm e@(If _ _ _) = immExp e
    -imm e@(If _ _ _) = immExp e
    +
    imm e@(If  _ _ _) = immExp e
    +imm e@(Let _ _ _) = immExp e
     
     immExp :: AnfE -> ([(Id, AnfE)], ImmE)
     immExp e = ([(t, e')], t)
    diff --git a/docs/lectures/05-cobra.html b/docs/lectures/05-cobra.html
    index 537a9ce..962292f 100644
    --- a/docs/lectures/05-cobra.html
    +++ b/docs/lectures/05-cobra.html
    @@ -285,11 +285,11 @@ 

    Option 1: Use Two Words

    12 -[0x000000000][0x0000000c] +[0x000000000][0x00000018] 42 -[0x000000000][0x0000002a] +[0x000000000][0x00000054] false @@ -459,11 +459,11 @@

    Types

    Number 12 -HexConst 0x0000000c +HexConst 0x00000018 Number 42 -HexConst 0x0000002a +HexConst 0x00000054 @@ -625,7 +625,7 @@

    Shifted Representation and Mu n1 * n2 -2*n1 * 2*n2 = 4*(n1 + n2) +2*n1 * 2*n2 = 4*(n1 * n2) @@ -777,7 +777,8 @@

    4. Dynamic Checking

    or

    In fact, lets try to see what happens with our code on the above:

    - +

    Oops.

    Checking Tags at Run-Time

    Later, we will look into adding a static type system that will reject such meaningless programs at compile time. For now, lets see how to extend the compilation to abort execution when the wrong types of operands are found when the code is executing.

    diff --git a/lectures/03-adder.md b/lectures/03-adder.md index adb3ad1..ab88104 100644 --- a/lectures/03-adder.md +++ b/lectures/03-adder.md @@ -629,7 +629,7 @@ let x = 1 -- [] , y = add1(x) -- [x |-> 1] , z = add1(y) -- [y |-> 2, x |-> 1] in - add1(z) -- [z |- 3, y |-> 2, x |-> 1] + add1(z) -- [z |-> 3, y |-> 2, x |-> 1] ``` ### QUIZ diff --git a/lectures/04-boa.md b/lectures/04-boa.md index b858674..386389b 100644 --- a/lectures/04-boa.md +++ b/lectures/04-boa.md @@ -55,7 +55,7 @@ else: ### Example: `If2` ```haskell -if sub(1): +if sub1(1): 22 else: sub1(0) @@ -64,7 +64,7 @@ else: -* Since `sub(1)` _is_ `0` we evaluate the "else" case to get `-1` +* Since `sub1(1)` _is_ `0` we evaluate the "else" case to get `-1` ### QUIZ: `If3` @@ -73,7 +73,7 @@ else: What should the following evaluate to? ```haskell -let x = if sub(1): +let x = if sub1(1): 22 else: sub1(0) @@ -136,7 +136,7 @@ Which of the following is a valid x86 encoding of ```python if 10: 22 -else +else: 33 ``` @@ -354,7 +354,7 @@ compile env (If eCond eTrue eFalse i) , IJe (BranchFalse i) -- if-zero then jump to 'False'-block ] ++ compile env eTrue ++ -- code for `True`-block - [ IJmp lExit ] -- jump to exit (don't execute `False`-block!) + [ IJmp (BranchExit i) ] -- jump to exit (don't execute `False`-block!) ++ ILabel (BranchFalse i) -- start of `False`-block : compile env eFalse ++ -- code for `False`-block @@ -773,7 +773,10 @@ Use the above function to **test** our ANF conversion. ```haskell immArg :: Env -> ImmExpr -> Arg immArg env (Number n _) = Const n -immArg env (Id x _) = RegOffset EBP (lookupEnv env x) +immArg env (Id x _) = RegOffset EBP i + where + i = fromMaybe err (lookupEnv env x) + err = error (printf "Error: Variable '%s' is unbound" x) compileImm :: Env -> ImmExpr Tag -> [Instruction] compileImm env v = [IMov (Reg EAX) (immArg env v) ] @@ -784,7 +787,7 @@ compile env v@(Id _ _) = compileImm env v compile env (Prim1 op e) = compile env e ++ [ (prim1Asm op (Reg EAX) (Const 1)] compile env (Prim2 op v1 v2) = [ compileImm env v1 - , prim2asm o (Reg EAX) (immArg env v2) + , prim2Asm o (Reg EAX) (immArg env v2) ] prim2Asm Add2 = IAdd @@ -1091,8 +1094,8 @@ That is, simply * bind them to a fresh variable. ```haskell -imm e@(If _ _ _) = immExp e -imm e@(If _ _ _) = immExp e +imm e@(If _ _ _) = immExp e +imm e@(Let _ _ _) = immExp e immExp :: AnfE -> ([(Id, AnfE)], ImmE) immExp e = ([(t, e')], t) diff --git a/lectures/05-cobra.md b/lectures/05-cobra.md index 44582b0..8090c95 100644 --- a/lectures/05-cobra.md +++ b/lectures/05-cobra.md @@ -57,8 +57,8 @@ First word is `0` means `bool`, is `1` means `number`, `2` means pointer etc. |---------:|------------------------------:| | `3`| `[0x000000000][0x00000003]`| | `5`| `[0x000000000][0x00000005]`| -| `12`| `[0x000000000][0x0000000c]`| -| `42`| `[0x000000000][0x0000002a]`| +| `12`| `[0x000000000][0x00000018]`| +| `42`| `[0x000000000][0x00000054]`| | `false`| `[0x000000001][0x00000000]`| | `true`| `[0x000000001][0x00000001]`| @@ -157,8 +157,8 @@ So, our examples become: | `Boolean True`| `HexConst 0x80000001`| | `Number 3`| `HexConst 0x00000006`| | `Number 5`| `HexConst 0x0000000a`| -| `Number 12`| `HexConst 0x0000000c`| -| `Number 42`| `HexConst 0x0000002a`| +| `Number 12`| `HexConst 0x00000018`| +| `Number 42`| `HexConst 0x00000054`| ### Transforms @@ -353,7 +353,7 @@ Thus, our _source values_ have the following _representations: | `3`| `6` | | `5`| `10` | | `3 * 5 = 15`| `6 * 10 = 60` | -| `n1 * n2`| `2*n1 * 2*n2 = 4*(n1 + n2)` | +| `n1 * n2`| `2*n1 * 2*n2 = 4*(n1 * n2)` | Thus, multiplication ends up accumulating the factor of 2. * Result is _two times_ the desired one. @@ -567,6 +567,7 @@ In fact, lets try to see what happens with our code on the above: ```haskell ghci> exec "2 + true" +Unknown value: 0x80000005 ``` Oops.