提交 74a1e417 编写于 作者: B Ben Shi

llvm: support building WA source file to an Arduino project

上级 9ea8f464
# Test the llvm backend.
# Make Arduino's builtin LED blinking.
# `wa native --target=avr arduino_blink.wa`
#wa:linkname __avr_write_port__
fn write_port(p i16, v i8)
# Delay a period of time
var cnt i8
fn delay(n i32) {
for i := i32(0); i < n; i++ {
cnt++
}
}
fn main() {
# Set Pin #5 (connected with the builtin LED) of Port B to output mode.
write_port(0x24, 0x20)
for b := 0; ; b++ {
if (b % 2) == 0 {
# Turn on the LED.
write_port(0x25, 0x20)
} else {
# Turn off the LED.
write_port(0x25, 0x00)
}
# Delay a period of time
delay(99999)
}
}
......@@ -331,6 +331,12 @@ func (p *App) LLVM(infile string, outfile string, target string, debug bool) err
if target != "" {
llc = append(llc, "-mtriple", target)
}
// Add target specific options.
switch target {
case "avr":
llc = append(llc, "-mcpu=atmega328")
default:
}
cmd0 := exec.Command(p.opt.Llc, llc...)
cmd0.Stderr = os.Stderr
if err := cmd0.Run(); err != nil {
......@@ -338,6 +344,35 @@ func (p *App) LLVM(infile string, outfile string, target string, debug bool) err
return err
}
// TODO: This is a temporary solution for AVR-Arduino. We generate
// an Arduino project instead of an ELF.
if target == "avr" {
// Create a new directory for the output Arduino project.
ext, outdir := path.Ext(outfile), ""
if len(ext) > 0 {
pos := strings.Index(outfile, ext)
outdir = outfile[0:pos]
}
if err := os.RemoveAll(outdir); err != nil {
return err
}
if err := os.Mkdir(outdir, 0755); err != nil {
return err
}
// Move the assembly file to the project directory.
newAsmFile := strings.ReplaceAll(asmfile, ".s", ".S")
if err := os.Rename(asmfile, path.Join(outdir, newAsmFile)); err != nil {
return err
}
// Create the project main '.ino' file.
inoFile := path.Join(outdir, path.Base(outdir)+".ino")
inoStr := "void setup(void) {}\nextern \"C\" { extern void wa_main(void); }\nvoid loop(void) { wa_main(); }\n"
if err := os.WriteFile(inoFile, []byte(inoStr), 0644); err != nil {
return err
}
return nil
}
// Invoke command `clang xxx.s -o outfile --target=xxx`.
clangArgs := []string{asmfile, "-static", "-o", outfile}
if target != "" {
......
......@@ -56,7 +56,7 @@ func (p *Compiler) Compile(prog *loader.Program) (output string, err error) {
}
// Emit some auxiliary functions.
p.output.WriteString("define void @main() {\n")
p.output.WriteString("define void @wa_main() {\n")
p.output.WriteString(" call void @")
p.output.WriteString(getNormalName(prog.SSAMainPkg.Pkg.Path() + ".init()\n"))
p.output.WriteString(" call void @")
......@@ -67,8 +67,22 @@ func (p *Compiler) Compile(prog *loader.Program) (output string, err error) {
// Emit some target specific functions.
switch getArch(p.target) {
case "", "x86_64", "aarch64":
p.output.WriteString("define void @main() {\n")
p.output.WriteString(" call void @wa_main()\n")
p.output.WriteString(" ret void\n")
p.output.WriteString("}\n\n")
p.output.WriteString("declare i32 @printf(i8* readonly, ...)\n")
case "avr":
p.output.WriteString("define void @__avr_write_port__(i16 %0, i8 zeroext %1) {\n")
p.output.WriteString(" %3 = inttoptr i16 %0 to i8*\n")
p.output.WriteString(" store volatile i8 %1, i8* %3, align 1\n")
p.output.WriteString(" ret void\n")
p.output.WriteString("}\n\n")
p.output.WriteString("define zeroext i8 @__avr_read_port__(i16 %0) {\n")
p.output.WriteString(" %2 = inttoptr i16 %0 to i8*\n")
p.output.WriteString(" %3 = load volatile i8, i8* %2, align 1\n")
p.output.WriteString(" ret i8 %3\n")
p.output.WriteString("}\n\n")
default:
}
......
......@@ -12,6 +12,10 @@ import (
)
func (p *Compiler) compileFunction(fn *ssa.Function) error {
if isTargetBuiltin(fn.LinkName(), p.target) || isTargetBuiltin(fn.Name(), p.target) {
return nil
}
// Translate return type.
var retTyStr string
rets := fn.Signature.Results()
......@@ -47,10 +51,18 @@ func (p *Compiler) compileFunction(fn *ssa.Function) error {
}
// Emit a proper function name.
p.output.WriteString("define ")
if len(fn.Blocks) == 0 {
p.output.WriteString("declare ")
} else {
p.output.WriteString("define ")
}
p.output.WriteString(retTyStr)
p.output.WriteString(" @")
p.output.WriteString(getNormalName(fn.Pkg.Pkg.Path() + "." + fn.Name()))
if len(fn.LinkName()) > 0 {
p.output.WriteString(fn.LinkName())
} else {
p.output.WriteString(getNormalName(fn.Pkg.Pkg.Path() + "." + fn.Name()))
}
p.output.WriteString("(")
// Translate arguments.
......@@ -70,7 +82,12 @@ func (p *Compiler) compileFunction(fn *ssa.Function) error {
p.output.WriteString(", ")
}
}
p.output.WriteString(") {\n")
if len(fn.Blocks) == 0 {
p.output.WriteString(")\n\n")
return nil
} else {
p.output.WriteString(") {\n")
}
// Translate Go SSA intermediate instructions.
for i, b := range fn.Blocks {
......
......@@ -303,6 +303,7 @@ func getNormalName(name string) string {
name = strings.ReplaceAll(name, ".", "__")
name = strings.ReplaceAll(name, "$", "__")
name = strings.ReplaceAll(name, "/", "__")
name = strings.ReplaceAll(name, "#", "__")
return name
}
......@@ -315,3 +316,24 @@ func getRealType(ty types.Type) types.Type {
}
}
}
func isTargetBuiltin(fn string, target string) bool {
avr := []string{"__avr_write_port__", "__avr_read_port__"}
other := []string{"printf"}
var ts []string
switch getArch(target) {
case "avr":
ts = avr
default:
ts = other
}
for _, v := range ts {
if v == fn {
return true
}
}
return false
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册