Skip to content

Commit

Permalink
absolutely minimal wasm target support
Browse files Browse the repository at this point in the history
can compile a simple add function to wasm!
  • Loading branch information
arnetheduck committed Apr 15, 2018
1 parent 2e658db commit 6c0de4b
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
6 changes: 6 additions & 0 deletions llvm/llvm.nim
Expand Up @@ -52,6 +52,12 @@ proc initializeX86Target*() {.importc: "LLVMInitializeX86Target", dynlib: LLVMLi
proc initializeX86TargetInfo*() {.importc: "LLVMInitializeX86TargetInfo", dynlib: LLVMLib.}
proc initializeX86TargetMC*() {.importc: "LLVMInitializeX86TargetMC", dynlib: LLVMLib.}

proc initializeWebAssemblyAsmPrinter*() {.importc: "LLVMInitializeWebAssemblyAsmPrinter", dynlib: LLVMLib.}
proc initializeWebAssemblyDisassembler*() {.importc: "LLVMInitializeWebAssemblyDisassembler", dynlib: LLVMLib.}
proc initializeWebAssemblyTarget*() {.importc: "LLVMInitializeWebAssemblyTarget", dynlib: LLVMLib.}
proc initializeWebAssemblyTargetInfo*() {.importc: "LLVMInitializeWebAssemblyTargetInfo", dynlib: LLVMLib.}
proc initializeWebAssemblyTargetMC*() {.importc: "LLVMInitializeWebAssemblyTargetMC", dynlib: LLVMLib.}

include llvm/Core
include llvm/DebugInfo
include llvm/BitReader
Expand Down
2 changes: 1 addition & 1 deletion make-llvm.sh
Expand Up @@ -14,7 +14,7 @@ tar xf llvm-$VER2.src.tar.xz || exit 1
cd llvm-$VER2.src
mkdir -p rel
cd rel
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_LLVM_DYLIB=1 -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_ENABLE_ASSERTIONS=1 ..
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_LLVM_DYLIB=1 -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DLLVM_ENABLE_ASSERTIONS=1 ..

ninja

Expand Down
40 changes: 31 additions & 9 deletions nlvm/llgen.nim
Expand Up @@ -132,6 +132,10 @@ type LLGenObj = object of TPassContext
# Compile unit
dcu: llvm.MetadataRef

# target specific stuff
tgt: string
tgtExportLinkage: llvm.Linkage

type LLGen = ref LLGenObj

# Using an ugly global - haven't found a way to keep per-project data other than
Expand Down Expand Up @@ -1988,7 +1992,7 @@ proc genGlobal(g: LLGen, n: PNode): llvm.ValueRef =
if sfImportc in s.flags:
result.setLinkage(llvm.ExternalLinkage)
elif sfExportc in s.flags:
result.setLinkage(llvm.CommonLinkage)
result.setLinkage(g.tgtExportLinkage)
result.setInitializer(llvm.constNull(t))
else:
result.setLinkage(llvm.PrivateLinkage)
Expand Down Expand Up @@ -2274,8 +2278,10 @@ proc genFunctionWithBody(g: LLGen, s: PSym): llvm.ValueRef =
if sfForward in s.flags: return
if sfImportc in s.flags: return

# Because we generate only one module, we can tag all functions internal
result.setLinkage(llvm.InternalLinkage)
# Because we generate only one module, we can tag all functions internal, except
# those that should be importable from c
if sfExportc notin s.flags:
result.setLinkage(llvm.InternalLinkage)

var i = 1
var lastIsArr = false
Expand Down Expand Up @@ -5569,6 +5575,19 @@ proc newLLGen(s: PSym): LLGen =
g.dtypes[tyCString] = g.d.nimDIBuilderCreatePointerType(
g.dtypes[tyChar], 64, 64, "")

if options.existsConfigVar("nlvm.target"):
result.tgt = options.getConfigVar("nlvm.target")
else:
let p = llvm.getDefaultTargetTriple()
result.tgt = $p
disposeMessage(p)

# TODO somehow, clang knows this! figure out how and why...
result.tgtExportLinkage = llvm.CommonLinkage

if result.tgt.startsWith("wasm"):
result.tgtExportLinkage = llvm.ExternalLinkage

proc genMain(g: LLGen) =
let llMainType = llvm.functionType(llCIntType, [llCIntType, llCStringType.pointerType()])

Expand Down Expand Up @@ -5619,13 +5638,13 @@ proc genMain(g: LLGen) =

let cmdLine = g.m.getNamedGlobal("cmdLine")
if cmdLine != nil:
cmdLine.setLinkage(llvm.CommonLinkage)
cmdLine.setLinkage(g.tgtExportLinkage)
cmdLine.setInitializer(llvm.constNull(cmdLine.typeOf().getElementType()))
discard g.b.buildStore(g.b.buildBitCast(f.getParam(1), cmdLine.typeOf().getElementType(), ""), cmdLine)

let cmdCount = g.m.getNamedGlobal("cmdCount")
if cmdCount != nil:
cmdCount.setLinkage(llvm.CommonLinkage)
cmdCount.setLinkage(g.tgtExportLinkage)
cmdCount.setInitializer(llvm.constNull(cmdCount.typeOf().getElementType()))
discard g.b.buildStore(f.getParam(0), cmdCount)

Expand Down Expand Up @@ -5690,10 +5709,13 @@ proc writeOutput(g: LLGen, project: string) =
initializeX86TargetInfo()
initializeX86TargetMC()

let triple = llvm.getDefaultTargetTriple()
initializeWebAssemblyAsmPrinter()
initializeWebAssemblyTarget()
initializeWebAssemblyTargetInfo()
initializeWebAssemblyTargetMC()

var tr: llvm.TargetRef
discard getTargetFromTriple(triple, addr(tr), nil)
discard getTargetFromTriple(g.tgt, addr(tr), nil)

var reloc = llvm.RelocDefault
if optGenDynLib in gGlobalOptions and
Expand All @@ -5704,12 +5726,12 @@ proc writeOutput(g: LLGen, project: string) =
if optOptimizeSpeed in gOptions: llvm.CodeGenLevelAggressive
else: llvm.CodeGenLevelDefault

let tm = createTargetMachine(tr, triple, "", "", cgl,
let tm = createTargetMachine(tr, g.tgt, "", "", cgl,
reloc, llvm.CodeModelDefault)

let layout = tm.createTargetDataLayout()
g.m.setModuleDataLayout(layout)
g.m.setTarget(triple)
g.m.setTarget(g.tgt)

g.runOptimizers()

Expand Down
6 changes: 5 additions & 1 deletion nlvm/nlvm.nim
Expand Up @@ -76,7 +76,11 @@ proc handleCmdLine() =
# act as a drop-in replacement (for now)
# Most of this is taken from the main nim command
if os.paramCount() == 0:
echo "you can: nlvm c <filename> (see standard nim compiler for options)"
echo """
you can: nlvm c <filename> (see standard nim compiler for options)
magic options:
--nlvm.target=wasm32 cross-compile to WebAssembly
"""
else:
# Main nim compiler has some reaons for two-pass parsing
service.processCmdLine(passCmd1, "")
Expand Down

0 comments on commit 6c0de4b

Please sign in to comment.