summary refs log tree commit diff stats
path: root/nim/cgen.pas
diff options
context:
space:
mode:
Diffstat (limited to 'nim/cgen.pas')
-rw-r--r--nim/cgen.pas482
1 files changed, 356 insertions, 126 deletions
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;