diff options
-rw-r--r-- | doc/docs/backend/rts.md | 25 | ||||
-rw-r--r-- | driver.s | 51 | ||||
-rw-r--r-- | example.snug | 9 | ||||
-rw-r--r-- | snug-clean/src/MIPS/MIPS32.dcl | 1 | ||||
-rw-r--r-- | snug-clean/src/MIPS/MIPS32.icl | 1 | ||||
-rw-r--r-- | snug-clean/src/Snug/Compile.icl | 40 | ||||
-rw-r--r-- | snug-clean/src/Snug/Compile/ABI.dcl | 1 | ||||
-rw-r--r-- | snug-clean/src/Snug/Compile/ABI.icl | 6 |
8 files changed, 111 insertions, 23 deletions
diff --git a/doc/docs/backend/rts.md b/doc/docs/backend/rts.md index d401f3a..36de2ce 100644 --- a/doc/docs/backend/rts.md +++ b/doc/docs/backend/rts.md @@ -53,19 +53,18 @@ The arguments of some built-in constructors can be unboxed: ### Hnf descriptors Descriptors of hnf nodes are located in the data section. They contain -information about the arity of the node. It also contains the number of -arguments to be curried in, which is 0 for all data constructors but non-zero -for the [descriptors of closures](#closure-descriptors). (This means that, in -principle, data constructor descriptors only need a halfword.) +information about the arity of the node. ```mipsasm .align 1 __main_cTuple: .byte 2 # pointer arity .byte 0 # basic value arity - .byte 0 # number of arguments to be curried in ``` +NB: [descriptors of closures](#closure-descriptors) also contain the number of +arguments to be curried in (minus 1). + ### Thunk descriptors Thunk nodes point to the code that can evaluate them. Above this code a descriptor is used storing information about arity and strictness: @@ -78,13 +77,13 @@ __main_nappend: # ... ``` -!!! warning "Implementation may change" - Strictness will probably be removed in the future, as evaluating arguments - will be moved out of the driver into generated code (see - [evaluation](#evaluation)). +!!! warning "Implementation will change" + Strictness will be removed in the future, as evaluating arguments will be + moved out of the driver into generated code (see [evaluation](#evaluation)). - This also makes the implementation of `ap` simpler, as it does not need to - check strictness of the function it evaluates any more. + This makes the implementation of `ap` simpler, as it does not need to check + strictness of the function it evaluates any more. Currently `ap` assumes all + arguments are strict. ### Closure descriptors For each thunk with a non-zero number of arguments there is also a closure @@ -97,12 +96,12 @@ this: # entry for closure with 0 arguments: .byte 0 # pointer arity .byte 0 # basic value arity - .byte 2 # number of arguments that are still to be curried in + .byte 1 # number of arguments that are still to be curried in minus 1 .byte 0 # reserved # entry for closure with 1 argument: .byte 1 # pointer arity .byte 0 # basic value arity - .byte 1 # number of arguments that are still to be curried in + .byte 0 # number of arguments that are still to be curried in minus 1 .byte 0 # reserved # pointer to corresponding code entry: __main_uappend: @@ -216,7 +216,7 @@ cycle_error: #.byte 1 # arity # TODO: we cannot use the above because SPIM does not accept .byte in text section .align 2 - .word 0x0001 # strictness, arity + .word 0x01000000 # arity, strictness _nroot: la $a0,cycle_error li $v0,4 # print_string @@ -232,10 +232,57 @@ indir_error: #.byte 1 # arity # TODO: we cannot use the above because SPIM does not accept .byte in text section .align 2 - .word 0x0101 # strictness, arity + .word 0x01010000 # arity, strictness _nindir: # indirections are handled in eval la $a0,indir_error li $v0,4 # print_string syscall break 0 + + #.align 1 + #.byte 0x3 # strictness (incorrect; see documentation) + #.byte 2 # arity + # TODO: we cannot use the above because SPIM does not accept .byte in text section + .align 2 + .word 0x02030000 # arity, strictness +_nap: + # 4($s3) is closure to apply + # 8($s3) is argument + # NB: assumption: the closure has no basic value arguments + lw $t0,4($s3) # t0 -> closure + lw $t1,($t0) # t1 -> closure descriptor + lbu $t2,($t1) # t2 = closure arity + # TODO: check heap space + # Create new closure: copy old closure + addi $t3,$t1,4 # t3 -> next closure descriptor + addi $t5,$gp,0 # t5 -> new closure + sw $t3,($gp) + addi $t6,$t0,4 # closure argument iterator +_nap_copy: + beq $t2,$0,_nap_copy_done + addi $gp,$gp,4 # branch delay slot + lw $t4,($t6) # t4 -> closure argument + addi $t6,$t6,4 + sw $t4,($gp) + j _nap_copy + addi $t2,$t2,-1 # branch delay slot +_nap_copy_done: + # Add new argument + lw $t0,8($s3) # t0 -> new argument + sw $t0,($gp) + addi $gp,$gp,4 + # Check if the closure is saturated + lbu $t2,2($t1) # t2 = number of remaining closure arguments - 1 + bne $t2,$0,_nap_no_eval + # Saturated; create thunk + lw $t3,($t3) # function address + sw $t3,($t5) +_nap_no_eval: + # Create indirection + la $t0,_nindir + sw $t0,($s3) + sw $t5,4($s3) + addi $s3,$t5,0 + j eval + nop diff --git a/example.snug b/example.snug index 33d4dab..035934d 100644 --- a/example.snug +++ b/example.snug @@ -73,7 +73,10 @@ (Cons _ xs -> length_acc (+ n 1) xs))) #) -(fun testb ((x : Int) (y : Char)) : Tuple Int Char : + +(fun unary ((x : Int)) : Tuple Int Int : + binary x) +(fun binary ((x : Int) (y : Int)) : Tuple Int Int : Tuple x y) -(fun test () : Tuple Int Char : - testb 37 'a') +(fun test () : Tuple Int Int : + unary 37 42) diff --git a/snug-clean/src/MIPS/MIPS32.dcl b/snug-clean/src/MIPS/MIPS32.dcl index 6e5ff44..83f15cb 100644 --- a/snug-clean/src/MIPS/MIPS32.dcl +++ b/snug-clean/src/MIPS/MIPS32.dcl @@ -10,6 +10,7 @@ from StdOverloaded import class toString | Instr !Instruction | RawByte !Int | RawWord !Int + | RawWordLabel !Label | RawAscii !String instance toString Line diff --git a/snug-clean/src/MIPS/MIPS32.icl b/snug-clean/src/MIPS/MIPS32.icl index ca5cbee..655219d 100644 --- a/snug-clean/src/MIPS/MIPS32.icl +++ b/snug-clean/src/MIPS/MIPS32.icl @@ -13,6 +13,7 @@ where toString (Instr i) = "\t" +++ toString i toString (RawByte i) = "\t.byte\t" +++ toString i toString (RawWord i) = "\t.word\t" +++ toString i + toString (RawWordLabel l) = "\t.word\t" +++ l toString (RawAscii s) = concat3 "\t.ascii\t\"" s "\"" // TODO: escaping instance toString Instruction diff --git a/snug-clean/src/Snug/Compile.icl b/snug-clean/src/Snug/Compile.icl index 8c23134..dcbc5ad 100644 --- a/snug-clean/src/Snug/Compile.icl +++ b/snug-clean/src/Snug/Compile.icl @@ -89,8 +89,27 @@ compileDefinition ns globals (DataDef _ _ constructors) = flatten <$> mapM (compileConstructor ns globals) constructors compileDefinition ns globals (FunDef id args ret expr) = (++) + (if (isEmpty args) [] ( + [ StartSection "data" + , Align 2 + ] ++ flatten + [[ Label (closure_label i) + // TODO: Ideally we would use the following here: + //, RawByte i // pointer arity + //, RawByte 0 // basic value arity + //, RawByte (length args-i-1) // number of arguments that still have to be curried in minus 1 + //, RawByte 0 // reserved + // But since SPIM does not allow .byte in the text section, we use: + , RawWord + (i bitor // pointer arity + ((length args-i-1) << 16)) // number of arguments that still have to be curried in minus 1 + ] \\ i <- [0..length args-1] + ] ++ + [ RawWordLabel n_label + ])) <$> + (++) [ StartSection "text" - , Global label + , Global n_label // TODO: Ideally we would use the following here: //, Align 1 //, RawByte (sum [2^i \\ i <- [0..] & _ <- args]) // all strict for now, TODO change @@ -101,11 +120,12 @@ compileDefinition ns globals (FunDef id args ret expr) = (sum [2^i \\ i <- [0..] & _ <- args] bitor // all strict for now, TODO change (length args << 8)) // arity // instead... (end modification) - , Label label + , Label n_label ] <$> map Instr <$> compileExpr ns globals locals expr where - label = functionLabel ns NodeEntry id + closure_label i = closureLabel ns id i + n_label = functionLabel ns NodeEntry id locals = 'Data.Map'.fromList [ (id, FrontPtrArg offset) \\ (id,_) <- args @@ -119,7 +139,7 @@ compileConstructor ns _ (ConstructorDef id args) = pure , Label label , RawByte (length args) // pointer arity , RawByte 0 // basic value arity - , RawByte 0 // number of arguments still to be curried in + //, RawByte -1 // number of arguments still to be curried in (unused for constructors) ] where label = constructorLabel ns id @@ -157,7 +177,17 @@ simulator ns globals locals expr=:(ExpApp _ _) = | info.arity == length args -> mapM_ (simulator ns globals locals) (reverse args) >>| buildThunk (functionLabel ns NodeEntry id) info.arity - | otherwise -> fail "arity mismatch in application" // TODO implement + | info.arity > length args -> + mapM_ (simulator ns globals locals) (reverse args) >>| + buildCons (closureLabel ns id (length args)) (length args) + | info.arity < length args -> + let + (closure_args,extra_args) = splitAt info.arity args + closure = foldl ExpApp f closure_args + in + mapM_ (simulator ns globals locals) extra_args >>| + simulator ns globals locals closure >>| + mapM_ (\_ -> buildThunk (functionLabel "" NodeEntry "ap") 2) extra_args Constructor id -> liftT (lookupConstructor ns id globals) >>= \(ConstructorDef _ arg_types) | length arg_types == length args -> diff --git a/snug-clean/src/Snug/Compile/ABI.dcl b/snug-clean/src/Snug/Compile/ABI.dcl index 6de2953..c7fe7ad 100644 --- a/snug-clean/src/Snug/Compile/ABI.dcl +++ b/snug-clean/src/Snug/Compile/ABI.dcl @@ -21,3 +21,4 @@ TempImm :== T 0 constructorLabel :: !Namespace !ConstructorIdent -> Label functionLabel :: !Namespace !EntryPoint !SymbolIdent -> Label +closureLabel :: !Namespace !SymbolIdent !Int -> Label diff --git a/snug-clean/src/Snug/Compile/ABI.icl b/snug-clean/src/Snug/Compile/ABI.icl index 66a8d5c..225f09c 100644 --- a/snug-clean/src/Snug/Compile/ABI.icl +++ b/snug-clean/src/Snug/Compile/ABI.icl @@ -20,11 +20,15 @@ where e = case entry_point of NodeEntry -> 'n' +closureLabel :: !Namespace !SymbolIdent !Int -> Label +closureLabel ns id nargs = constructorLabel ns (concat3 id "@" (toString nargs)) + escapeLabel :: !String -> String escapeLabel s = {#c \\ c <- escape [c \\ c <-: s]} where escape [] = [] escape [c:cs] | isAlphanum c = [c:escape cs] + // Symbols allowed in snug but not in symbol names: escape ['_':cs] = ['__':escape cs] escape ['`':cs] = ['_B':escape cs] escape [':':cs] = ['_C':escape cs] @@ -36,3 +40,5 @@ where escape ['+':cs] = ['_P':escape cs] escape ['\'':cs] = ['_Q':escape cs] escape ['~':cs] = ['_T':escape cs] + // Symbols not allowed in snug but used internally: + escape ['@':cs] = ['_c':escape cs] // see closureLabel |