summary refs log tree commit diff stats
path: root/nim
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2009-04-22 15:55:27 +0200
committerAndreas Rumpf <rumpf_a@web.de>2009-04-22 15:55:27 +0200
commite792940f5273bf8f8761c4cb29b241445e8b1d0b (patch)
tree8a6b224b8c0b3db14dbc20d89b7ca9ccb19b1f56 /nim
parent439aa2d04d5528b5aed288f70895515d1da2dc3d (diff)
downloadNim-e792940f5273bf8f8761c4cb29b241445e8b1d0b.tar.gz
version 0.7.6
Diffstat (limited to 'nim')
-rw-r--r--nim/ast.pas27
-rw-r--r--nim/ccgexprs.pas45
-rw-r--r--nim/ccgstmts.pas72
-rw-r--r--nim/ccgtypes.pas83
-rw-r--r--nim/ccgutils.pas28
-rw-r--r--nim/cgen.pas482
-rw-r--r--nim/commands.pas7
-rw-r--r--nim/debugids.pas129
-rw-r--r--nim/docgen.pas4
-rw-r--r--nim/extccomp.pas4
-rw-r--r--nim/idents.pas9
-rw-r--r--nim/llstream.pas2
-rw-r--r--nim/main.pas7
-rw-r--r--nim/msgs.pas66
-rw-r--r--nim/nimconf.pas12
-rw-r--r--nim/nimrod.pas16
-rw-r--r--nim/nos.pas2
-rw-r--r--nim/nsystem.pas1
-rw-r--r--nim/nversion.pas4
-rw-r--r--nim/options.pas28
-rw-r--r--nim/parsecfg.pas2
-rw-r--r--nim/passes.pas2
-rw-r--r--nim/platform.pas2
-rw-r--r--nim/pragmas.pas13
-rw-r--r--nim/rodread.pas8
-rw-r--r--nim/rodwrite.pas3
-rw-r--r--nim/ropes.pas7
-rw-r--r--nim/rst.pas4
-rw-r--r--nim/scanner.pas4
-rw-r--r--nim/sem.pas4
-rw-r--r--nim/semdata.pas3
-rw-r--r--nim/semexprs.pas90
-rw-r--r--nim/semfold.pas2
-rw-r--r--nim/seminst.pas34
-rw-r--r--nim/semstmts.pas49
-rw-r--r--nim/semtempl.pas2
-rw-r--r--nim/semtypes.pas38
-rw-r--r--nim/sigmatch.pas15
-rw-r--r--nim/strtabs.pas4
-rw-r--r--nim/strutils.pas32
-rw-r--r--nim/transf.pas82
-rw-r--r--nim/types.pas106
-rw-r--r--nim/wordrecg.pas10
43 files changed, 1045 insertions, 499 deletions
diff --git a/nim/ast.pas b/nim/ast.pas
index c22385805..a57632468 100644
--- a/nim/ast.pas
+++ b/nim/ast.pas
@@ -93,12 +93,12 @@ type
     nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally, 
     nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt, 
     nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt, 
-    nkFromStmt, nkImportAs, nkIncludeStmt, nkAccessStmt, 
-    nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, 
-    nkBlockType, nkVm, nkTypeOfExpr, nkObjectTy, 
-    nkTupleTy, nkRecList, nkRecCase, nkRecWhen, 
-    nkRefTy, nkPtrTy, nkVarTy, nkProcTy, 
-    nkEnumTy, nkEnumFieldDef, nkReturnToken);
+    nkFromStmt, nkImportAs, nkIncludeStmt, nkCommentStmt, 
+    nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType, 
+    nkVm, nkTypeOfExpr, nkObjectTy, nkTupleTy, 
+    nkRecList, nkRecCase, nkRecWhen, nkRefTy, 
+    nkPtrTy, nkVarTy, nkProcTy, nkEnumTy, 
+    nkEnumFieldDef, nkReturnToken);
   TNodeKinds = set of TNodeKind;
 const
   NodeKindToStr: array [TNodeKind] of string = (
@@ -128,12 +128,12 @@ const
     'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally', 
     'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 
     'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 
-    'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkAccessStmt', 
-    'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType', 
-    'nkBlockType', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 
-    'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen', 
-    'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkProcTy', 
-    'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
+    'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkCommentStmt', 
+    'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 
+    'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 'nkTupleTy', 
+    'nkRecList', 'nkRecCase', 'nkRecWhen', 'nkRefTy', 
+    'nkPtrTy', 'nkVarTy', 'nkProcTy', 'nkEnumTy', 
+    'nkEnumFieldDef', 'nkReturnToken');
 type
   TSymFlag = (
     sfUsed, sfStar, sfMinus, sfInInterface, 
@@ -327,7 +327,8 @@ type
   );

 

   TLocFlag = (

-    lfIndirect,    // backend introduced a pointer

+    lfIndirect,    // backend introduced a pointer
+    lfParamCopy,   // backend introduced a parameter copy (LLVM)

     lfNoDeepCopy,  // no need for a deep copy

     lfNoDecl,      // do not declare it in C

     lfDynamicLib,  // link symbol to dynamic library

diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 161804208..03de5c4de 100644
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -1233,16 +1233,14 @@ begin
         app(r, '.Sup');
         s := skipGeneric(s.sons[0]);
       end;    
-      appf(p.s[cpsStmts], '$1.m_type = $2;$n',
-          [r, genTypeInfo(p.module, t)])
+      appf(p.s[cpsStmts], '$1.m_type = $2;$n', [r, genTypeInfo(p.module, t)])
     end;
     frEmbedded: begin 
       // worst case for performance:
       useMagic(p.module, 'objectInit');
       if takeAddr then r := addrLoc(a)
       else r := rdLoc(a);
-      appf(p.s[cpsStmts], 'objectInit($1, $2);$n',
-          [r, genTypeInfo(p.module, t)])
+      appf(p.s[cpsStmts], 'objectInit($1, $2);$n', [r, genTypeInfo(p.module, t)])
     end
   end
 end;
@@ -1256,9 +1254,15 @@ begin
   refType := skipVarGenericRange(e.sons[1].typ);
   InitLocExpr(p, e.sons[1], a);
   initLoc(b, locExpr, a.t, OnHeap);
-  b.r := ropef('($1) newObj($2, sizeof($3))',
-    [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType),
-    getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
+  
+  if optBoehmGC in gGlobalOptions then 
+    b.r := ropef('($1) newObj(sizeof($2))',
+      [getTypeDesc(p.module, reftype), 
+      getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))])  
+  else
+    b.r := ropef('($1) newObj($2, sizeof($3))',
+      [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType),
+      getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
   genAssignment(p, a, b, {@set}[]);
   // set the object type:
   bt := skipGenericRange(refType.sons[0]);
@@ -1275,10 +1279,16 @@ begin
   InitLocExpr(p, e.sons[1], a);
   InitLocExpr(p, e.sons[2], b);
   initLoc(c, locExpr, a.t, OnHeap);
-  c.r := ropef('($1) newSeq($2, $3)',
-    [getTypeDesc(p.module, seqtype),
-     genTypeInfo(p.module, seqType),
-     rdLoc(b)]);
+  if optBoehmGC in gGlobalOptions then 
+    c.r := ropef('($1) newSeq(sizeof($2), $3)',
+      [getTypeDesc(p.module, seqtype), 
+       getTypeDesc(p.module, skipGenericRange(seqtype.sons[0])),
+       rdLoc(b)])
+  else
+    c.r := ropef('($1) newSeq($2, $3)',
+      [getTypeDesc(p.module, seqtype),
+       genTypeInfo(p.module, seqType),
+       rdLoc(b)]);
   genAssignment(p, a, c, {@set}[]);
 end;
 
@@ -1324,7 +1334,8 @@ begin
   refType := skipVarGenericRange(e.sons[1].typ);
   InitLocExpr(p, e.sons[1], a);
   
-  // This is a little hack:
+  // This is a little hack: 
+  // XXX this is also a bug, if the finalizer expression produces side-effects
   oldModule := p.module;
   p.module := gmti;
   InitLocExpr(p, e.sons[2], f);
@@ -2290,7 +2301,7 @@ begin
   len := sonsLen(n);
   result := toRope('{'+'');
   for i := 0 to len - 2 do
-    app(result, ropef('$1,$n', [genConstExpr(p, n.sons[i])]));
+    appf(result, '$1,$n', [genConstExpr(p, n.sons[i])]);
   if len > 0 then app(result, genConstExpr(p, n.sons[len-1]));
   app(result, '}' + tnl)
 end;
@@ -2299,6 +2310,7 @@ function genConstExpr(p: BProc; n: PNode): PRope;
 var
   trans: PNode;
   cs: TBitSet;
+  d: TLoc;
 begin
   case n.Kind of
     nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[1]);
@@ -2317,7 +2329,10 @@ begin
         trans := n;
       result := genConstSimpleList(p, trans);
     end
-    else
-      result := genLiteral(p, n)
+    else begin
+      //  result := genLiteral(p, n)
+      initLocExpr(p, n, d);
+      result := rdLoc(d)
+    end
   end
 end;
diff --git a/nim/ccgstmts.pas b/nim/ccgstmts.pas
index e611bbeea..7588f7e15 100644
--- a/nim/ccgstmts.pas
+++ b/nim/ccgstmts.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -18,25 +18,41 @@ begin
   line := toLinenumber(t.info); // BUGFIX
   if line < 0 then line := 0; // negative numbers are not allowed in #line
   if optLineDir in p.Options then
-    appf(p.s[cpsStmts], '#line $2 "$1"$n',
+    appff(p.s[cpsStmts], 
+      '#line $2 "$1"$n',
+      '; line $2 "$1"$n',
       [toRope(toFilename(t.info)), toRope(line)]);
   if ([optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb]) and
       ((p.prc = nil) or not (sfPure in p.prc.flags)) then begin
     useMagic(p.module, 'endb');      // new: endb support
-    appf(p.s[cpsStmts], 'endb($1);$n', [toRope(line)])
+    appff(p.s[cpsStmts], 'endb($1);$n', 
+         'call void @endb(%NI $1)$n',
+         [toRope(line)])
   end
   else if ([optLineTrace, optStackTrace] * p.Options =
         [optLineTrace, optStackTrace]) and ((p.prc = nil) or
-      not (sfPure in p.prc.flags)) then
-    appf(p.s[cpsStmts], 'F.line = $1;$n', [toRope(line)])
+      not (sfPure in p.prc.flags)) then begin
+    inc(p.labels);
+    appff(p.s[cpsStmts], 'F.line = $1;$n', 
+         '%LOC$2 = getelementptr %TF %F, %NI 2$n' +
+         'store %NI $1, %NI* %LOC$2$n',
+         [toRope(line), toRope(p.labels)])
+  end
 end;
 
 procedure finishTryStmt(p: BProc; howMany: int);
 var
   i: int;
 begin
-  for i := 1 to howMany do
-    app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
+  for i := 1 to howMany do begin
+    inc(p.labels, 3);
+    appff(p.s[cpsStmts], 'excHandler = excHandler->prev;$n',
+          '%LOC$1 = load %TSafePoint** @excHandler$n' +
+          '%LOC$2 = getelementptr %TSafePoint* %LOC$1, %NI 0$n' +
+          '%LOC$3 = load %TSafePoint** %LOC$2$n' +
+          'store %TSafePoint* %LOC$3, %TSafePoint** @excHandler$n', 
+          [toRope(p.labels), toRope(p.labels-1), toRope(p.labels-2)]);
+  end
 end;
 
 procedure genReturnStmt(p: BProc; t: PNode);
@@ -45,7 +61,7 @@ begin
   genLineDir(p, t);
   if (t.sons[0] <> nil) then genStmts(p, t.sons[0]);
   finishTryStmt(p, p.nestedTryStmts);
-  app(p.s[cpsStmts], 'goto BeforeRet;' + tnl)
+  appff(p.s[cpsStmts], 'goto BeforeRet;$n', 'br label %BeforeRet$n', [])
 end;
 
 procedure initVariable(p: BProc; v: PSym);
@@ -53,11 +69,29 @@ begin
   if containsGarbageCollectedRef(v.typ) or (v.ast = nil) then
     // Language change: always initialize variables if v.ast == nil!
     if not (skipVarGenericRange(v.typ).Kind in [tyArray, tyArrayConstr, tySet,
-                                                tyTuple, tyObject]) then
-      appf(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(v.loc)])
-    else
-      appf(p.s[cpsStmts], 'memset((void*)$1, 0, sizeof($2));$n',
-        [addrLoc(v.loc), rdLoc(v.loc)])
+                                                tyTuple, tyObject]) then begin
+      if gCmd = cmdCompileToLLVM then
+        appf(p.s[cpsStmts], 'store $2 0, $2* $1$n', 
+             [addrLoc(v.loc), getTypeDesc(p.module, v.loc.t)])
+      else
+        appf(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(v.loc)])
+    end
+    else begin
+      if gCmd = cmdCompileToLLVM then begin
+        app(p.module.s[cfsProcHeaders], 
+            'declare void @llvm.memset.i32(i8*, i8, i32, i32)' + tnl);
+        inc(p.labels, 2);
+        appf(p.s[cpsStmts], 
+            '%LOC$3 = getelementptr $2* null, %NI 1$n' +
+            '%LOC$4 = cast $2* %LOC$3 to i32$n' +
+            'call void @llvm.memset.i32(i8* $1, i8 0, i32 %LOC$4, i32 0)$n', 
+            [addrLoc(v.loc), getTypeDesc(p.module, v.loc.t), 
+            toRope(p.labels), toRope(p.labels-1)])
+      end
+      else
+        appf(p.s[cpsStmts], 'memset((void*)$1, 0, sizeof($2));$n',
+          [addrLoc(v.loc), rdLoc(v.loc)])
+   end
 end;
 
 procedure genVarStmt(p: BProc; n: PNode);
@@ -73,7 +107,7 @@ begin
     assert(a.sons[0].kind = nkSym);
     v := a.sons[0].sym;
     if sfGlobal in v.flags then
-      assignGlobalVar(p.module, v)
+      assignGlobalVar(p, v)
     else begin
       assignLocalVar(p, v);
       initVariable(p, v) // XXX: this is not required if a.sons[2] != nil,
@@ -140,10 +174,14 @@ begin
       nkElifBranch: begin
         initLocExpr(p, it.sons[0], a);
         Lelse := getLabel(p);
-        appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
+        inc(p.labels);
+        appff(p.s[cpsStmts], 'if (!$1) goto $2;$n', 
+                             'br i1 $1, label %LOC$3, label %$2$n' +
+                             'LOC$3: $n', 
+                             [rdLoc(a), Lelse, toRope(p.labels)]);
         genStmts(p, it.sons[1]);
         if sonsLen(n) > 1 then
-          appf(p.s[cpsStmts], 'goto $1;$n', [Lend]);
+          appff(p.s[cpsStmts], 'goto $1;$n', 'br label %$1$n', [Lend]);
         fixLabel(p, Lelse);
       end;
       nkElse: begin
@@ -857,7 +895,7 @@ begin
     nkCaseStmt:    genCaseStmt(p, t);
     nkReturnStmt:  genReturnStmt(p, t);
     nkBreakStmt:   genBreakStmt(p, t);
-    nkCall: begin
+    nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
       genLineDir(p, t);
       initLocExpr(p, t, a);
     end;
diff --git a/nim/ccgtypes.pas b/nim/ccgtypes.pas
index f6eb64c08..ee7388e1c 100644
--- a/nim/ccgtypes.pas
+++ b/nim/ccgtypes.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -45,7 +45,19 @@ function mangleName(s: PSym): PRope;
 begin
   result := s.loc.r;
   if result = nil then begin
-    result := toRope(mangle(s.name.s));
+    if gCmd = cmdCompileToLLVM then begin
+      case s.kind of
+        skProc, skConverter, skConst: result := toRope('@'+'');
+        skVar: begin
+          if (sfGlobal in s.flags) then result := toRope('@'+'')
+          else result := toRope('%'+'');
+        end;
+        skForVar, skTemp, skParam, skType, skEnumField, skModule: 
+          result := toRope('%'+'');
+        else InternalError(s.info, 'mangleName');
+      end;
+    end;
+    app(result, toRope(mangle(s.name.s)));
     app(result, '_'+'');
     app(result, toRope(s.id));
     if optGenMapping in gGlobalOptions then
@@ -58,15 +70,33 @@ end;
 
 function getTypeName(typ: PType): PRope;
 begin
-  if (typ.sym <> nil) and ([sfImportc, sfExportc] * typ.sym.flags <> []) then
+  if (typ.sym <> nil) and ([sfImportc, sfExportc] * typ.sym.flags <> [])
+  and (gCmd <> cmdCompileToLLVM) then
     result := typ.sym.loc.r
   else begin
-    if typ.loc.r = nil then typ.loc.r := con('TY', toRope(typ.id));
+    if typ.loc.r = nil then 
+      typ.loc.r := ropeff('TY$1', '%TY$1', [toRope(typ.id)]);
     result := typ.loc.r
   end;
   if result = nil then InternalError('getTypeName: ' + typeKindToStr[typ.kind]);
 end;
 
+// ----------------------------- other helpers ----------------------------
+(*
+function getSizeof(m: BModule; var labels: int; 
+                   var body: PRope; typ: PType): PRope;
+begin
+  if (gCmd <> cmdCompileToLLVM) then 
+    result := ropef('sizeof($1)', getTypeDesc(m, typ))
+  else begin
+    inc(labels, 2);
+    result := ropef('%UOC$1', [toRope(labels)]);
+    appf(body, '%UOC$1 = getelementptr $3* null, %NI 1$n' +
+               '$2 = cast $3* %UOC$1 to i32$n', 
+               [toRope(labels-1), result, getTypeDesc(m, typ)]);
+  end
+end; *)
+
 // ------------------------------ C type generator ------------------------
 
 function mapType(typ: PType): TCTypeKind;
@@ -104,10 +134,6 @@ begin
     tyPtr, tyVar, tyRef: begin
       case typ.sons[0].kind of
         tyOpenArray, tyArrayConstr, tyArray: result := ctArray;
-        (*tySet: begin
-          if mapType(typ.sons[0]) = ctArray then result := ctArray
-          else result := ctPtr
-        end*)
         else result := ctPtr
       end
     end;
@@ -155,6 +181,10 @@ const
     // but one can //define it to what you want so there will no problem
     'N_INLINE', 'N_NOINLINE', 'N_FASTCALL', 'N_CLOSURE', 'N_NOCONV');
 
+  CallingConvToStrLLVM: array [TCallingConvention] of string = ('fastcc $1',
+    'stdcall $1', 'ccc $1', 'safecall $1', 'syscall $1',
+    '$1 alwaysinline', '$1 noinline', 'fastcc $1', 'ccc $1', '$1');
+
 function CacheGetType(const tab: TIdTable; key: PType): PRope;
 begin
   // returns nil if we need to declare this type
@@ -165,7 +195,13 @@ end;
 
 function getTempName(): PRope;
 begin
-  result := con('TMP', toRope(gId));
+  result := ropeff('TMP$1', '%TMP$1', [toRope(gId)]);
+  inc(gId);
+end;
+
+function getGlobalTempName(): PRope;
+begin
+  result := ropeff('TMP$1', '@TMP$1', [toRope(gId)]);
   inc(gId);
 end;
 
@@ -194,7 +230,8 @@ end;
 
 procedure fillResult(param: PSym);
 begin
-  fillLoc(param.loc, locParam, param.typ, toRope('Result'), OnStack);
+  fillLoc(param.loc, locParam, param.typ, ropeff('Result', '%Result', []), 
+          OnStack);
   if (mapType(param.typ) <> ctArray) and IsInvalidReturnType(param.typ) then
   begin
     include(param.loc.flags, lfIndirect);
@@ -232,7 +269,7 @@ begin
     if arr.kind = tyVar then arr := arr.sons[0];
     j := 0;
     while arr.Kind = tyOpenArray do begin // need to pass hidden parameter:
-      appf(params, ', NI $1Len$2', [param.loc.r, toRope(j)]);
+      appff(params, ', NI $1Len$2', ', @NI $1Len$2', [param.loc.r, toRope(j)]);
       inc(j);
       arr := arr.sons[0]
     end;
@@ -241,8 +278,9 @@ begin
   if (t.sons[0] <> nil) and isInvalidReturnType(t.sons[0]) then begin
     if params <> nil then app(params, ', ');
     app(params, getTypeDescAux(m, t.sons[0], check));
-    if mapType(t.sons[0]) <> ctArray then app(params, '*'+'');
-    app(params, ' Result');
+    if (mapType(t.sons[0]) <> ctArray) or (gCmd = cmdCompileToLLVM) then 
+      app(params, '*'+'');
+    appff(params, ' Result', ' @Result', []);
   end;
   if t.callConv = ccClosure then begin
     if params <> nil then app(params, ', ');
@@ -252,7 +290,7 @@ begin
     if params <> nil then app(params, ', ');
     app(params, '...')
   end;
-  if params = nil then
+  if (params = nil) and (gCmd <> cmdCompileToLLVM) then
     app(params, 'void)')
   else
     app(params, ')'+'');
@@ -621,7 +659,7 @@ begin
   end
 end;
 
-function getTypeDesc(m: BModule; typ: PType): PRope;
+function getTypeDesc(m: BModule; typ: PType): PRope; overload;
 var
   check: TIntSet;
 begin
@@ -629,6 +667,19 @@ begin
   result := getTypeDescAux(m, typ, check);
 end;
 
+function getTypeDesc(m: BModule; const magic: string): PRope; overload;
+var
+  sym: PSym;
+begin
+  sym := magicsys.getCompilerProc(magic);
+  if sym <> nil then 
+    result := getTypeDesc(m, sym.typ)
+  else begin
+    rawMessage(errSystemNeeds, magic);
+    result := nil
+  end
+end;
+
 procedure finishTypeDescriptions(m: BModule);
 var
   i: int;
@@ -1012,4 +1063,4 @@ begin
     end
   end
 end;
-*)
\ No newline at end of file
+*)
diff --git a/nim/ccgutils.pas b/nim/ccgutils.pas
index 97ef65f70..56eff6c9e 100644
--- a/nim/ccgutils.pas
+++ b/nim/ccgutils.pas
@@ -20,6 +20,7 @@ uses
 
 function toCChar(c: Char): string;
 function makeCString(const s: string): PRope;
+function makeLLVMString(const s: string): PRope;
 
 function TableGetType(const tab: TIdTable; key: PType): PObject;
 function GetUniqueType(key: PType): PType;
@@ -154,6 +155,33 @@ begin
   app(result, toRope(res));
 end;
 
+function makeLLVMString(const s: string): PRope;
+const
+  MaxLineLength = 64;
+var
+  i: int;
+  res: string;
+begin
+  result := nil;
+  res := 'c"';
+  for i := strStart to length(s)+strStart-1 do begin
+    if (i-strStart+1) mod MaxLineLength = 0 then begin
+      app(result, toRope(res));
+      setLength(res, 0);
+    end;
+    case s[i] of
+     #0..#31, #128..#255, '"', '\': begin
+       addChar(res, '\');
+       add(res, toHex(ord(s[i]), 2));
+     end
+     else
+       addChar(res, s[i])
+    end;
+  end;
+  add(res, '\00"');
+  app(result, toRope(res));
+end;
+
 begin
   InitTypeTables();
 end.
diff --git a/nim/cgen.pas b/nim/cgen.pas
index 02713f902..5dcb7f50b 100644
--- a/nim/cgen.pas
+++ b/nim/cgen.pas
@@ -37,9 +37,9 @@ type
                        // reasons
     cfsFieldInfo,      // section for field information
     cfsTypeInfo,       // section for type information
+    cfsProcHeaders,    // section for C procs prototypes
     cfsData,           // section for C constant data
     cfsVars,           // section for C variable declarations
-    cfsProcHeaders,    // section for C procs prototypes
     cfsProcs,          // section for C procs that are not inline
     cfsTypeInit1,      // section 1 for declarations of type information
     cfsTypeInit2,      // section 2 for initialization of type information
@@ -120,6 +120,7 @@ type
     forwardedProcs: TSymSeq; // keep forwarded procs here
     typeNodes, nimTypes: int;// used for type info generation
     typeNodesName, nimTypesName: PRope; // used for type info generation
+    labels: natural;         // for generating unique module-scope names
   end;
 
 var
@@ -132,6 +133,24 @@ var
   gForwardedProcsCounter: int = 0;
   gmti: BModule; // generated type info: no need to initialize: defaults fit
 
+function ropeff(const cformat, llvmformat: string; 
+                const args: array of PRope): PRope;
+begin
+  if gCmd = cmdCompileToLLVM then 
+    result := ropef(llvmformat, args)
+  else
+    result := ropef(cformat, args)
+end;
+
+procedure appff(var dest: PRope; const cformat, llvmformat: string; 
+                const args: array of PRope);
+begin
+  if gCmd = cmdCompileToLLVM then 
+    appf(dest, llvmformat, args)
+  else
+    appf(dest, cformat, args);
+end;
+
 procedure addForwardedProc(m: BModule; prc: PSym);
 var
   L: int;
@@ -240,8 +259,12 @@ end;
 procedure getTemp(p: BProc; t: PType; var result: TLoc);
 begin
   inc(p.labels);
-  result.r := con('LOC', toRope(p.labels));
-  appf(p.s[cpsLocals], '$1 $2;$n', [getTypeDesc(p.module, t), result.r]);
+  if gCmd = cmdCompileToLLVM then 
+    result.r := con('%LOC', toRope(p.labels))
+  else begin
+    result.r := con('LOC', toRope(p.labels));
+    appf(p.s[cpsLocals], '$1 $2;$n', [getTypeDesc(p.module, t), result.r]);
+  end;
   result.k := locTemp;
   result.a := -1;
   result.t := getUniqueType(t);
@@ -251,6 +274,86 @@ end;
 
 // -------------------------- Variable manager ----------------------------
 
+function cstringLit(p: BProc; var r: PRope; const s: string): PRope; overload;
+begin
+  if gCmd = cmdCompileToLLVM then begin
+    inc(p.module.labels);
+    inc(p.labels);
+    result := ropef('%LOC$1', [toRope(p.labels)]);
+    appf(p.module.s[cfsData], '@C$1 = private constant [$2 x i8] $3$n', [
+         toRope(p.module.labels), toRope(length(s)), makeLLVMString(s)]);
+    appf(r, '$1 = getelementptr [$2 x i8]* @C$3, %NI 0, %NI 0$n', 
+        [result, toRope(length(s)), toRope(p.module.labels)]);
+  end
+  else
+    result := makeCString(s)
+end;
+
+function cstringLit(m: BModule; var r: PRope; const s: string): PRope; overload;
+begin
+  if gCmd = cmdCompileToLLVM then begin
+    inc(m.labels, 2);
+    result := ropef('%MOC$1', [toRope(m.labels-1)]);
+    appf(m.s[cfsData], '@MOC$1 = private constant [$2 x i8] $3$n', [
+         toRope(m.labels), toRope(length(s)), makeLLVMString(s)]);
+    appf(r, '$1 = getelementptr [$2 x i8]* @MOC$3, %NI 0, %NI 0$n', 
+        [result, toRope(length(s)), toRope(m.labels)]);
+  end
+  else
+    result := makeCString(s)
+end;
+
+procedure allocParam(p: BProc; s: PSym);
+var
+  tmp: PRope;
+begin
+  assert(s.kind = skParam);
+  if not (lfParamCopy in s.loc.flags) then begin
+    inc(p.labels);
+    tmp := con('%LOC', toRope(p.labels));
+    include(s.loc.flags, lfParamCopy);
+    include(s.loc.flags, lfIndirect);
+    appf(p.s[cpsInit], 
+        '$1 = alloca $3$n' +
+        'store $3 $2, $3* $1$n', [tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)]);
+    s.loc.r := tmp
+  end;
+end;
+
+procedure localDebugInfo(p: BProc; s: PSym); 
+var
+  name, a: PRope;
+begin
+  if [optStackTrace, optEndb] * p.options <> [optStackTrace, optEndb] then exit;
+  if gCmd = cmdCompileToLLVM then begin
+    // "address" is the 0th field
+    // "typ" is the 1rst field
+    // "name" is the 2nd field
+    name := cstringLit(p, p.s[cpsInit], normalize(s.name.s));
+    if (s.kind = skParam) and not ccgIntroducedPtr(s) then allocParam(p, s);
+    inc(p.labels, 3);
+    appf(p.s[cpsInit], 
+        '%LOC$6 = getelementptr %TF* %F, %NI 0, $1, %NI 0$n' +
+        '%LOC$7 = getelementptr %TF* %F, %NI 0, $1, %NI 1$n' +
+        '%LOC$8 = getelementptr %TF* %F, %NI 0, $1, %NI 2$n' +
+        'store i8* $2, i8** %LOC$6$n' +
+        'store $3* $4, $3** %LOC$7$n' +
+        'store i8* $5, i8** %LOC$8$n', 
+        [toRope(p.frameLen), s.loc.r, getTypeDesc(p.module, 'TNimType'),
+         genTypeInfo(p.module, s.loc.t), name, toRope(p.labels), 
+         toRope(p.labels-1), toRope(p.labels-2)])
+  end
+  else begin
+    a := con('&'+'', s.loc.r);
+    if (s.kind = skParam) and ccgIntroducedPtr(s) then a := s.loc.r;
+    appf(p.s[cpsInit],
+      'F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n',
+      [toRope(p.frameLen), makeCString(normalize(s.name.s)), a,
+      genTypeInfo(p.module, s.loc.t)]);
+  end;
+  inc(p.frameLen);
+end;
+
 procedure assignLocalVar(p: BProc; s: PSym);
 begin
   //assert(s.loc.k == locNone) // not yet assigned
@@ -258,45 +361,54 @@ begin
   // for each module that uses them!
   if s.loc.k = locNone then
     fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack);
-  app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
-  if sfRegister in s.flags then
-    app(p.s[cpsLocals], ' register');
-  if (sfVolatile in s.flags) or (p.nestedTryStmts > 0) then
-    app(p.s[cpsLocals], ' volatile');
+  if gCmd = cmdCompileToLLVM then begin
+    appf(p.s[cpsLocals], '$1 = alloca $2$n', 
+         [s.loc.r, getTypeDesc(p.module, s.loc.t)]);
+    include(s.loc.flags, lfIndirect);
+  end
+  else begin
+    app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
+    if sfRegister in s.flags then
+      app(p.s[cpsLocals], ' register');
+    if (sfVolatile in s.flags) or (p.nestedTryStmts > 0) then
+      app(p.s[cpsLocals], ' volatile');
 
-  appf(p.s[cpsLocals], ' $1;$n', [s.loc.r]);
+    appf(p.s[cpsLocals], ' $1;$n', [s.loc.r]);
+  end;
   // if debugging we need a new slot for the local variable:
-  if [optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb] then begin
-    appf(p.s[cpsInit],
-      'F.s[$1].name = $2; F.s[$1].address = (void*)&$3; F.s[$1].typ = $4;$n',
-      [toRope(p.frameLen), makeCString(normalize(s.name.s)), s.loc.r,
-      genTypeInfo(p.module, s.loc.t)]);
-    inc(p.frameLen);
-  end
+  localDebugInfo(p, s);
 end;
 
-procedure assignGlobalVar(m: BModule; s: PSym);
+procedure assignGlobalVar(p: BProc; s: PSym);
 begin
   if s.loc.k = locNone then
     fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap);
-  useHeader(m, s);
-  if lfNoDecl in s.loc.flags then exit;
-  if sfImportc in s.flags then app(m.s[cfsVars], 'extern ');
-  app(m.s[cfsVars], getTypeDesc(m, s.loc.t));
-  if sfRegister in s.flags then
-    app(m.s[cfsVars], ' register');
-  if sfVolatile in s.flags then
-    app(m.s[cfsVars], ' volatile');
-  if sfThreadVar in s.flags then
-    app(m.s[cfsVars], ' NIM_THREADVAR');
-  appf(m.s[cfsVars], ' $1;$n', [s.loc.r]);
-  if [optStackTrace, optEndb] * m.module.options =
+  if gCmd = cmdCompileToLLVM then begin
+    appf(p.module.s[cfsVars], '$1 = linkonce global $2 zeroinitializer$n', 
+         [s.loc.r, getTypeDesc(p.module, s.loc.t)]);
+    include(s.loc.flags, lfIndirect);
+  end
+  else begin
+    useHeader(p.module, s);
+    if lfNoDecl in s.loc.flags then exit;
+    if sfImportc in s.flags then app(p.module.s[cfsVars], 'extern ');
+    app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t));
+    if sfRegister in s.flags then app(p.module.s[cfsVars], ' register');
+    if sfVolatile in s.flags then app(p.module.s[cfsVars], ' volatile');
+    if sfThreadVar in s.flags then app(p.module.s[cfsVars], ' NIM_THREADVAR');
+    appf(p.module.s[cfsVars], ' $1;$n', [s.loc.r]);
+  end;
+  if [optStackTrace, optEndb] * p.module.module.options =
      [optStackTrace, optEndb] then begin
-    useMagic(m, 'dbgRegisterGlobal');
-    appf(m.s[cfsDebugInit],
+    useMagic(p.module, 'dbgRegisterGlobal');
+    appff(p.module.s[cfsDebugInit], 
       'dbgRegisterGlobal($1, &$2, $3);$n',
-      [makeCString(normalize(s.owner.name.s + '.' +{&} s.name.s)), s.loc.r,
-      genTypeInfo(m, s.typ)])
+      'call void @dbgRegisterGlobal(i8* $1, i8* $2, $4* $3)$n',
+      [cstringLit(p, p.module.s[cfsDebugInit], 
+                  normalize(s.owner.name.s + '.' +{&} s.name.s)),
+       s.loc.r,
+       genTypeInfo(p.module, s.typ),
+       getTypeDesc(p.module, 'TNimType')]);
   end;
 end;
 
@@ -308,15 +420,9 @@ end;
 procedure assignParam(p: BProc; s: PSym);
 begin
   assert(s.loc.r <> nil);
-  if [optStackTrace, optEndb] * p.options = [optStackTrace, optEndb] then begin
-    appf(p.s[cpsInit],
-      'F.s[$1].name = $2; F.s[$1].address = (void*)$3; ' +
-      'F.s[$1].typ = $4;$n',
-      [toRope(p.frameLen), makeCString(normalize(s.name.s)),
-      iff(ccgIntroducedPtr(s), s.loc.r, con('&'+'', s.loc.r)),
-      genTypeInfo(p.module, s.loc.t)]);
-    inc(p.frameLen)
-  end
+  if (sfAddrTaken in s.flags) and (gCmd = cmdCompileToLLVM) then 
+    allocParam(p, s);
+  localDebugInfo(p, s);
 end;
 
 procedure fillProcLoc(sym: PSym);
@@ -359,19 +465,26 @@ begin
   assert(lib <> nil);
   if not lib.generated then begin
     lib.generated := true;
+    tmp := getGlobalTempName();
+    assert(lib.name = nil);
+    lib.name := tmp;
+    // BUGFIX: useMagic has awful side-effects
+    appff(m.s[cfsVars], 'static void* $1;$n', 
+                        '$1 = linkonce global i8* zeroinitializer$n', [tmp]);
+    inc(m.labels);
+    appff(m.s[cfsDynLibInit],
+        '$1 = nimLoadLibrary((NimStringDesc*) &$2);$n',
+        '%MOC$4 = call i8* @nimLoadLibrary($3 $2)$n' +
+        'store i8* %MOC$4, i8** $1$n',
+        [tmp, getStrLit(m, lib.path), getTypeDesc(m, getSysType(tyString)),
+         toRope(m.labels)]);
+    //appf(m.s[cfsDynLibDeinit],
+    //  'if ($1 != NIM_NIL) nimUnloadLibrary($1);$n', [tmp]);
     useMagic(m, 'nimLoadLibrary');
     useMagic(m, 'nimUnloadLibrary');
     useMagic(m, 'NimStringDesc');
-    tmp := getTempName();
-    appf(m.s[cfsVars], 'static void* $1;$n', [tmp]);
-    appf(m.s[cfsDynLibInit],
-      '$1 = nimLoadLibrary((NimStringDesc*) &$2);$n',
-      [tmp, getStrLit(m, lib.path)]);
-    appf(m.s[cfsDynLibDeinit],
-      'if ($1 != NIM_NIL) nimUnloadLibrary($1);$n', [tmp]);
-    assert(lib.name = nil);
-    lib.name := tmp
-  end
+  end;
+  if lib.name = nil then InternalError('loadDynamicLib');
 end;
 
 procedure SymInDynamicLib(m: BModule; sym: PSym);
@@ -383,14 +496,25 @@ begin
   extname := sym.loc.r;
   loadDynamicLib(m, lib);
   useMagic(m, 'nimGetProcAddr');
-  tmp := ropef('Dl_$1', [toRope(sym.id)]);
+  if gCmd = cmdCompileToLLVM then include(sym.loc.flags, lfIndirect);
+
+  tmp := ropeff('Dl_$1', '@Dl_$1', [toRope(sym.id)]);
   sym.loc.r := tmp; // from now on we only need the internal name
   sym.typ.sym := nil; // generate a new name
-  appf(m.s[cfsDynLibInit], '$1 = ($2) nimGetProcAddr($3, $4);$n',
-    [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString(ropeToStr(extname))]);
-
-  app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
-  appf(m.s[cfsVars], ' $1;$n', [sym.loc.r]);
+  inc(m.labels, 2);
+  appff(m.s[cfsDynLibInit], 
+    '$1 = ($2) nimGetProcAddr($3, $4);$n',
+    '%MOC$5 = load i8* $3$n' +
+    '%MOC$6 = call $2 @nimGetProcAddr(i8* %MOC$5, i8* $4)$n' +
+    'store $2 %MOC$6, $2* $1$n',
+    [tmp, getTypeDesc(m, sym.typ), lib.name, 
+    cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname)),
+    toRope(m.labels), toRope(m.labels-1)]);
+
+  appff(m.s[cfsVars], 
+    '$2 $1;$n', 
+    '$1 = linkonce global $2 zeroinitializer$n',
+    [sym.loc.r, getTypeDesc(m, sym.loc.t)]);
 end;
 
 // ----------------------------- sections ---------------------------------
@@ -433,14 +557,23 @@ var
 begin
   if p.frameLen > 0 then begin
     useMagic(p.module, 'TVarSlot');
-    slots := ropef('  TVarSlot s[$1];$n', [toRope(p.frameLen)])
+    slots := ropeff('  TVarSlot s[$1];$n',
+                    ', [$1 x %TVarSlot]', [toRope(p.frameLen)])
   end
   else
     slots := nil;
-  appf(p.s[cpsLocals], 'volatile struct {TFrame* prev;' +
+  appff(p.s[cpsLocals], 
+    'volatile struct {TFrame* prev;' +
     'NCSTRING procname;NI line;NCSTRING filename;' +
-    'NI len;$n$1} F;$n', [slots]);
-  prepend(p.s[cpsInit], ropef('F.len = $1;$n', [toRope(p.frameLen)]))
+    'NI len;$n$1} F;$n', 
+    '%TF = type {%TFrame*, i8*, %NI, %NI$1}$n' + 
+    '%F = alloca %TF$n',
+    [slots]);
+  inc(p.labels);
+  prepend(p.s[cpsInit], ropeff('F.len = $1;$n',
+      '%LOC$2 = getelementptr %TF %F, %NI 4$n' +
+      'store %NI $1, %NI* %LOC$2$n',
+      [toRope(p.frameLen), toRope(p.labels)]))
 end;
 
 function retIsNotVoid(s: PSym): bool;
@@ -448,10 +581,48 @@ begin
   result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
 end;
 
+function initFrame(p: BProc; procname, filename: PRope): PRope;
+begin
+  inc(p.labels, 5);
+  result := ropeff(
+    'F.procname = $1;$n' +
+    'F.prev = framePtr;$n' +
+    'F.filename = $2;$n' +
+    'F.line = 0;$n' +
+    'framePtr = (TFrame*)&F;$n',
+    
+    '%LOC$3 = getelementptr %TF %F, %NI 1$n' +
+    '%LOC$4 = getelementptr %TF %F, %NI 0$n' +
+    '%LOC$5 = getelementptr %TF %F, %NI 3$n' +
+    '%LOC$6 = getelementptr %TF %F, %NI 2$n' +
+    
+    'store i8* $1, i8** %LOC$3$n' +
+    'store %TFrame* @framePtr, %TFrame** %LOC$4$n' +
+    'store i8* $2, i8** %LOC$5$n' +
+    'store %NI 0, %NI* %LOC$6$n' +
+    
+    '%LOC$7 = bitcast %TF* %F to %TFrame*$n' +
+    'store %TFrame* %LOC$7, %TFrame** @framePtr$n',
+    [procname, filename, toRope(p.labels), toRope(p.labels-1), 
+     toRope(p.labels-2), toRope(p.labels-3), toRope(p.labels-4)]);
+end;
+
+function deinitFrame(p: BProc): PRope;
+begin
+  inc(p.labels, 3);
+  result := ropeff('framePtr = framePtr->prev;$n',
+    
+                   '%LOC$1 = load %TFrame* @framePtr$n' +
+                   '%LOC$2 = getelementptr %TFrame* %LOC$1, %NI 0$n' +
+                   '%LOC$3 = load %TFrame** %LOC$2$n' +
+                   'store %TFrame* $LOC$3, %TFrame** @framePtr', [
+                   toRope(p.labels), toRope(p.labels-1), toRope(p.labels-2)])
+end;
+
 procedure genProcAux(m: BModule; prc: PSym);
 var
   p: BProc;
-  generatedProc, header, returnStmt: PRope;
+  generatedProc, header, returnStmt, procname, filename: PRope;
   i: int;
   res, param: PSym;
 begin
@@ -466,7 +637,7 @@ begin
       // declare the result symbol:
       assignLocalVar(p, res);
       assert(res.loc.r <> nil);
-      returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]);
+      returnStmt := ropeff('return $1;$n', 'ret $1$n', [rdLoc(res.loc)]);
     end
     else begin
       fillResult(res);
@@ -482,22 +653,21 @@ begin
 
   genStmts(p, prc.ast.sons[codePos]); // modifies p.locals, p.init, etc.
   if sfPure in prc.flags then
-    generatedProc := ropef('$1 {$n$2$3$4}$n',
+    generatedProc := ropeff('$1 {$n$2$3$4}$n', 'define $1 {$n$2$3$4}$n',
       [header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
   else begin
-    generatedProc := con(header, '{' + tnl);
+    generatedProc := ropeff('$1 {$n', 'define $1 {$n', [header]);
     if optStackTrace in prc.options then begin
       getFrameDecl(p);
-      prepend(p.s[cpsInit], ropef(
-        'F.procname = $1;$n' +
-        'F.prev = framePtr;$n' +
-        'F.filename = $2;$n' +
-        'F.line = 0;$n' +
-        'framePtr = (TFrame*)&F;$n',
-        [makeCString(prc.owner.name.s +{&} '.' +{&} prc.name.s),
-        makeCString(toFilename(prc.info))]));
-    end;
-    if optProfiler in prc.options then begin
+      app(generatedProc, p.s[cpsLocals]);
+      procname := CStringLit(p, generatedProc, 
+                             prc.owner.name.s +{&} '.' +{&} prc.name.s);
+      filename := CStringLit(p, generatedProc, toFilename(prc.info));
+      app(generatedProc, initFrame(p, procname, filename));
+    end
+    else
+      app(generatedProc, p.s[cpsLocals]);
+    if (optProfiler in prc.options) and (gCmd <> cmdCompileToLLVM) then begin
       if gProcProfile >= 64*1024 then // XXX: hard coded value!
         InternalError(prc.info, 'too many procedures for profiling');
       useMagic(m, 'profileData');
@@ -511,12 +681,13 @@ begin
       end;
       prepend(p.s[cpsInit], toRope('NIM_profilingStart = getticks();' + tnl));
     end;
-    app(generatedProc, con(p.s));
+    app(generatedProc, p.s[cpsInit]);
+    app(generatedProc, p.s[cpsStmts]);
     if p.beforeRetNeeded then
       app(generatedProc, 'BeforeRet: ;' + tnl);
     if optStackTrace in prc.options then
-      app(generatedProc, 'framePtr = framePtr->prev;' + tnl);
-    if optProfiler in prc.options then
+      app(generatedProc, deinitFrame(p));
+    if (optProfiler in prc.options) and (gCmd <> cmdCompileToLLVM) then 
       appf(generatedProc,
         'profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n',
         [toRope(prc.loc.a)]);
@@ -533,8 +704,10 @@ begin
   if lfDynamicLib in sym.loc.Flags then begin
     if (sym.owner.id <> m.module.id) and
         not intSetContainsOrIncl(m.declaredThings, sym.id) then begin
-      appf(m.s[cfsVars], 'extern $1 Dl_$2;$n',
-           [getTypeDesc(m, sym.loc.t), toRope(sym.id)])
+      appff(m.s[cfsVars], 'extern $1 Dl_$2;$n',
+           '@Dl_$2 = linkonce global $1 zeroinitializer$n',
+           [getTypeDesc(m, sym.loc.t), toRope(sym.id)]);
+      if gCmd = cmdCompileToLLVM then include(sym.loc.flags, lfIndirect);
     end
   end
   else begin
@@ -586,15 +759,22 @@ begin
   if sym.owner.id <> m.module.id then begin
     // else we already have the symbol generated!
     assert(sym.loc.r <> nil);
-    app(m.s[cfsVars], 'extern ');
-    app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
-    if sfRegister in sym.flags then
-      app(m.s[cfsVars], ' register');
-    if sfVolatile in sym.flags then
-      app(m.s[cfsVars], ' volatile');
-    if sfThreadVar in sym.flags then
-      app(m.s[cfsVars], ' NIM_THREADVAR');
-    appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
+    if gCmd = cmdCompileToLLVM then begin
+      include(sym.loc.flags, lfIndirect);
+      appf(m.s[cfsVars], '$1 = linkonce global $2 zeroinitializer$n', 
+           [sym.loc.r, getTypeDesc(m, sym.loc.t)]);
+    end
+    else begin
+      app(m.s[cfsVars], 'extern ');
+      app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
+      if sfRegister in sym.flags then
+        app(m.s[cfsVars], ' register');
+      if sfVolatile in sym.flags then
+        app(m.s[cfsVars], ' volatile');
+      if sfThreadVar in sym.flags then
+        app(m.s[cfsVars], ' NIM_THREADVAR');
+      appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
+    end
   end
 end;
 
@@ -609,8 +789,9 @@ begin
   if sym.owner.id <> m.module.id then begin
     // else we already have the symbol generated!
     assert(sym.loc.r <> nil);
-    app(m.s[cfsData], 'extern ');
-    appf(m.s[cfsData], 'NIM_CONST $1 $2;$n',
+    appff(m.s[cfsData], 
+      'extern NIM_CONST $1 $2;$n',
+      '$1 = linkonce constant $2 zeroinitializer',
       [getTypeDesc(m, sym.loc.t), sym.loc.r])
   end
 end;
@@ -618,27 +799,36 @@ end;
 function getFileHeader(const cfilenoext: string): PRope;
 begin
   if optCompileOnly in gGlobalOptions then
-    result := ropef(
+    result := ropeff(
       '/* Generated by the Nimrod Compiler v$1 */$n' +
       '/*   (c) 2008 Andreas Rumpf */$n',
+      '; Generated by the Nimrod Compiler v$1$n' +
+      ';   (c) 2008 Andreas Rumpf$n',
       [toRope(versionAsString)])
   else
-    result := ropef(
+    result := ropeff(
       '/* Generated by the Nimrod Compiler v$1 */$n' +
       '/*   (c) 2008 Andreas Rumpf */$n' +
       '/* Compiled for: $2, $3, $4 */$n' +
       '/* Command for C compiler:$n   $5 */$n',
+      '; Generated by the Nimrod Compiler v$1$n' +
+      ';   (c) 2008 Andreas Rumpf$n' +
+      '; Compiled for: $2, $3, $4$n' +
+      '; Command for C compiler:$n   $5$n',
       [toRope(versionAsString), toRope(platform.OS[targetOS].name),
       toRope(platform.CPU[targetCPU].name),
       toRope(extccomp.CC[extccomp.ccompiler].name),
       toRope(getCompileCFileCmd(cfilenoext))]);
   case platform.CPU[targetCPU].intSize of
-    16: appf(result, '$ntypedef short int NI;$n' +
-                     'typedef unsigned short int NU;$n', []);
-    32: appf(result, '$ntypedef long int NI;$n' +
-                     'typedef unsigned long int NU;$n', []);
-    64: appf(result, '$ntypedef long long int NI;$n' +
-                     'typedef unsigned long long int NU;$n', []);
+    16: appff(result, '$ntypedef short int NI;$n' +
+                      'typedef unsigned short int NU;$n',
+                      '$n%NI = type i16$n', []);
+    32: appff(result, '$ntypedef long int NI;$n' +
+                      'typedef unsigned long int NU;$n',
+                      '$n%NI = type i32$n', []);
+    64: appff(result, '$ntypedef long long int NI;$n' +
+                      'typedef unsigned long long int NU;$n',
+                      '$n%NI = type i64$n', []);
     else begin end
   end
 end;
@@ -651,18 +841,37 @@ const
     '  systemInit();$n' +
     '$1' +
     '$2';
+  CommonMainBodyLLVM = 
+    '  %MOC$3 = bitcast [8 x %NI]* %dummy to i8*$n' +
+    '  call void @setStackBottom(i8* %MOC$3)$n' +
+    '  call void @nim__datInit()$n' +
+    '  call void systemInit()$n' +
+    '$1' +
+    '$2';    
   PosixMain =
-    'NI cmdCount;$n' +
+    'int cmdCount;$n' +
     'char** cmdLine;$n' +
     'char** gEnv;$n' +
     'int main(int argc, char** args, char** env) {$n' +
     '  int dummy[8];$n' +
     '  cmdLine = args;$n' +
-    '  cmdCount = (NI)argc;$n' +
+    '  cmdCount = argc;$n' +
     '  gEnv = env;$n' +{&}
     CommonMainBody +{&}
     '  return 0;$n' +
     '}$n';
+  PosixMainLLVM =
+    '@cmdCount = linkonce i32$n' +
+    '@cmdLine = linkonce i8**$n' +
+    '@gEnv = linkonce i8**$n' +
+    'define i32 @main(i32 %argc, i8** %args, i8** %env) {$n' +
+    '  %dummy = alloca [8 x %NI]$n' +
+    '  store i8** %args, i8*** @cmdLine$n' +
+    '  store i32 %argc, i32* @cmdCount$n' +
+    '  store i8** %env, i8*** @gEnv$n' +{&}
+    CommonMainBodyLLVM +{&}
+    '  ret i32 0$n' +
+    '}$n';
   WinMain =
     'N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n' +
     '                        HINSTANCE hPrevInstance, $n' +
@@ -671,6 +880,14 @@ const
     CommonMainBody +{&}
     '  return 0;$n' +
     '}$n';
+  WinMainLLVM =
+    'define stdcall i32 @WinMain(i32 %hCurInstance, $n' +
+    '                            i32 %hPrevInstance, $n' +
+    '                            i8* %lpCmdLine, i32 %nCmdShow) {$n' +
+    '  %dummy = alloca [8 x %NI]$n' +{&}
+    CommonMainBodyLLVM +{&}
+    '  ret i32 0$n' +
+    '}$n';
   WinDllMain =
     'BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n' +
     '                    LPVOID lpvReserved) {$n' +
@@ -678,6 +895,13 @@ const
     CommonMainBody +{&}
     '  return 1;$n' +
     '}$n';
+  WinDllMainLLVM =
+    'define stdcall i32 @DllMain(i32 %hinstDLL, i32 %fwdreason, $n' +
+    '                            i8* %lpvReserved) {$n' +
+    '  %dummy = alloca [8 x %NI]$n' +{&}
+    CommonMainBodyLLVM +{&}
+    '  ret i32 1$n' +
+    '}$n';
 var
   frmt: TFormatStr;
 begin
@@ -685,21 +909,28 @@ begin
   if (platform.targetOS = osWindows) and
       (gGlobalOptions * [optGenGuiApp, optGenDynLib] <> []) then begin
     if optGenGuiApp in gGlobalOptions then
-      frmt := WinMain
+      if gCmd = cmdCompileToLLVM then frmt := WinMainLLVM else frmt := WinMain
     else
-      frmt := WinDllMain;
+      if gCmd = cmdCompileToLLVM then 
+        frmt := WinDllMainLLVM 
+      else 
+        frmt := WinDllMain;
     {@discard} lists.IncludeStr(m.headerFiles, '<windows.h>')
   end
-  else
-    frmt := PosixMain;
+  else 
+    if gCmd = cmdCompileToLLVM then 
+      frmt := PosixMainLLVM 
+    else 
+      frmt := PosixMain;
   if gBreakpoints <> nil then
     useMagic(m, 'dbgRegisterBreakpoint');
-  appf(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit])
+  inc(m.labels);
+  appf(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit, toRope(m.labels)])
 end;
 
 function getInitName(m: PSym): PRope;
 begin
-  result := con(m.name.s, toRope('Init'));
+  result := ropeff('$1Init', '@$1Init', [toRope(m.name.s)]);
 end;
 
 procedure registerModuleToMain(m: PSym);
@@ -707,14 +938,15 @@ var
   initname: PRope;
 begin
   initname := getInitName(m);
-  appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [initname]);
+  appff(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
+                      'declare void $1() noinline$n', [initname]);
   if not (sfSystemModule in m.flags) then
-    appf(mainModInit, '$1();$n', [initname]);
+    appff(mainModInit, '$1();$n', 'call void ()* $1$n', [initname]);
 end;
 
 procedure genInitCode(m: BModule);
 var
-  initname, prc: PRope;
+  initname, prc, procname, filename: PRope;
 begin
   if optProfiler in m.initProc.options then begin
     // This does not really belong here, but there is no good place for this
@@ -723,31 +955,28 @@ begin
     {@discard} lists.IncludeStr(m.headerFiles, '<cycle.h>');
   end;
   initname := getInitName(m.module);
-  prc := ropef('N_NOINLINE(void, $1)(void) {$n', [initname]);
-  
+  prc := ropeff('N_NOINLINE(void, $1)(void) {$n',
+                'define void $1() noinline {$n', [initname]);
   if m.typeNodes > 0 then begin
     useMagic(m, 'TNimNode');
-    appf(m.s[cfsTypeInit1], 'static TNimNode $1[$2];$n', 
+    appff(m.s[cfsTypeInit1], 'static TNimNode $1[$2];$n',
+         '$1 = private alloca [$2 x @TNimNode]$n', 
          [m.typeNodesName, toRope(m.typeNodes)]);
   end;
   if m.nimTypes > 0 then begin
     useMagic(m, 'TNimType');
-    appf(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n', 
+    appff(m.s[cfsTypeInit1], 'static TNimType $1[$2];$n', 
+         '$1 = private alloca [$2 x @TNimType]$n',
          [m.nimTypesName, toRope(m.nimTypes)]);
   end;
   if optStackTrace in m.initProc.options then begin
     getFrameDecl(m.initProc);
     app(prc, m.initProc.s[cpsLocals]);
     app(prc, m.s[cfsTypeInit1]);
-    appf(prc,
-      'F.len = 0;$n' + // IMPORTANT: else the debugger crashes!
-      'F.procname = $1;$n' +
-      'F.prev = framePtr;$n' +
-      'F.filename = $2;$n' +
-      'F.line = 0;$n' +
-      'framePtr = (TFrame*)&F;$n',
-      [makeCString('module ' + m.module.name.s),
-      makeCString(toFilename(m.module.info))])
+    
+    procname := CStringLit(m.initProc, prc, 'module ' +{&} m.module.name.s);
+    filename := CStringLit(m.initProc, prc, toFilename(m.module.info));
+    app(prc, initFrame(m.initProc, procname, filename));
   end
   else begin
     app(prc, m.initProc.s[cpsLocals]);
@@ -760,7 +989,7 @@ begin
   app(prc, m.initProc.s[cpsInit]);
   app(prc, m.initProc.s[cpsStmts]);
   if optStackTrace in m.initProc.options then
-    app(prc, 'framePtr = framePtr->prev;' + tnl);
+    app(prc, deinitFrame(m.initProc));
   app(prc, '}' +{&} tnl +{&} tnl);
   app(m.s[cfsProcs], prc)
 end;
@@ -817,7 +1046,8 @@ begin
   s := NewSym(skModule, getIdent(moduleName), nil);
   gmti := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
   addPendingModule(gmti);
-  appf(mainModProcs, 'N_NOINLINE(void, $1)(void);$n', [getInitName(s)]);
+  appff(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
+                      'declare void $1() noinline$n', [getInitName(s)]);
 end;
 
 function myOpen(module: PSym; const filename: string): PPassContext;
diff --git a/nim/commands.pas b/nim/commands.pas
index d87a8f084..8a4435eb0 100644
--- a/nim/commands.pas
+++ b/nim/commands.pas
@@ -77,14 +77,14 @@ const
 +{&} '  --debugger:on|off         turn Embedded Nimrod Debugger ON|OFF' +{&} nl
 +{&} '  -x, --checks:on|off       code generation for all runtime checks ON|OFF' +{&} nl
 +{&} '  --obj_checks:on|off       code generation for obj conversion checks ON|OFF' +{&} nl
-+{&} '  --field_checks:on|off     code generation for case record fields ON|OFF' +{&} nl
++{&} '  --field_checks:on|off     code generation for case variant fields ON|OFF' +{&} nl
 +{&} '  --range_checks:on|off     code generation for range checks ON|OFF' +{&} nl
 +{&} '  --bound_checks:on|off     code generation for bound checks ON|OFF' +{&} nl
 +{&} '  --overflow_checks:on|off  code generation for over-/underflow checks ON|OFF' +{&} nl
 +{&} '  -a, --assertions:on|off   code generation for assertions ON|OFF' +{&} nl
 +{&} '  --dead_code_elim:on|off   whole program dead code elimination ON|OFF' +{&} nl
 +{&} '  --opt:none|speed|size     optimize not at all or for speed|size' +{&} nl
-+{&} '  --app:console|gui|lib     generate a console|GUI application or a shared lib' +{&} nl
++{&} '  --app:console|gui         generate a console|GUI application' +{&} nl
 +{&} '  -r, --run                 run the compiled program with given arguments' +{&} nl
 +{&} '  --advanced                show advanced command line switches' +{&} nl
 +{&} '  -h, --help                show this help' +{&} nl
@@ -125,7 +125,6 @@ const
 +{&} '  --checkpoints:on|off      turn on|off checkpoints; for debugging Nimrod' +{&} nl
 +{&} '  --skip_cfg                do not read the general configuration file' +{&} nl
 +{&} '  --skip_proj_cfg           do not read the project''s configuration file' +{&} nl
-+{&} '  --import:MODULE_FILE      import the given module implicitly for each module' +{&} nl
 +{&} '  --index:FILE              use FILE to generate a documenation index file' +{&} nl
 +{&} '  --putenv:key=value        set an environment variable' +{&} nl
 +{&} '  --list_cmd                list the commands used to execute external programs' +{&} nl
@@ -506,7 +505,7 @@ begin
       expectArg(switch, arg, pass, info);
       gErrorMax := parseInt(arg);
     end;
-    else if findSubStr('.', switch) >= strStart then
+    else if strutils.find(switch, '.') >= strStart then
       options.setConfigVar(switch, arg)
     else
       InvalidCmdLineOption(pass, switch, info)
diff --git a/nim/debugids.pas b/nim/debugids.pas
deleted file mode 100644
index fff9ed10b..000000000
--- a/nim/debugids.pas
+++ /dev/null
@@ -1,129 +0,0 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-unit debugids;
-
-interface
-
-{$include 'config.inc'}
-
-uses
-  nsystem, nos, strutils, ast;
-
-const
-  idfile = 'debugids.txt';
-
-// This module implements debugging facilities for the ID mechanism.
-procedure registerID(s: PSym);
-
-procedure writeIDTable();
-procedure loadIDTable();
-
-implementation
-
-type
-  TIdSymTuple = record{@tuple} // keep id from sym to better detect bugs
-    id: int;
-    s: PSym;
-  end;
-  TIdSymTupleSeq = array of TIdSymTuple;
-  TIdSymTable = record
-    counter: int;
-    data: TIdSymTupleSeq;
-  end;
-
-function TableRawGet(const t: TTable; key: PObject): int;
-var
-  h: THash;
-begin
-  h := hashNode(key) and high(t.data); // start with real hash value
-  while t.data[h].key <> nil do begin
-    if (t.data[h].key = key) then begin
-      result := h; exit
-    end;
-    h := nextTry(h, high(t.data))
-  end;
-  result := -1
-end;
-
-function TableSearch(const t: TTable; key, closure: PObject;
-                     comparator: TCmpProc): PObject;
-var
-  h: THash;
-begin
-  h := hashNode(key) and high(t.data); // start with real hash value
-  while t.data[h].key <> nil do begin
-    if (t.data[h].key = key) then
-      if comparator(t.data[h].val, closure) then begin // BUGFIX 1
-        result := t.data[h].val; exit
-      end;
-    h := nextTry(h, high(t.data))
-  end;
-  result := nil
-end;
-
-function TableGet(const t: TTable; key: PObject): PObject;
-var
-  index: int;
-begin
-  index := TableRawGet(t, key);
-  if index >= 0 then result := t.data[index].val
-  else result := nil
-end;
-
-procedure TableRawInsert(var data: TPairSeq; key, val: PObject);
-var
-  h: THash;
-begin
-  h := HashNode(key) and high(data);
-  while data[h].key <> nil do begin
-    assert(data[h].key <> key);
-    h := nextTry(h, high(data))
-  end;
-  assert(data[h].key = nil);
-  data[h].key := key;
-  data[h].val := val;
-end;
-
-procedure TableEnlarge(var t: TTable);
-var
-  n: TPairSeq;
-  i: int;
-begin
-{@ignore}
-  n := emptySeq;
-  setLength(n, length(t.data) * growthFactor);
-  fillChar(n[0], length(n)*sizeof(n[0]), 0);
-{@emit
-  newSeq(n, length(t.data) * growthFactor); }
-  for i := 0 to high(t.data) do
-    if t.data[i].key <> nil then
-      TableRawInsert(n, t.data[i].key, t.data[i].val);
-{@ignore}
-  t.data := n;
-{@emit
-  swap(t.data, n);
-}
-end;
-
-procedure TablePut(var t: TTable; key, val: PObject);
-var
-  index: int;
-begin
-  index := TableRawGet(t, key);
-  if index >= 0 then
-    t.data[index].val := val
-  else begin
-    if mustRehash(length(t.data), t.counter) then TableEnlarge(t);
-    TableRawInsert(t.data, key, val);
-    inc(t.counter)
-  end;
-end;
-
-
-end.
diff --git a/nim/docgen.pas b/nim/docgen.pas
index bd4613180..15969f51d 100644
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -40,7 +40,7 @@ type
     modDesc: PRope;     // module description
     dependsOn: PRope;   // dependencies
     id: int;            // for generating IDs
-    splitAfter: int;    // split to long entries in the TOC
+    splitAfter: int;    // split too long entries in the TOC
     tocPart: array of TTocEntry;
     hasToc: bool;
     toc, section: TSections;
@@ -777,7 +777,7 @@ begin
     rnLineBlock: outer := '<p>$1</p>';
     rnLineBlockItem: outer := '$1<br />';
 
-    rnBlockQuote: outer := '<blockquote>$1</blockquote>$n';
+    rnBlockQuote: outer := '<blockquote><p>$1</p></blockquote>$n';
 
     rnTable, rnGridTable:
       outer := '<table border="1" class="docutils">$1</table>';
diff --git a/nim/extccomp.pas b/nim/extccomp.pas
index 51cf009d1..f51e5f690 100644
--- a/nim/extccomp.pas
+++ b/nim/extccomp.pas
@@ -352,13 +352,13 @@ end;
 
 procedure addCompileOption(const option: string);
 begin
-  if strutils.findSubStr(option, compileOptions, strStart) < strStart then
+  if strutils.find(compileOptions, option, strStart) < strStart then
     addOpt(compileOptions, option)
 end;
 
 procedure addLinkOption(const option: string);
 begin
-  if findSubStr(option, linkOptions, strStart) < strStart then
+  if find(linkOptions, option, strStart) < strStart then
     addOpt(linkOptions, option)
 end;
 
diff --git a/nim/idents.pas b/nim/idents.pas
index 44957ba7a..c0e4c994f 100644
--- a/nim/idents.pas
+++ b/nim/idents.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -38,8 +38,15 @@ function getIdent(identifier: cstring; len: int; h: THash): PIdent; overload;
   // special version for the scanner; the scanner's buffering scheme makes
   // this horribly efficient. Most of the time no character copying is needed!
 
+function IdentEq(id: PIdent; const name: string): bool;
+
 implementation
 
+function IdentEq(id: PIdent; const name: string): bool;
+begin
+  result := id.id = getIdent(name).id;
+end;
+
 var
   buckets: array [0..4096*2-1] of PIdent;
 
diff --git a/nim/llstream.pas b/nim/llstream.pas
index 2d4336664..df4c823a6 100644
--- a/nim/llstream.pas
+++ b/nim/llstream.pas
@@ -22,7 +22,7 @@ type
     llsFile,          // stream encapsulates a file
     llsStdIn);        // stream encapsulates stdin
   TLLStream = object(NObject)
-    kind: TLLStreamKind; // exposed for low-level access (lexbase uses this)
+    kind: TLLStreamKind; // accessible for low-level access (lexbase uses this)
     f: TBinaryFile;
     s: string;
     pos: int; // for string streams
diff --git a/nim/main.pas b/nim/main.pas
index 565373685..c888e5c3c 100644
--- a/nim/main.pas
+++ b/nim/main.pas
@@ -119,7 +119,7 @@ procedure CompileProject(const filename: string);
 begin
   {@discard} CompileModule(
     JoinPath(options.libpath, appendFileExt('system', nimExt)), false, true);
-  {@discard} CompileModule(filename, true, false);
+  {@discard} CompileModule(appendFileExt(filename, nimExt), true, false);
 end;
 
 procedure semanticPasses;
@@ -352,6 +352,11 @@ begin
       wantFile(filename);
       CommandCompileToEcmaScript(filename);
     end;
+    wCompileToLLVM: begin
+      gCmd := cmdCompileToLLVM;
+      wantFile(filename);
+      CommandCompileToC(filename);
+    end;
     wPretty: begin
       gCmd := cmdPretty;
       wantFile(filename);
diff --git a/nim/msgs.pas b/nim/msgs.pas
index a91c328ef..0eb1651d9 100644
--- a/nim/msgs.pas
+++ b/nim/msgs.pas
@@ -278,6 +278,7 @@ type
     errXRequiresOneArgument,
     errUnhandledExceptionX,
     errCyclicTree,
+    errXisNoMacroOrTemplate,
     errUser,
     warnCannotOpenFile,
     warnOctalEscape,
@@ -491,7 +492,7 @@ const
     '$1 here not allowed',
     'invalid control flow: $1',
     'a type has no value',
-    '''$1'' is no type',
+    'invalid type: ''$1''',
     '''^'' needs a pointer or reference type',
     'invalid context for builtin ''$1''',
     'invalid expression',
@@ -536,6 +537,7 @@ const
     'converter requires one parameter',
     'unhandled exception: $1',
     'macro returned a cyclic abstract syntax tree',
+    '''$1'' is no macro or template',
     '$1',
     'cannot open ''$1'' [CannotOpenFile]',
     'octal escape sequences do not exist; leading zero is ignored [OctalEscape]',
@@ -645,8 +647,8 @@ const // this format is understood by many text editors: it is the same that
 procedure MessageOut(const s: string);

 

 procedure rawMessage(const msg: TMsgKind; const arg: string = ''); overload;

-procedure rawMessage(const msg: TMsgKind; const args: array of string); overload;
-
+procedure rawMessage(const msg: TMsgKind; const args: array of string); overload;

+

 procedure liMessage(const info: TLineInfo; const msg: TMsgKind;

                     const arg: string = '');

 

@@ -840,37 +842,37 @@ begin
                              getMessageStr(errInstantiationFrom, '')]));

   end;

 end;

-
-procedure rawMessage(const msg: TMsgKind; const args: array of string);
-var
-  frmt: string;
-begin
-  case msg of
-    errMin..errMax: begin
-      writeContext();
-      frmt := rawErrorFormat;
-    end;
-    warnMin..warnMax: begin
-      if not (optWarns in gOptions) then exit;
-      if not (msg in gNotes) then exit;
-      frmt := rawWarningFormat;
-      inc(gWarnCounter);
-    end;
-    hintMin..hintMax: begin
-      if not (optHints in gOptions) then exit;
-      if not (msg in gNotes) then exit;
-      frmt := rawHintFormat;
-      inc(gHintCounter);
-    end;
-    else assert(false) // cannot happen
-  end;
-  MessageOut(Format(frmt, format(msgKindToString(msg), args)));
-  handleError(msg);
-end;
+

+procedure rawMessage(const msg: TMsgKind; const args: array of string);

+var

+  frmt: string;

+begin

+  case msg of

+    errMin..errMax: begin

+      writeContext();

+      frmt := rawErrorFormat;

+    end;

+    warnMin..warnMax: begin

+      if not (optWarns in gOptions) then exit;

+      if not (msg in gNotes) then exit;

+      frmt := rawWarningFormat;

+      inc(gWarnCounter);

+    end;

+    hintMin..hintMax: begin

+      if not (optHints in gOptions) then exit;

+      if not (msg in gNotes) then exit;

+      frmt := rawHintFormat;

+      inc(gHintCounter);

+    end;

+    else assert(false) // cannot happen

+  end;

+  MessageOut(Format(frmt, format(msgKindToString(msg), args)));

+  handleError(msg);

+end;

 

 procedure rawMessage(const msg: TMsgKind; const arg: string = '');

-begin
-  rawMessage(msg, [arg]);
+begin

+  rawMessage(msg, [arg]);

 end;

 

 procedure liMessage(const info: TLineInfo; const msg: TMsgKind;

diff --git a/nim/nimconf.pas b/nim/nimconf.pas
index 1a70abdbe..8f908bf62 100644
--- a/nim/nimconf.pas
+++ b/nim/nimconf.pas
@@ -9,9 +9,7 @@
 
 unit nimconf;
 
-// This module used to handle the reading of the config file. We now just
-// read environment variables. This is easier to avoid bootstraping issues.
-
+// This module handles the reading of the config file.
 {$include 'config.inc'}
 
 interface
@@ -258,7 +256,7 @@ begin
     addChar(s, '.');
     confTok(L, tok);
     checkSymbol(L, tok);
-    s := s +{&} tokToStr(tok);
+    add(s, tokToStr(tok));
     confTok(L, tok)
   end;
   if tok.tokType = tkBracketLe then begin
@@ -266,7 +264,7 @@ begin
     // BUGFIX: do not copy '['!
     confTok(L, tok);
     checkSymbol(L, tok);
-    val := val +{&} tokToStr(tok);
+    add(val, tokToStr(tok));
     confTok(L, tok);
     if tok.tokType = tkBracketRi then confTok(L, tok)
     else lexMessage(L, errTokenExpected, ''']''');
@@ -276,12 +274,12 @@ begin
     if length(val) > 0 then addChar(val, ':'); // BUGFIX
     confTok(L, tok); // skip ':' or '='
     checkSymbol(L, tok);
-    val := val +{&} tokToStr(tok);
+    add(val, tokToStr(tok));
     confTok(L, tok); // skip symbol
     while (tok.ident <> nil) and (tok.ident.id = getIdent('&'+'').id) do begin
       confTok(L, tok);
       checkSymbol(L, tok);
-      val := val +{&} tokToStr(tok);
+      add(val, tokToStr(tok));
       confTok(L, tok)
     end
   end;
diff --git a/nim/nimrod.pas b/nim/nimrod.pas
index 99d9a9d0f..728325ccc 100644
--- a/nim/nimrod.pas
+++ b/nim/nimrod.pas
@@ -61,7 +61,7 @@ type
 
 procedure HandleCmdLine;
 var
-  command, filename: string;
+  command, filename, prog: string;
   start: TTime;
 begin
   {@emit start := getTime(); }
@@ -92,13 +92,21 @@ begin
                                 toString(getTime() - start)]);
     }
     end;
-    if optRun in gGlobalOptions then
-      execExternalProgram(quoteIfContainsWhite(changeFileExt(filename, '')) +{&}
-                         ' ' +{&} arguments)
+    if optRun in gGlobalOptions then begin
+      {$ifdef unix}
+      prog := './' + quoteIfContainsWhite(changeFileExt(filename, ''));
+      {$else}
+      prog := quoteIfContainsWhite(changeFileExt(filename, ''));
+      {$endif}
+      execExternalProgram(prog +{&} ' ' +{&} arguments)
+    end
   end
 end;
 
 begin
+//{@emit
+//  GC_disableMarkAndSweep();
+//}
   cmdLineInfo := newLineInfo('command line', -1, -1);
   condsyms.InitDefines();
   HandleCmdLine();
diff --git a/nim/nos.pas b/nim/nos.pas
index 73b17ae58..4926c99b0 100644
--- a/nim/nos.pas
+++ b/nim/nos.pas
@@ -123,7 +123,7 @@ procedure createDir(const dir: string);
 var
   i: int;
 begin
-  for i := 1 to length(dir) do begin
+  for i := 2 to length(dir) do begin
     if dir[i] in [sep, altsep] then sysutils.createDir(ncopy(dir, 1, i-1));
   end;
   sysutils.createDir(dir);
diff --git a/nim/nsystem.pas b/nim/nsystem.pas
index f476e09ca..51ca05605 100644
--- a/nim/nsystem.pas
+++ b/nim/nsystem.pas
@@ -43,6 +43,7 @@ type
 {$endif}
   EOutOfRange = class(Exception)
   end;
+  EOS = class(Exception) end;
 
   float32 = single;
   float64 = double;
diff --git a/nim/nversion.pas b/nim/nversion.pas
index 7d179bb35..de0ad2b79 100644
--- a/nim/nversion.pas
+++ b/nim/nversion.pas
@@ -31,10 +31,10 @@ const
   //cog.outl('VersionMinor = %s;' % ver[1])
   //cog.outl('VersionPatch = %s;' % ver[2])
   //]]]
-  VersionAsString = '0.7.4';
+  VersionAsString = '0.7.6';
   VersionMajor = 0;
   VersionMinor = 7;
-  VersionPatch = 4;
+  VersionPatch = 6;
   //[[[[end]]]]
 
 implementation
diff --git a/nim/options.pas b/nim/options.pas
index 5bbfbbbee..d6f6d14da 100644
--- a/nim/options.pas
+++ b/nim/options.pas
@@ -55,6 +55,7 @@ type
     cmdCompileToC,
     cmdCompileToCpp,
     cmdCompileToEcmaScript,
+    cmdCompileToLLVM,
     cmdInterpret,
     cmdPretty,
     cmdDoc,
@@ -207,7 +208,15 @@ begin
   if startsWith(dir, prefix) then begin
     result := ncopy(dir, length(prefix) + strStart); exit
   end;
-  result := dir
+  result := dir;
+end;
+
+function removeTrailingDirSep(const path: string): string;
+begin
+  if (length(path) > 0) and (path[length(path)+strStart-1] = dirSep) then
+    result := ncopy(path, strStart, length(path)+strStart-2)
+  else
+    result := path
 end;
 
 function toGeneratedFile(const path, ext: string): string;
@@ -215,7 +224,8 @@ var
   head, tail: string;
 begin
   splitPath(path, head, tail);
-  result := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep), 
+  if length(head) > 0 then head := shortenDir(head +{&} dirSep);
+  result := joinPath([projectPath, genSubDir, head, 
                       changeFileExt(tail, ext)])
 end;
 
@@ -225,10 +235,18 @@ var
   head, tail, subdir: string;
 begin
   splitPath(f, head, tail);
-  subdir := joinPath([projectPath, genSubDir, shortenDir(head +{&} dirSep)]);
+  if length(head) > 0 then
+    head := removeTrailingDirSep(shortenDir(head +{&} dirSep));
+  subdir := joinPath([projectPath, genSubDir, head]);
   if createSubDir then begin
-    //Writeln(output, subdir);
-    createDir(subdir);
+    try
+      createDir(subdir);
+    except
+      on EOS do begin
+        writeln(output, 'cannot create directory: ' + subdir);
+        halt(1)
+      end
+    end
   end;
   result := joinPath(subdir, tail)
 end;
diff --git a/nim/parsecfg.pas b/nim/parsecfg.pas
index a99da6852..3c10cc8fc 100644
--- a/nim/parsecfg.pas
+++ b/nim/parsecfg.pas
@@ -350,7 +350,7 @@ begin
       addChar(result.key, '.');
       rawGetTok(c, c.tok);
       if c.tok.kind = tkSymbol then begin
-        result.key := result.key +{&} c.tok.literal;
+        add(result.key, c.tok.literal);
         rawGetTok(c, c.tok);
       end
       else begin
diff --git a/nim/passes.pas b/nim/passes.pas
index 028cfc2a2..f5dff3559 100644
--- a/nim/passes.pas
+++ b/nim/passes.pas
@@ -57,7 +57,7 @@ function astNeeded(s: PSym): bool;
   // appropriate to free the procedure body's memory. This is important
   // to keep memory usage down.
 
-// some passes (the semantic checker) need these:
+// the semantic checker needs these:
 var
   gImportModule: function (const filename: string): PSym;
   gIncludeFile: function (const filename: string): PNode;
diff --git a/nim/platform.pas b/nim/platform.pas
index 8bf4f3d9b..9f8d30f60 100644
--- a/nim/platform.pas
+++ b/nim/platform.pas
@@ -12,7 +12,7 @@ unit platform;
 // and operating systems.
 // Note: Unfortunately if an OS or CPU is listed here this does not mean that
 // Nimrod has been tested on this platform or that the RTL has been ported.
-// Feel free to test for your exentric platform!
+// Feel free to test for your excentric platform!
 
 interface
 
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index 636a1198a..9a60e6bd3 100644
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -228,7 +228,7 @@ procedure processDynLib(c: PContext; n: PNode; sym: PSym);
 var
   lib: PLib;
 begin
-  if sym = nil then
+  if (sym = nil) or (sym.kind = skModule) then
     POptionEntry(c.optionStack.tail).dynlib := getLib(c, libDynamic,
                                                       expectStrLit(c, n))
   else begin
@@ -553,13 +553,6 @@ begin
           wPassL: extccomp.addLinkOption(expectStrLit(c, it));
           wPassC: extccomp.addCompileOption(expectStrLit(c, it));
 
-          // fixupSystem not even documented:
-          wFixupSystem: begin
-            if c.module = magicSys.SystemModule then
-              magicsys.FinishSystem(magicsys.SystemModule.tab)
-            else
-              invalidPragma(it)
-          end;
           wBreakpoint: PragmaBreakpoint(c, it);
           wCheckpoint: PragmaCheckpoint(c, it);
 
@@ -585,7 +578,7 @@ begin
       processNote(c, n)
     end;
   end;
-  if sym <> nil then begin
+  if (sym <> nil) and (sym.kind <> skModule) then begin
     lib := POptionEntry(c.optionstack.tail).dynlib;
     if ([lfDynamicLib, lfHeader] * sym.loc.flags = []) and
          (sfImportc in sym.flags) and
@@ -625,7 +618,7 @@ begin
       wHints, wLinedir, wStacktrace, wLinetrace, wOptimization,
       wHint, wWarning, wError, wFatal, wDefine, wUndef,
       wCompile, wLink, wLinkSys, wPure,
-      wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint,
+      wPush, wPop, wBreakpoint, wCheckpoint,
       wPassL, wPassC, wDeadCodeElim]);
 end;
 
diff --git a/nim/rodread.pas b/nim/rodread.pas
index 549cfec58..a34153ccf 100644
--- a/nim/rodread.pas
+++ b/nim/rodread.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -123,7 +123,7 @@ type
     files: TStringSeq;
     dataIdx: int;       // offset of start of data section
     convertersIdx: int; // offset of start of converters section
-    initIdx, interfIdx, compilerProcsIdx: int;
+    initIdx, interfIdx, compilerProcsIdx, cgenIdx: int;
     filename: string;
     index, imports: TIndex;
     readerIndex: int;
@@ -841,6 +841,10 @@ begin
       r.initIdx := r.pos+2; // "(\10"
       skipSection(r);
     end
+    else if section = 'CGEN' then begin
+      r.cgenIdx := r.pos+2;
+      skipSection(r);
+    end
     else begin
       MessageOut('skipping section: ' + toString(r.pos));
       skipSection(r);
diff --git a/nim/rodwrite.pas b/nim/rodwrite.pas
index 637f69ff7..72d5c893d 100644
--- a/nim/rodwrite.pas
+++ b/nim/rodwrite.pas
@@ -530,6 +530,7 @@ begin
     nkVarSection: begin
       for i := 0 to sonsLen(n)-1 do begin
         a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
         if a.kind <> nkIdentDefs then InternalError(a.info, 'rodwrite.process');
         addInterfaceSym(w, a.sons[0].sym);
       end
@@ -537,6 +538,7 @@ begin
     nkConstSection: begin
       for i := 0 to sonsLen(n)-1 do begin
         a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
         if a.kind <> nkConstDef then InternalError(a.info, 'rodwrite.process');
         addInterfaceSym(w, a.sons[0].sym);
       end
@@ -544,6 +546,7 @@ begin
     nkTypeSection: begin
       for i := 0 to sonsLen(n)-1 do begin
         a := n.sons[i];
+        if a.kind = nkCommentStmt then continue;
         if a.sons[0].kind <> nkSym then
           InternalError(a.info, 'rodwrite.process');
         s := a.sons[0].sym;
diff --git a/nim/ropes.pas b/nim/ropes.pas
index a6ba2a11b..864afd5b8 100644
--- a/nim/ropes.pas
+++ b/nim/ropes.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -112,8 +112,6 @@ function ropef(const frmt: TFormatStr; const args: array of PRope): PRope;
 procedure appf(var c: PRope; const frmt: TFormatStr;
   const args: array of PRope);
 
-procedure RopeSeqInsert(var rs: TRopeSeq; r: PRope; at: Natural);
-
 function getCacheStats: string;
 
 function RopeEqualsFile(r: PRope; const f: string): Boolean;
@@ -524,8 +522,7 @@ begin
   assert(RopeInvariant(result));
 end;
 
-procedure appf(var c: PRope; const frmt: TFormatStr;
-  const args: array of PRope);
+procedure appf(var c: PRope; const frmt: TFormatStr; const args: array of PRope);
 begin
   app(c, ropef(frmt, args))
 end;
diff --git a/nim/rst.pas b/nim/rst.pas
index 55c2c933a..0c5377646 100644
--- a/nim/rst.pas
+++ b/nim/rst.pas
@@ -1967,6 +1967,10 @@ begin
       initParser(q, p.s);
       q.filename := filename;
       getTokens(readFile(path), false, q.tok);
+      // workaround a GCC bug: 
+      if find(q.tok[high(q.tok)].symbol, #0#1#2) > 0 then begin
+        InternalError('Too many binary zeros in include file');
+      end;
       result := parseDoc(q);
     end
   end
diff --git a/nim/scanner.pas b/nim/scanner.pas
index a78f9c6ce..d035b973b 100644
--- a/nim/scanner.pas
+++ b/nim/scanner.pas
@@ -428,7 +428,7 @@ begin
     L.bufpos := pos; // restore position
 
   try
-    if (L.buf[pos] = '0') and (L.buf[pos+1] in ['x','X','b','B','o','O'])
+    if (L.buf[pos] = '0') and (L.buf[pos+1] in ['x','X','b','B','o','O','c','C'])
     then begin
       inc(pos, 2);
       xi := 0;
@@ -451,7 +451,7 @@ begin
             end
           end
         end;
-        'o': begin
+        'o', 'c', 'C': begin
           result.base := base8;
           while true do begin
             case L.buf[pos] of
diff --git a/nim/sem.pas b/nim/sem.pas
index 6d97da3e8..3494754fd 100644
--- a/nim/sem.pas
+++ b/nim/sem.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -183,7 +183,7 @@ begin
   c := newContext(module, filename);
   if (c.p <> nil) then InternalError(module.info, 'sem.myOpen');
   c.semConstExpr := semConstExpr;
-  c.p := newProcCon(nil);
+  c.p := newProcCon(module);
   pushOwner(c.module);
   openScope(c.tab); // scope for imported symbols
   SymTabAdd(c.tab, module); // a module knows itself
diff --git a/nim/semdata.pas b/nim/semdata.pas
index 9ffd41eac..3393ed4b3 100644
--- a/nim/semdata.pas
+++ b/nim/semdata.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -128,6 +128,7 @@ end;
 
 function newProcCon(owner: PSym): PProcCon;
 begin
+  if owner = nil then InternalError('owner is nil');
   new(result);
 {@ignore}
   fillChar(result^, sizeof(result^), 0);
diff --git a/nim/semexprs.pas b/nim/semexprs.pas
index 3e95e3457..59d7f969a 100644
--- a/nim/semexprs.pas
+++ b/nim/semexprs.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Ethexor Morpork Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -87,19 +87,23 @@ begin
   end
 end;
 
-function isCastable(castDest, src: PType): Boolean;
+function isCastable(dst, src: PType): Boolean;
+//const
+//  castableTypeKinds = {@set}[tyInt, tyPtr, tyRef, tyCstring, tyString, 
+//                             tySequence, tyPointer, tyNil, tyOpenArray,
+//                             tyProc, tySet, tyEnum, tyBool, tyChar];
 var
   ds, ss: biggestInt;
 begin
   // this is very unrestrictive; cast is allowed if castDest.size >= src.size
-  ds := computeSize(castDest);
+  ds := computeSize(dst);
   ss := computeSize(src);
   if ds < 0 then result := false
   else if ss < 0 then result := false
-  else
+  else 
     result := (ds >= ss) or
-      (castDest.kind in [tyInt..tyFloat128]) or
-      (src.kind in [tyInt..tyFloat128])
+      (skipGeneric(dst).kind in [tyInt..tyFloat128]) or
+      (skipGeneric(src).kind in [tyInt..tyFloat128])
 end;
 
 function semConv(c: PContext; n: PNode; s: PSym): PNode;
@@ -620,6 +624,11 @@ begin
   end;
 end;
 
+procedure checkDeprecated(n: PNode; s: PSym);
+begin
+  if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);  
+end;
+
 function semSym(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
 begin
   result := newSymNode(s);
@@ -652,7 +661,8 @@ begin
       end
     end
     else begin end
-  end
+  end;
+  checkDeprecated(n, s);
 end;
 
 function isTypeExpr(n: PNode): bool;
@@ -787,6 +797,7 @@ begin
       result := newSymNode(f);
       result.info := n.info;
       result.typ := ty;
+      checkDeprecated(n, f);
     end
     else
       liMessage(n.sons[1].info, errEnumHasNoValueX, i.s);
@@ -814,6 +825,7 @@ begin
         n.sons[0] := makeDeref(n.sons[0]);
         n.sons[1] := newSymNode(f); // we now have the correct field
         n.typ := f.typ;
+        checkDeprecated(n, f);
         if check = nil then result := n
         else begin
           check.sons[0] := n;
@@ -831,14 +843,17 @@ begin
       n.sons[1] := newSymNode(f);
       n.typ := f.typ;
       result := n;
+      checkDeprecated(n, f);
       exit
     end
   end;
   // allow things like "".replace(...)
   // --> replace("", ...)
   f := SymTabGet(c.tab, i);
-  if (f <> nil) and (f.kind = skStub) then loadStub(f);
-  if (f <> nil) and (f.kind in [skProc, skIterator]) then begin
+  //if (f <> nil) and (f.kind = skStub) then loadStub(f);
+  // XXX ``loadStub`` is not correct here as we don't care for ``f`` really
+  if (f <> nil) then begin
+    // BUGFIX: do not check for (f.kind in [skProc, skIterator]) here
     result := newNodeI(nkDotCall, n.info);
     // This special node kind is to merge with the call handler in `semExpr`.
     addSon(result, newIdentNode(i, n.info));
@@ -1121,6 +1136,57 @@ begin
     result := semFieldAccess(c, n, flags);
 end;
 
+function isCallExpr(n: PNode): bool;
+begin
+  result := n.kind in [nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand];
+end;
+
+function semMacroStmt(c: PContext; n: PNode): PNode;
+var
+  s: PSym;
+  a: PNode;
+  i: int;
+begin
+  checkMinSonsLen(n, 2);
+  if isCallExpr(n.sons[0]) then
+    a := n.sons[0].sons[0]
+  else
+    a := n.sons[0];
+  s := qualifiedLookup(c, a, false);
+  if (s <> nil) then begin
+    checkDeprecated(n, s);
+    case s.kind of
+      skMacro: begin
+        include(s.flags, sfUsed);
+        result := semMacroExpr(c, n, s);
+      end;
+      skTemplate: begin
+        include(s.flags, sfUsed);
+        // transform
+        // nkMacroStmt(nkCall(a...), stmt, b...)
+        // to
+        // nkCall(a..., stmt, b...)
+        result := newNodeI(nkCall, n.info);
+        addSon(result, a);
+        if isCallExpr(n.sons[0]) then begin
+          for i := 1 to sonsLen(n.sons[0])-1 do
+            addSon(result, n.sons[0].sons[i]);
+        end;
+        for i := 1 to sonsLen(n)-1 do
+          addSon(result, n.sons[i]);
+        pushInfoContext(n.info);
+        result := evalTemplate(c, result, s);
+        popInfoContext();
+      end;
+      else
+        liMessage(n.info, errXisNoMacroOrTemplate, s.name.s);
+    end
+  end
+  else
+    liMessage(n.info, errInvalidExpressionX,
+              renderTree(a, {@set}[renderNoComments]));
+end;
+
 function semExpr(c: PContext; n: PNode; flags: TExprFlags = {@set}[]): PNode;
 var
   s: PSym;
@@ -1174,6 +1240,7 @@ begin
       checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
       if (s <> nil) then begin
+        checkDeprecated(n, s);
         case s.kind of
           skMacro: begin
             include(s.flags, sfUsed);
@@ -1200,6 +1267,9 @@ begin
       end
       else result := semIndirectOp(c, n);
     end;
+    nkMacroStmt: begin
+      result := semMacroStmt(c, n);
+    end;
     nkBracketExpr: begin
       checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
@@ -1221,7 +1291,7 @@ begin
     nkPar: begin
       case checkPar(n) of
         paNone: result := nil;
-        paTuplePositions:  result := semTuplePositionsConstr(c, n);
+        paTuplePositions: result := semTuplePositionsConstr(c, n);
         paTupleFields: result := semTupleFieldsConstr(c, n);
         paSingle: result := semExpr(c, n.sons[0]);
       end;
diff --git a/nim/semfold.pas b/nim/semfold.pas
index 422ddbd01..781c3b97d 100644
--- a/nim/semfold.pas
+++ b/nim/semfold.pas
@@ -406,6 +406,8 @@ begin
           else            result := copyTree(s.ast); // BUGFIX
         end
       end
+      else if s.kind = skProc then // BUGFIX
+        result := n
     end;
     nkCharLit..nkNilLit: result := copyNode(n);
     nkIfExpr: result := getConstIfExpr(module, n);
diff --git a/nim/seminst.pas b/nim/seminst.pas
index 4c3d416d4..a49d8478e 100644
--- a/nim/seminst.pas
+++ b/nim/seminst.pas
@@ -58,10 +58,29 @@ begin
   end
 end;
 
+procedure genericToConcreteTypeKind(t: PType);
+var
+  body: PNode;
+begin
+  if (t.kind = tyGeneric) and (t.sym <> nil) then begin
+    body := t.sym.ast.sons[2];
+    case body.kind of
+      nkObjectTy: t.kind := tyObject;
+      nkTupleTy: t.kind := tyTuple;
+      nkRefTy: t.kind := tyRef;
+      nkPtrTy: t.kind := tyPtr;
+      nkVarTy: t.kind := tyVar;
+      nkProcTy: t.kind := tyProc;
+      else InternalError('genericToConcreteTypeKind');
+    end
+  end
+end;
+
 function instantiateType(c: PInstantiateClosure; typ: PType): PType;
 var
   i: int;
 begin
+  if typ = nil then begin result := nil; exit end;
   result := PType(idTableGet(c.typeMap, typ));
   if result <> nil then exit;
   //if typ.kind = tyOpenArray then
@@ -73,6 +92,7 @@ begin
       result.sons[i] := instantiateType(c, result.sons[i]);
     if result.n <> nil then
       result.n := instTypeNode(c, result.n);
+    genericToConcreteTypeKind(result);
   end
   else
     result := typ;
@@ -272,6 +292,20 @@ begin
   result := instantiateType(c, t);
 end;
 
+function newInstantiateClosure(p: PContext;
+          const instantiator: TLineInfo): PInstantiateClosure;
+begin
+  new(result);
+{@ignore}
+  fillChar(result^, sizeof(result^), 0);
+{@emit}
+  InitIdTable(result.typeMap);
+  InitIdTable(result.symMap);
+  result.fn := nil;
+  result.instantiator := instantiator;
+  result.module := p.module;
+end;
+
 function partialSpecialization(c: PContext; n: PNode; s: PSym): PNode;
 begin
   result := n;
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index 098b95072..ebf14693c 100644
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -42,7 +42,7 @@ begin
   end;
   if result = nil then result := newNodeI(nkNilLit, n.info);
   // The ``when`` statement implements the mechanism for platform dependant
-  // code. Thus we try to ensure here consistent ID distribution after the
+  // code. Thus we try to ensure here consistent ID allocation after the
   // ``when`` statement.
   IDsynchronizationPoint(200);
 end;
@@ -59,9 +59,11 @@ begin
     case it.kind of
       nkElifBranch: begin
         checkSonsLen(it, 2);
+        openScope(c.tab);
         it.sons[0] := semExprWithType(c, it.sons[0]);
         checkBool(it.sons[0]);
-        it.sons[1] := semStmtScope(c, it.sons[1])
+        it.sons[1] := semStmt(c, it.sons[1]);
+        closeScope(c.tab);
       end;
       nkElse: begin
         if sonsLen(it) = 1 then it.sons[0] := semStmtScope(c, it.sons[0])
@@ -144,7 +146,7 @@ begin
       // now parse the string literal and substitute symbols:
       a := strStart;
       repeat
-        b := findSubStr(marker, str, a);
+        b := strutils.find(str, marker, a);
         if b < strStart then
           sub := ncopy(str, a)
         else
@@ -153,7 +155,7 @@ begin
           addSon(result, newStrNode(nkStrLit, sub));
 
         if b < strStart then break;
-        c := findSubStr(marker, str, b+1);
+        c := strutils.find(str, marker, b+1);
         if c < strStart then
           sub := ncopy(str, b+1)
         else
@@ -179,11 +181,13 @@ function semWhile(c: PContext; n: PNode): PNode;
 begin
   result := n;
   checkSonsLen(n, 2);
+  openScope(c.tab);
   n.sons[0] := semExprWithType(c, n.sons[0]);
   CheckBool(n.sons[0]);
   inc(c.p.nestedLoopCounter);
-  n.sons[1] := semStmtScope(c, n.sons[1]);
+  n.sons[1] := semStmt(c, n.sons[1]);
   dec(c.p.nestedLoopCounter);
+  closeScope(c.tab);
 end;
 
 function semCase(c: PContext; n: PNode): PNode;
@@ -197,6 +201,7 @@ begin
   // check selector:
   result := n;
   checkMinSonsLen(n, 2);
+  openScope(c.tab);
   n.sons[0] := semExprWithType(c, n.sons[0]);
   chckCovered := false;
   covered := 0;
@@ -216,7 +221,7 @@ begin
       end;
       nkElifBranch: begin
         chckCovered := false;
-        checkSonsLen(n, 2);
+        checkSonsLen(x, 2);
         x.sons[0] := semExprWithType(c, x.sons[0]);
         checkBool(x.sons[0]);
         x.sons[1] := semStmtScope(c, x.sons[1])
@@ -231,6 +236,7 @@ begin
   end;
   if chckCovered and (covered <> lengthOrd(n.sons[0].typ)) then
     liMessage(n.info, errNotAllCasesCovered);
+  closeScope(c.tab);
 end;
 
 function semAsgn(c: PContext; n: PNode): PNode;
@@ -388,7 +394,7 @@ begin
     if (a.kind <> nkIdentDefs) and (a.kind <> nkVarTuple) then IllFormedAst(a);
     checkMinSonsLen(a, 3);
     len := sonsLen(a);
-    if a.sons[len-2] <> nil then
+    if a.sons[len-2] <> nil then 
       typ := semTypeNode(c, a.sons[len-2], nil)
     else
       typ := nil;
@@ -401,6 +407,8 @@ begin
     end
     else
       def := nil;
+    if not typeAllowed(typ, skVar) then
+      liMessage(a.info, errXisNoType, typeToString(typ));
     tup := skipGeneric(typ);
     if a.kind = nkVarTuple then begin
       if tup.kind <> tyTuple then liMessage(a.info, errXExpected, 'tuple');
@@ -408,7 +416,7 @@ begin
         liMessage(a.info, errWrongNumberOfVariables);
     end;
     for j := 0 to len-3 do begin
-      if c.p.owner = nil then begin
+      if (c.p.owner.kind = skModule) then begin
         v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]);
         include(v.flags, sfGlobal);
       end
@@ -441,7 +449,7 @@ begin
     if a.kind = nkCommentStmt then continue;
     if (a.kind <> nkConstDef) then IllFormedAst(a);
     checkSonsLen(a, 3);
-    if (c.p.owner = nil) then begin
+    if (c.p.owner.kind = skModule) then begin
       v := semIdentWithPragma(c, skConst, a.sons[0], {@set}[sfStar, sfMinus]);
       include(v.flags, sfGlobal);
     end
@@ -456,6 +464,8 @@ begin
       def := fitRemoveHiddenConv(c, typ, def);
     end
     else typ := def.typ;
+    if not typeAllowed(typ, skConst) then
+      liMessage(a.info, errXisNoType, typeToString(typ));
 
     v.typ := typ;
     v.ast := def; // no need to copy
@@ -480,6 +490,7 @@ begin
   result := n;
   checkMinSonsLen(n, 3);
   len := sonsLen(n);
+  openScope(c.tab);
   if n.sons[len-2].kind = nkRange then begin
     checkSonsLen(n.sons[len-2], 2);
     // convert ``in 3..5`` to ``in countup(3, 5)``
@@ -500,7 +511,6 @@ begin
   end;
   n.sons[len-2] := semExprWithType(c, n.sons[len-2]);
   iter := skipGeneric(n.sons[len-2].typ);
-  openScope(c.tab);
   if iter.kind <> tyTuple then begin
     if len <> 3 then liMessage(n.info, errWrongNumberOfVariables);
     v := newSymS(skForVar, n.sons[0], c);
@@ -573,7 +583,7 @@ begin
   end;
 end;
 
-procedure semGenericParamList(c: PContext; n: PNode);
+procedure semGenericParamList(c: PContext; n: PNode; father: PType = nil);
 var
   i: int;
   s: PSym;
@@ -590,6 +600,7 @@ begin
       s.typ := newTypeS(tyGenericParam, c);
       s.typ.sym := s;
     end;
+    if father <> nil then addSon(father, s.typ);
     s.position := i;
     n.sons[i] := newSymNode(s);
     addDecl(c, s);
@@ -631,7 +642,7 @@ begin
     if a.kind = nkCommentStmt then continue;
     if (a.kind <> nkTypeDef) then IllFormedAst(a);
     checkSonsLen(a, 3);
-    if (c.p.owner = nil) then begin
+    if (c.p.owner.kind = skModule) then begin
       s := semIdentWithPragma(c, skType, a.sons[0], {@set}[sfStar, sfMinus]);
       include(s.flags, sfGlobal);
     end
@@ -665,7 +676,8 @@ begin
       openScope(c.tab);
       pushOwner(s);
       s.typ.kind := tyGeneric;
-      semGenericParamList(c, a.sons[1]);
+      semGenericParamList(c, a.sons[1], s.typ);
+      addSon(s.typ, nil);
       // process the type body for symbol lookup of generic params
       // we can use the same algorithm as for template parameters:
       a.sons[2] := resolveTemplateParams(c, a.sons[2]);
@@ -736,7 +748,7 @@ var
 begin
   result := n;
   checkSonsLen(n, codePos+1);
-  if c.p.owner <> nil then
+  if c.p.owner.kind <> skModule then
     liMessage(n.info, errIteratorNotAllowed);
   oldP := c.p; // restore later
   s := semIdentVis(c, skIterator, n.sons[0], {@set}[sfStar]);
@@ -857,7 +869,7 @@ var
 begin
   result := n;
   checkSonsLen(n, codePos+1);
-  if c.p.owner = nil then begin
+  if c.p.owner.kind = skModule then begin
     s := semIdentVis(c, kind, n.sons[0], {@set}[sfStar]);
     include(s.flags, sfGlobal);
   end
@@ -885,7 +897,7 @@ begin
   proto := SearchForProc(c, s, c.tab.tos-2); // -2 because we have a scope open
                                              // for parameters
   if proto = nil then begin
-    if oldP.owner <> nil then // we are in a nested proc
+    if oldP.owner.kind <> skModule then // we are in a nested proc
       s.typ.callConv := ccClosure
     else
       s.typ.callConv := lastOptionEntry(c).defaultCC;
@@ -1025,7 +1037,7 @@ begin
   if nfSem in n.flags then exit;
   case n.kind of
     nkAsgn: result := semAsgn(c, n);
-    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand:
+    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkMacroStmt:
       result := semCommand(c, n);
     nkEmpty, nkCommentStmt, nkNilLit: begin end;
     nkBlockStmt: result := semBlock(c, n);
@@ -1051,8 +1063,7 @@ begin
     nkDiscardStmt: result := semDiscard(c, n);
     nkWhileStmt: result := semWhile(c, n);
     nkTryStmt: result := semTry(c, n);
-    nkBreakStmt, nkContinueStmt:
-      result := semBreakOrContinue(c, n);
+    nkBreakStmt, nkContinueStmt: result := semBreakOrContinue(c, n);
     nkForStmt: result := semFor(c, n);
     nkCaseStmt: result := semCase(c, n);
     nkReturnStmt: result := semReturn(c, n);
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index c07a7bd13..ebc5e1ebb 100644
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -164,7 +164,7 @@ var
   i, j, len, counter: int;
   params, p, paramKind: PNode;
 begin
-  if c.p.owner = nil then begin
+  if c.p.owner.kind = skModule then begin
     s := semIdentVis(c, skTemplate, n.sons[0], {@set}[sfStar]);
     include(s.flags, sfGlobal);
   end
diff --git a/nim/semtypes.pas b/nim/semtypes.pas
index 37958c4d0..014ff0216 100644
--- a/nim/semtypes.pas
+++ b/nim/semtypes.pas
@@ -51,10 +51,12 @@ begin
         e := newSymS(skEnumField, n.sons[i].sons[0], c);
         v := semConstExpr(c, n.sons[i].sons[1]);
         x := getOrdValue(v);
-        if (x <> counter) and (i <> 1) then
-          include(result.flags, tfEnumHasWholes);
-        if x < counter then
-          liMessage(n.sons[i].info, errInvalidOrderInEnumX, e.name.s);
+        if i <> 1 then begin
+          if (x <> counter) then
+            include(result.flags, tfEnumHasWholes);
+          if x < counter then
+            liMessage(n.sons[i].info, errInvalidOrderInEnumX, e.name.s);
+        end;
         counter := x;
       end;
       nkSym: e := n.sons[i].sym;
@@ -247,7 +249,7 @@ begin
     end
   end
 end;
-
+(*
 function instGenericAux(c: PContext; templ, actual: PNode;
                         sym: PSym): PNode;
 var
@@ -271,34 +273,48 @@ begin
         result.sons[i] := instGenericAux(c, templ.sons[i], actual, sym);
     end
   end
-end;
+end; *)
 
 function semGeneric(c: PContext; n: PNode; s: PSym; prev: PType): PType;
 var
   i: int;
   elem: PType;
   inst: PNode;
+  cl: PInstantiateClosure;
 begin
   if (s.typ = nil) or (s.typ.kind <> tyGeneric) then
     liMessage(n.info, errCannotInstantiateX, s.name.s);
   result := newOrPrevType(tyGenericInst, prev, c); // new ID...
   result.containerID := s.typ.containerID; // ... but the same containerID
   result.sym := s;
-  if (s.typ.containerID = 0) then
-    InternalError(n.info, 'semtypes.semGeneric');  
+  if (s.typ.containerID = 0) then InternalError(n.info, 'semtypes.semGeneric');
+  cl := newInstantiateClosure(c, n.info);
+  // check the number of supplied arguments suffices:
+  if sonsLen(n) <> sonsLen(s.typ) then begin
+    //MessageOut('n: ' +{&} toString(sonsLen(n)) +{&} ' s: '
+    //           +{&} toString(sonsLen(s.typ)));
+    liMessage(n.info, errWrongNumberOfTypeParams);
+  end;
+  // a generic type should be instantiated with itself:
+  // idTablePut(cl.typeMap, s.typ, result);
+  // iterate over arguments:
   for i := 1 to sonsLen(n)-1 do begin
     elem := semTypeNode(c, n.sons[i], nil);
     if elem.kind = tyGenericParam then 
-      result.kind := tyGeneric; // prevend type from instantiation
+      result.kind := tyGeneric // prevend type from instantiation
+    else
+      idTablePut(cl.typeMap, s.typ.sons[i-1], elem);
     addSon(result, elem);
   end;
   if s.ast <> nil then begin
     if (result.kind = tyGenericInst) then begin
-      inst := instGenericAux(c, s.ast.sons[2], n, s);
+      // inst := instGenericAux(c, s.ast.sons[2], n, s);
       internalError(n.info, 'Generic containers not implemented');
       // XXX: implementation does not work this way
+      // we need to do the following: 
+      // traverse and copy the type and replace any tyGenericParam type
       // does checking of instantiated type for us:
-      elem := semTypeNode(c, inst, nil);
+      elem := instantiateType(cl, s.typ); //semTypeNode(c, inst, nil);
       elem.id := result.containerID;
       addSon(result, elem);
     end
diff --git a/nim/sigmatch.pas b/nim/sigmatch.pas
index 289a17673..ebcbb2529 100644
--- a/nim/sigmatch.pas
+++ b/nim/sigmatch.pas
@@ -80,7 +80,7 @@ var
 begin
   result := msgKindToString(errTypeMismatch);
   for i := 1 to sonsLen(n)-1 do begin
-    debug(n.sons[i].typ);
+    //debug(n.sons[i].typ);
     add(result, typeToString(n.sons[i].typ));
     if i <> sonsLen(n)-1 then add(result, ', ');
   end;
@@ -361,9 +361,7 @@ begin // is a subtype of f?
         tyProc: begin
           if (sonsLen(f) = sonsLen(a)) and (f.callconv = a.callconv) then begin
             // Note: We have to do unification for the parameters before the
-            // return type! Otherwise it'd be counter-intuitive for the standard
-            // Nimrod syntax. For the C-based syntax it IS counter-intuitive.
-            // But that is one of the reasons a standard syntax was picked.
+            // return type!
             result := isEqual; // start with maximum; also correct for no
                                // params at all
             for i := 1 to sonsLen(f)-1 do begin
@@ -433,8 +431,9 @@ begin // is a subtype of f?
     end;
     tyAnyEnum: begin
       case a.kind of
-        tyRange: result := typeRel(mapping, f, base(a));
-        tyEnum:  result := isSubtype;
+        tyRange:   result := typeRel(mapping, f, base(a));
+        tyEnum:    result := isSubtype;
+        tyAnyEnum: result := isEqual;
         else begin end
       end
     end;
@@ -726,11 +725,11 @@ begin
         end
         else begin
           setSon(m.call, formal.position+1, arg);
-        end;
-        inc(f);
+        end
       end
     end;
     inc(a);
+    inc(f);
   end;
   // iterate over all formal params and check all are provided:
   f := 1;
diff --git a/nim/strtabs.pas b/nim/strtabs.pas
index b07aefab1..4fcf32891 100644
--- a/nim/strtabs.pas
+++ b/nim/strtabs.pas
@@ -269,14 +269,14 @@ begin
           j := i+1;
           while (j <= length(f)+strStart-1) and (f[j] <> '}') do inc(j);
           key := ncopy(f, i+2+strStart-1, j-1+strStart-1);
-          result := result +{&} getValue(t, flags, key);
+          add(result, getValue(t, flags, key));
           i := j+1
         end;
         'a'..'z', 'A'..'Z', #128..#255, '_': begin
           j := i+1;
           while (j <= length(f)+strStart-1) and (f[j] in PatternChars) do inc(j);
           key := ncopy(f, i+1+strStart-1, j-1+strStart-1);
-          result := result +{&} getValue(t, flags, key);
+          add(result, getValue(t, flags, key));
           i := j
         end
         else begin
diff --git a/nim/strutils.pas b/nim/strutils.pas
index 71a428dbb..cd07105be 100644
--- a/nim/strutils.pas
+++ b/nim/strutils.pas
@@ -28,6 +28,7 @@ function cmp(const x, y: string): int;
 function cmpIgnoreCase(const x, y: string): int;
 
 function format(const f: string; const args: array of string): string;
+procedure addf(var result: string; const f: string; args: array of string);
 
 function toHex(x: BiggestInt; len: int): string;
 function toOctal(value: Char): string;
@@ -47,7 +48,7 @@ function ToString(b: Boolean): string; overload;
 
 function IntToStr(i: BiggestInt; minChars: int): string;
 
-function findSubStr(const sub, s: string; start: int = 1): int;
+function find(const s, sub: string; start: int = 1): int; overload;
 function replaceStr(const s, search, by: string): string;
 procedure deleteStr(var s: string; first, last: int);
 
@@ -81,8 +82,8 @@ implementation
 
 function quoteIfContainsWhite(const s: string): string;
 begin
-  if ((findSubStr(' ', s) >= strStart)
-  or (findSubStr(#9, s) >= strStart)) and (s[strStart] <> '"') then
+  if ((find(s, ' ') >= strStart)
+  or (find(s, #9) >= strStart)) and (s[strStart] <> '"') then
     result := '"' +{&} s +{&} '"'
   else
     result := s
@@ -247,7 +248,7 @@ begin
       result := result + s[i]
 end;
 
-function findSubStr(const sub, s: string; start: int = 1): int;
+function find(const s, sub: string; start: int = 1): int;
 var
   i, j, M, N: int;
 begin
@@ -277,7 +278,7 @@ begin
   result := '';
   i := 1;
   repeat
-    j := findSubStr(search, s, i);
+    j := find(s, search, i);
     if j = 0 then begin
       // copy the rest:
       result := result + copy(s, i, length(s) - i + 1);
@@ -475,7 +476,7 @@ begin
   until false
 end;
 
-function find(const x: string; const inArray: array of string): int;
+function find(const x: string; const inArray: array of string): int; overload;
 var
   i: int;
   y: string;
@@ -491,30 +492,29 @@ begin
   result := -1
 end;
 
-function format(const f: string; const args: array of string): string;
+procedure addf(var result: string; const f: string; args: array of string);
 const
   PatternChars = ['a'..'z', 'A'..'Z', '0'..'9', '_', #128..#255];
 var
   i, j, x: int;
 begin
-  result := '';
   i := 1;
   while i <= length(f) do
     if f[i] = '$' then begin
       case f[i+1] of
         '$': begin
-          result := result + '$';
+          addChar(result, '$');
           inc(i, 2);
         end;
         '1'..'9': begin
-          result := result + args[ord(f[i+1]) - ord('0') - 1];
+          add(result, args[ord(f[i+1]) - ord('0') - 1]);
           inc(i, 2);
         end;
         '{': begin
           j := i+1;
           while (j <= length(f)) and (f[j] <> '}') do inc(j);
           x := find(ncopy(f, i+2, j-1), args);
-          if (x >= 0) and (x < high(args)) then result := result + args[x+1]
+          if (x >= 0) and (x < high(args)) then add(result, args[x+1])
           else raise EInvalidFormatStr.create('');
           i := j+1
         end;
@@ -522,7 +522,7 @@ begin
           j := i+1;
           while (j <= length(f)) and (f[j] in PatternChars) do inc(j);
           x := find(ncopy(f, i+1, j-1), args);
-          if (x >= 0) and (x < high(args)) then result := result + args[x+1]
+          if (x >= 0) and (x < high(args)) then add(result, args[x+1])
           else raise EInvalidFormatStr.create(ncopy(f, i+1, j-1));
           i := j
         end
@@ -530,11 +530,17 @@ begin
       end
     end
     else begin
-      result := result + f[i];
+      addChar(result, f[i]);
       inc(i)
     end
 end;
 
+function format(const f: string; const args: array of string): string;
+begin
+  result := '';
+  addf(result, f, args)
+end;
+
 {@ignore}
 {$ifopt Q-} {$Q+}
 {$else}     {$define Q_off}
diff --git a/nim/transf.pas b/nim/transf.pas
index 98d1e89ea..5d9f44143 100644
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -14,6 +14,7 @@ unit transf;
 // * inlines iterators
 // * inlines constants
 // * performes contant folding
+// * introduces nkHiddenDeref, nkHiddenSubConv, etc.
 
 interface
 
@@ -446,12 +447,51 @@ begin
   end;
 end;
 
+function skipPassAsOpenArray(n: PNode): PNode;
+begin
+  result := n;
+  while result.kind = nkPassAsOpenArray do 
+    result := result.sons[0]
+end;
+
+type 
+  TPutArgInto = (paDirectMapping, paFastAsgn, paVarAsgn);
+
+function putArgInto(arg: PNode; formal: PType): TPutArgInto;
+// This analyses how to treat the mapping "formal <-> arg" in an
+// inline context.
+var
+  i: int;
+begin
+  if skipGeneric(formal).kind = tyOpenArray then begin
+    result := paDirectMapping; // XXX really correct?
+    // what if ``arg`` has side-effects?
+    exit
+  end;
+  case arg.kind of
+    nkEmpty..nkNilLit: result := paDirectMapping;
+    nkPar, nkCurly, nkBracket: begin
+      result := paFastAsgn;
+      for i := 0 to sonsLen(arg)-1 do 
+        if putArgInto(arg.sons[i], formal) <> paDirectMapping then
+          exit;
+      result := paDirectMapping;
+    end;
+    else begin
+      if skipGeneric(formal).kind = tyVar then
+        result := paVarAsgn
+      else
+        result := paFastAsgn
+    end
+  end
+end;
+
 function transformFor(c: PTransf; n: PNode): PNode;
 // generate access statements for the parameters (unless they are constant)
 // put mapping from formal parameters to actual parameters
 var
   i, len: int;
-  call, e, v, body: PNode;
+  call, v, body, arg: PNode;
   newC: PTransCon;
   temp, formal: PSym;
 begin
@@ -473,24 +513,24 @@ begin
   // generate access statements for the parameters (unless they are constant)
   pushTransCon(c, newC);
   for i := 1 to sonsLen(call)-1 do begin
-    e := getConstExpr(c.module, call.sons[i]);
+    arg := skipPassAsOpenArray(transform(c, call.sons[i]));
     formal := skipGeneric(newC.owner.typ).n.sons[i].sym;
-    if e <> nil then
-      IdNodeTablePut(newC.mapping, formal, e)
-    else if (skipConv(call.sons[i]).kind = nkSym) then begin
-      // since parameters cannot be modified, we can identify the formal and
-      // the actual params
-      IdNodeTablePut(newC.mapping, formal, call.sons[i]);
-    end
-    else begin
-      // generate a temporary and produce an assignment statement:
-      temp := newTemp(c, formal.typ, formal.info);
-      addVar(v, newSymNode(temp));
-      // BUGFIX: do not copy call.sons[i], but transform it!
-      addSon(result, newAsgnStmt(c, newSymNode(temp),
-                                 transform(c, call.sons[i])));
-      IdNodeTablePut(newC.mapping, formal, newSymNode(temp)); // BUGFIX
-    end
+    //if IdentEq(newc.Owner.name, 'items') then 
+    //  liMessage(arg.info, warnUser, 'items: ' + nodeKindToStr[arg.kind]);
+    case putArgInto(arg, formal.typ) of
+      paDirectMapping: IdNodeTablePut(newC.mapping, formal, arg);
+      paFastAsgn: begin
+        // generate a temporary and produce an assignment statement:
+        temp := newTemp(c, formal.typ, formal.info);
+        addVar(v, newSymNode(temp));
+        addSon(result, newAsgnStmt(c, newSymNode(temp), arg));
+        IdNodeTablePut(newC.mapping, formal, newSymNode(temp));
+      end;
+      paVarAsgn: begin
+        assert(skipGeneric(formal.typ).kind = tyVar);
+        InternalError(arg.info, 'not implemented: pass to var parameter');
+      end;
+    end;
   end;
   body := newC.owner.ast.sons[codePos];
   pushInfoContext(n.info);
@@ -668,7 +708,7 @@ function transformCase(c: PTransf; n: PNode): PNode;
 // removes `elif` branches of a case stmt
 var
   len, i, j: int;
-  ifs: PNode;
+  ifs, elsen: PNode;
 begin
   len := sonsLen(n);
   i := len-1;
@@ -678,9 +718,11 @@ begin
     if (n.sons[i].kind <> nkOfBranch) then 
       InternalError(n.sons[i].info, 'transformCase');
     ifs := newNodeI(nkIfStmt, n.sons[i+1].info);
+    elsen := newNodeI(nkElse, ifs.info);
     for j := i+1 to len-1 do addSon(ifs, n.sons[j]);
     setLength(n.sons, i+2);
-    n.sons[i+1] := ifs;
+    addSon(elsen, ifs);
+    n.sons[i+1] := elsen;
   end;
   result := n;
   for j := 0 to sonsLen(n)-1 do result.sons[j] := transform(c, n.sons[j]);
diff --git a/nim/types.pas b/nim/types.pas
index 25ad54b33..af19a1671 100644
--- a/nim/types.pas
+++ b/nim/types.pas
@@ -1,12 +1,11 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
-
 unit types;
 
 // this module contains routines for accessing and iterating over types
@@ -47,7 +46,6 @@ function mutateType(t: PType; iter: TTypeMutator; closure: PObject): PType;
 // Returns result of `iter`.
 
 
-
 function SameType(x, y: PType): Boolean;
 function SameTypeOrNil(a, b: PType): Boolean;
 
@@ -115,6 +113,8 @@ function analyseObjectWithTypeField(t: PType): TTypeFieldResult;
 // made or intializing of the type field suffices or if there is no type field
 // at all in this type.
 
+function typeAllowed(t: PType; kind: TSymKind): bool;
+
 implementation
 
 function InvalidGenericInst(f: PType): bool;
@@ -185,11 +185,13 @@ begin
   n := sym.typ.n;
   for i := 1 to sonsLen(n)-1 do begin
     p := n.sons[i];
-    assert(p.kind = nkSym);
-    result := result +{&} p.sym.name.s +{&} ': ' +{&} typeToString(p.sym.typ);
-    if i <> sonsLen(n)-1 then result := result + ', ';
+    if (p.kind <> nkSym) then InternalError('getProcHeader');
+    add(result, p.sym.name.s);
+    add(result, ': ');
+    add(result, typeToString(p.sym.typ));
+    if i <> sonsLen(n)-1 then add(result, ', ');
   end;
-  result := result + ')';
+  addChar(result, ')');
   if n.sons[0].typ <> nil then
     result := result +{&} ': ' +{&} typeToString(n.sons[0].typ);
 end;
@@ -928,6 +930,96 @@ begin
   end
 end;
 
+function typeAllowedAux(var marker: TIntSet; t: PType; 
+                        kind: TSymKind): bool; forward;
+
+function typeAllowedNode(var marker: TIntSet; n: PNode; kind: TSymKind): bool;
+var
+  i: int;
+begin
+  result := true;
+  if n <> nil then begin
+    result := typeAllowedAux(marker, n.typ, kind);
+    if result then 
+      case n.kind of
+        nkNone..nkNilLit: begin end;
+        else begin
+          for i := 0 to sonsLen(n)-1 do begin
+            result := typeAllowedNode(marker, n.sons[i], kind);
+            if not result then exit
+          end
+        end
+      end
+  end
+end;
+
+function typeAllowedAux(var marker: TIntSet; t: PType; kind: TSymKind): bool;
+var
+  i: int;
+begin
+  assert(kind in [skVar, skConst, skParam]);
+  result := true;
+  if t = nil then exit;
+  // if we have already checked the type, return true, because we stop the
+  // evaluation if something is wrong:
+  if IntSetContainsOrIncl(marker, t.id) then exit;
+  case skipGeneric(t).kind of 
+    tyVar: begin
+      case skipGeneric(t.sons[0]).kind of
+        tyVar: result := false; // ``var var`` is always an invalid type:
+        tyOpenArray: result := (kind = skParam) and 
+                                typeAllowedAux(marker, t.sons[0], kind);
+        else result := (kind <> skConst) and 
+                                typeAllowedAux(marker, t.sons[0], kind);
+      end
+    end;
+    tyProc: begin
+      for i := 1 to sonsLen(t)-1 do begin
+        result := typeAllowedAux(marker, t.sons[i], skParam);
+        if not result then exit;
+      end;
+      if t.sons[0] <> nil then
+        result := typeAllowedAux(marker, t.sons[0], skVar)
+    end;
+    tyGeneric, tyGenericParam, tyForward, tyNone: result := false;
+    tyEmpty, tyNil: result := kind = skConst;
+    tyString, tyBool, tyChar, tyEnum, tyInt..tyFloat128, tyCString, tyPointer: 
+      result := true;
+    tyAnyEnum: result := kind = skParam;
+    tyGenericInst: result := typeAllowedAux(marker, lastSon(t), kind);
+    tyRange: result := skipGeneric(t.sons[0]).kind in 
+                         [tyChar, tyEnum, tyInt..tyFloat128];
+    tyOpenArray: 
+      result := (kind = skParam) and typeAllowedAux(marker, t.sons[0], skVar);
+    tySequence: result := (kind <> skConst) 
+      and typeAllowedAux(marker, t.sons[0], skVar)
+      or (t.sons[0].kind = tyEmpty);
+    tyArray: result := typeAllowedAux(marker, t.sons[1], skVar);
+    tyPtr, tyRef: result := typeAllowedAux(marker, t.sons[0], skVar);
+    tyArrayConstr, tyTuple, tySet: begin
+      for i := 0 to sonsLen(t)-1 do begin
+        result := typeAllowedAux(marker, t.sons[i], kind);
+        if not result then exit
+      end;
+    end;
+    tyObject: begin
+      for i := 0 to sonsLen(t)-1 do begin
+        result := typeAllowedAux(marker, t.sons[i], skVar);
+        if not result then exit
+      end;
+      if t.n <> nil then result := typeAllowedNode(marker, t.n, skVar)
+    end
+  end
+end;
+
+function typeAllowed(t: PType; kind: TSymKind): bool;
+var 
+  marker: TIntSet; 
+begin
+  IntSetInit(marker);
+  result := typeAllowedAux(marker, t, kind);
+end;
+
 function align(address, alignment: biggestInt): biggestInt;
 begin
   result := (address + (alignment-1)) and not (alignment-1);
diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas
index 587005c2a..dd2df0047 100644
--- a/nim/wordrecg.pas
+++ b/nim/wordrecg.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -66,7 +66,7 @@ type
     wMerge, wLib, wDynlib, wCompilerproc, wCppmethod, wFatal,
     wError, wWarning, wHint, wLine, wPush, wPop,
     wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wPragma,
-    wLink, wCompile, wLinksys, wFixupsystem, wDeprecated, wVarargs,
+    wLink, wCompile, wLinksys, wDeprecated, wVarargs,
     wByref, wCallconv, wBreakpoint, wDebugger, wNimcall, wStdcall,
     wCdecl, wSafecall, wSyscall, wInline, wNoInline, wFastcall, wClosure,
     wNoconv, wOn, wOff, wChecks, wRangechecks, wBoundchecks,
@@ -84,7 +84,7 @@ type
     wMaxErr, wExpr, wStmt, wTypeDesc,
     wSubsChar, wAstCache, wAcyclic, wIndex,
     // commands:
-    wCompileToC, wCompileToCpp, wCompileToEcmaScript,
+    wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM,
     wPretty, wDoc, wPas,
     wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy,
     wRst2html, wI,
@@ -140,7 +140,7 @@ const
     'merge', 'lib', 'dynlib', 'compilerproc', 'cppmethod', 'fatal',
     'error', 'warning', 'hint', 'line', 'push', 'pop',
     'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'pragma',
-    'link', 'compile', 'linksys', 'fixupsystem', 'deprecated', 'varargs',
+    'link', 'compile', 'linksys', 'deprecated', 'varargs',
     'byref', 'callconv', 'breakpoint', 'debugger', 'nimcall', 'stdcall',
     'cdecl', 'safecall', 'syscall', 'inline', 'noinline', 'fastcall', 'closure',
     'noconv', 'on', 'off', 'checks', 'rangechecks', 'boundchecks',
@@ -158,7 +158,7 @@ const
     'maxerr', 'expr', 'stmt', 'typedesc',
     'subschar', 'astcache', 'acyclic', 'index',
     // commands:
-    'compiletoc', 'compiletocpp', 'compiletoecmascript',
+    'compiletoc', 'compiletocpp', 'compiletoecmascript', 'compiletollvm',
     'pretty', 'doc', 'pas', 'gendepend', 'listdef', 'check', 'parse',
     'scan', 'boot', 'lazy', 'rst2html', 'i'+'',