提交 0c9f5866 编写于 作者: chai2010's avatar chai2010

添加 LLVM 后端

上级 919a51c4
default:
clang -S -emit-llvm _builtin.c
clang -Woverride-module _builtin.ll main.ll
./a.out || echo $$?
builtin-ll:
clang -S -emit-llvm _builtin.c
clean:
// 版权 @2021 凹语言 作者。保留所有权利。
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ----------------------------------------------------------------------------
// bool
// ----------------------------------------------------------------------------
typedef uint8_t ugo_bool_t;
// ----------------------------------------------------------------------------
// ugo_string_t
// ----------------------------------------------------------------------------
typedef struct {
char* data;
int size;
} ugo_string_t;
ugo_string_t* ugo_string_new(int size, const char* data) {
ugo_string_t* p = malloc(sizeof(*p)+size+1);
p->data = (char*)(p+1);
p->size = size;
if(data != NULL) {
memcpy(p->data, data, size);
p->data[size] = '\0';
} else {
memset(p->data, 0, size+1);
}
return p;
}
ugo_string_t* ugo_string_clone(ugo_string_t* s) {
ugo_string_t* p = malloc(sizeof(*p)+s->size+1);
memcpy(p->data, s->data, s->size);
p->data[s->size] = '\0';
p->size = s->size;
return p;
}
void ugo_string_free(ugo_string_t* s) {
free(s);
}
// ----------------------------------------------------------------------------
// cstring
// ----------------------------------------------------------------------------
char* ugo_cstring_join(const char* s1, const char* s2) {
int len1 = strlen(s1);
int len2 = strlen(s2);
char* dst = malloc(len1+len2+1);
strcpy(dst, s1);
strcat(dst, s2);
return dst;
}
char* ugo_cstring_slice(const char* s, int low, int high) {
int src_len = strlen(s);
int dst_len = 0;
char* dst = NULL;
if(low < 0) { low = 0; }
if(high < 0) { high = src_len; }
if(low >= src_len) { low = src_len-1; }
if(high > src_len) { low = src_len; }
dst_len = high-low;
dst = malloc(dst_len+1);
memcpy(dst, s+low, dst_len);
dst[dst_len] = '\0';
return dst;
}
int ugo_cstring_index(const char* s, int idx) {
return s[idx];
}
int ugo_cstring_cmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
}
// ----------------------------------------------------------------------------
// ugo_print_xxx
// ----------------------------------------------------------------------------
int ugo_print_rune(int ch) {
return printf("%c", ch);
}
int ugo_print_cstring(const char* s) {
return printf("%s", s);
}
int ugo_print_cstring_len(const char* s, int n) {
while(n-- > 0) {
printf("%c", *s++);
}
return 1;
}
int ugo_print_string(const ugo_string_t* s) {
return printf("%.*s", s->size, s->data);
}
int ugo_print_bool(ugo_bool_t x) {
return printf("%s", x? "true": "false");
}
int ugo_print_int(int x) {
return printf("%d", x);
}
int ugo_print_int64(int64_t x) {
return printf("%lld", x);
}
int ugo_print_ptr(void *p) {
return printf("0x%x", p, p);
}
int ugo_printf(const char* format, ...) {
va_list args;
int n;
va_start(args, format);
n = vprintf(format, args);
va_end(args);
return n;
}
// ----------------------------------------------------------------------------
// builtin
// ----------------------------------------------------------------------------
int ugo_builtin_println(int x) {
return printf("%d\n", x);
}
int ugo_builtin_exit(int x) {
exit(x);
return 0;
}
// ----------------------------------------------------------------------------
// END
// ----------------------------------------------------------------------------
此差异已折叠。
; declare i32 @ugo_builtin_println(i32*)
; declare i32 @ugo_builtin_println(i32)
// 版权 @2021 凹语言 作者。保留所有权利。
package builtin
import _ "embed"
//go:embed _builtin.ll
var llBuiltin string
//go:embed _builtin_wasm.ll
var llBuiltin_wasm string
func GetBuiltinLL(goos, goarch string) string {
switch goos {
case "wasm":
return llBuiltin_wasm
case "darwin":
case "linux":
case "windows":
}
return llBuiltin
}
const Header = `
declare i32 @ugo_builtin_println(i32)
declare i32 @ugo_builtin_exit(i32)
`
const MainMain = `
define i32 @main() {
call i32() @ugo_main_init()
call i32() @ugo_main_main()
ret i32 0
}
`
; ModuleID = 'builtin.c'
source_filename = "builtin.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.4"
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @ugo_builtin_exit(i32) #0 {
%2 = alloca i32, align 4
store i32 %0, i32* %2, align 4
%3 = load i32, i32* %2, align 4
call void @exit(i32 %3) #2
unreachable
}
; Function Attrs: noreturn
declare void @exit(i32) #1
attributes #0 = { noinline nounwind optnone ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "darwin-stkchk-strong-link" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { noreturn "correctly-rounded-divide-sqrt-fp-math"="false" "darwin-stkchk-strong-link" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "probe-stack"="___chkstk_darwin" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { noreturn }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 2, !"SDK Version", [3 x i32] [i32 10, i32 15, i32 4]}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 7, !"PIC Level", i32 2}
!3 = !{!"Apple clang version 11.0.3 (clang-1103.0.32.62)"}
declare i32 @ugo_builtin_exit(i32)
define i32 @ugo_main_main() {
%t0 = add i32 0, 40 ; t0 = 40
%t1 = add i32 0, 2 ; t1 = 2
%t2 = add i32 %t0, %t1 ; t2 = t1 + t1
call i32(i32) @ugo_builtin_exit(i32 %t2)
ret i32 0
}
define i32 @main() {
call i32() @ugo_main_main()
ret i32 0
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"fmt"
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/config"
"github.com/wa-lang/wa/internal/loader"
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/ssa"
)
type Compiler struct {
prog *loader.Program
module *llir.Module
curFunc *llir.Func
curLocals map[ssa.Value]llvalue.Value
curBlockEntries map[*ssa.BasicBlock]*llir.Block // a *ssa.BasicBlock may be split up
phis map[*ssa.Phi]*llir.InstPhi
llTypeNameMap map[lltypes.Type]string
llNamedTypeMap map[string]lltypes.Type
llFuncNameMap map[*llir.Func]string
llNamedFuncMap map[string]*llir.Func
compilePkgDoneMap map[*ssa.Package]bool
}
func New() *Compiler {
return &Compiler{}
}
func (p *Compiler) Compile(prog *loader.Program) (output string, err error) {
p.prog = prog
p.module = llir.NewModule()
p.llTypeNameMap = make(map[lltypes.Type]string)
p.llNamedTypeMap = make(map[string]lltypes.Type)
p.llFuncNameMap = make(map[*llir.Func]string)
p.llNamedFuncMap = make(map[string]*llir.Func)
p.compilePkgDoneMap = make(map[*ssa.Package]bool)
if !p.prog.Cfg.Debug {
defer func() {
//if r := recover(); r != nil {
// err = fmt.Errorf("%v", r)
//}
}()
}
// 定义 builtin 类型和函数
if err := p.defineBuiltin(); err != nil {
return "", err
}
// 编译全部包
for _, pkg := range prog.SSAProgram.AllPackages() {
if err := p.compilePackage(pkg); err != nil {
return "", err
}
}
// main 包入口
{
main_init := p.getFunc("main.init")
main_main := p.getFunc("main.main")
mainFunc := p.module.NewFunc("main", lltypes.I32)
mainFuncBlock := mainFunc.NewBlock("entry")
mainFuncBlock.NewCall(main_init)
mainFuncBlock.NewCall(main_main)
mainFuncBlock.NewRet(llconstant.NewInt(lltypes.I32, 0))
}
// 输出 LLIR 文件
return p.module.String(), nil
}
func (p *Compiler) compilePackage(pkg *ssa.Package) (err error) {
// 已经编译过
if p.compilePkgDoneMap[pkg] {
return nil
}
// 成功编译后记录状态
defer func() {
if err == nil {
p.compilePkgDoneMap[pkg] = true
}
}()
// 先编译导入的包
for _, importPkg := range pkg.Pkg.Imports() {
ssaPkg := p.prog.Pkgs[importPkg.Path()].SSAPkg
if err := p.compilePackage(ssaPkg); err != nil {
return err
}
}
// 定义类型
for _, member := range pkg.Members {
if typ, ok := member.(*ssa.Type); ok {
if err := p.compileType(pkg, typ); err != nil {
return err
}
}
}
// 定义常量
for _, member := range pkg.Members {
if namedConst, ok := member.(*ssa.NamedConst); ok {
if err := p.compileNamedConst(pkg, namedConst); err != nil {
return err
}
}
}
// 定义全局变量
for _, member := range pkg.Members {
if g, ok := member.(*ssa.Global); ok {
if err := p.compileGlobal(pkg, g); err != nil {
return err
}
}
}
// 声明函数
for _, member := range pkg.Members {
if fn, ok := member.(*ssa.Function); ok {
if err := p.compileFuncDeclare(pkg, fn); err != nil {
return err
}
}
}
// 定义函数
for _, member := range pkg.Members {
if fn, ok := member.(*ssa.Function); ok {
if err := p.compileFunc(fn); err != nil {
return err
}
}
}
return nil
}
func (p *Compiler) compileNamedConst(pkg *ssa.Package, namedConst *ssa.NamedConst) error {
return nil
}
func (p *Compiler) compileGlobal(pkg *ssa.Package, g *ssa.Global) error {
p.defGlobal(g)
return nil
}
func (p *Compiler) compileFuncDeclare(pkg *ssa.Package, fn *ssa.Function) error {
logger.Tracef(&config.EnableTrace_compiler, "pkgpath:%s, name=%s", fn.Pkg.Pkg.Path(), fn.Pkg.Pkg.Name())
var mangledName string
if pkgName := fn.Pkg.Pkg.Name(); pkgName == "main" || pkgName == "" {
mangledName = fmt.Sprintf("%s.%s", "main", fn.Name())
} else {
mangledName = fmt.Sprintf("%s.%s", pkg.Pkg.Path(), fn.Name())
}
p.curFunc = p.getFunc(mangledName)
if p.curFunc == nil {
fnType := p.toLLFuncType(fn.Signature)
fnParams := []*llir.Param{}
for i, typ := range fnType.Params {
fnParams = append(fnParams, llir.NewParam(fmt.Sprint(i), typ))
}
p.curFunc = p.module.NewFunc(mangledName, fnType.RetType, fnParams...)
}
return nil
}
func (p *Compiler) compileFunc(fn *ssa.Function) error {
logger.Tracef(&config.EnableTrace_compiler, "pkgpath=%s, name=%s", fn.Pkg.Pkg.Path(), fn.Pkg.Pkg.Name())
var mangledName string
if pkgName := fn.Pkg.Pkg.Name(); pkgName == "main" || pkgName == "" {
mangledName = fmt.Sprintf("%s.%s", "main", fn.Name())
} else {
mangledName = fmt.Sprintf("%s.%s", fn.Pkg.Pkg.Path(), fn.Name())
}
p.curFunc = p.getFunc(mangledName)
if p.curFunc == nil {
fnType := p.toLLFuncType(fn.Signature)
fnParams := []*llir.Param{}
for i, typ := range fnType.Params {
fnParams = append(fnParams, llir.NewParam(fmt.Sprint(i), typ))
}
p.curFunc = p.module.NewFunc(mangledName, fnType.RetType, fnParams...)
}
p.curLocals = make(map[ssa.Value]llvalue.Value)
p.curBlockEntries = make(map[*ssa.BasicBlock]*llir.Block)
p.phis = make(map[*ssa.Phi]*llir.InstPhi)
for _, block := range fn.Blocks {
p.curBlockEntries[block] = p.curFunc.NewBlock(fmt.Sprintf("block_%04d", block.Index))
}
for _, block := range fn.Blocks {
if err := p.compileBlock(block); err != nil {
return err
}
}
// fix phis
for expr, phi := range p.phis {
var incomings []*llir.Incoming
for i, edge := range expr.Edges {
x := p.getValue(edge)
pred := p.curBlockEntries[expr.Block().Preds[i]]
incomings = append(incomings, llir.NewIncoming(x, pred))
}
phi.Incs = incomings
}
return nil
}
func (p *Compiler) compileBlock(block *ssa.BasicBlock) error {
llirBlock := p.curBlockEntries[block]
if llirBlock == nil {
panic("unreachable")
}
for _, ins := range block.Instrs {
if err := p.compileInstruction(ins); err != nil {
return err
}
}
if llirBlock.Term == nil {
llirBlock.Term = llir.NewUnreachable()
}
return nil
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"fmt"
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/config"
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/ssa"
)
func (p *Compiler) defineBuiltin() error {
// syscall: int write(i32 fd, void* buf, int n)
p.module.NewFunc("write",
lltypes.I64,
llir.NewParam("fd", lltypes.I32),
llir.NewParam("buf", lltypes.NewPointer(lltypes.I8)),
llir.NewParam("size", lltypes.I64),
)
p.module.NewTypeDef(g_typ_complex64_name,
lltypes.NewStruct(lltypes.Float, lltypes.Float),
)
p.module.NewTypeDef(g_typ_complex128_name,
lltypes.NewStruct(lltypes.Double, lltypes.Double),
)
p.module.NewTypeDef(g_typ_string_name,
lltypes.NewStruct(lltypes.NewPointer(lltypes.I8), lltypes.I64),
)
p.module.NewFunc("ugo_print_rune",
lltypes.I32,
llir.NewParam("x", lltypes.I32),
)
p.module.NewFunc("ugo_print_bool",
lltypes.I32,
llir.NewParam("x", lltypes.I8),
)
p.module.NewFunc("ugo_print_int",
lltypes.I32,
llir.NewParam("x", lltypes.I32),
)
p.module.NewFunc("ugo_print_int64",
lltypes.I32,
llir.NewParam("x", lltypes.I64),
)
p.module.NewFunc("ugo_print_ptr",
lltypes.I32,
llir.NewParam("p", lltypes.I8Ptr),
)
p.module.NewFunc("ugo_print_cstring",
lltypes.I32,
llir.NewParam("s", lltypes.NewPointer(lltypes.I8)),
)
p.module.NewFunc("ugo_print_cstring_len",
lltypes.I32,
llir.NewParam("s", lltypes.NewPointer(lltypes.I8)),
llir.NewParam("n", lltypes.I32),
)
fn := p.module.NewFunc("ugo_printf",
lltypes.I32,
llir.NewParam("format", lltypes.NewPointer(lltypes.I8)),
)
fn.Sig.Variadic = true
p.module.NewFunc("ugo_cstring_join",
lltypes.NewPointer(lltypes.I8),
llir.NewParam("s0", lltypes.NewPointer(lltypes.I8)),
llir.NewParam("s1", lltypes.NewPointer(lltypes.I8)),
)
p.module.NewFunc("ugo_cstring_slice",
lltypes.NewPointer(lltypes.I8),
llir.NewParam("s", lltypes.NewPointer(lltypes.I8)),
llir.NewParam("low", lltypes.I32),
llir.NewParam("high", lltypes.I32),
)
p.module.NewFunc("ugo_cstring_index",
lltypes.I32,
llir.NewParam("s", lltypes.NewPointer(lltypes.I8)),
llir.NewParam("idx", lltypes.I32),
)
p.module.NewFunc("ugo_cstring_cmp",
lltypes.I32,
llir.NewParam("s0", lltypes.NewPointer(lltypes.I8)),
llir.NewParam("s1", lltypes.NewPointer(lltypes.I8)),
)
p.module.NewFunc("ugo_string_new",
lltypes.NewPointer(
p.getLLType(g_typ_string_name),
),
llir.NewParam("size", lltypes.I32),
llir.NewParam("data", lltypes.NewPointer(lltypes.I8)),
)
p.module.NewFunc("ugo_print_string", lltypes.I32,
llir.NewParam("s", lltypes.NewPointer(
p.getLLType(g_typ_string_name),
)),
)
return nil
}
func (p *Compiler) callBuiltin(expr *ssa.Call, builtin *ssa.Builtin) llvalue.Value {
logger.Tracef(&config.EnableTrace_compiler, "expr=%v, builtin=%v", expr, builtin)
switch builtin.Name() {
case "print", "println":
for i, arg := range expr.Common().Args {
if i > 0 {
p.builtin_print_space(expr, builtin)
}
arg := p.getValue(arg)
if p.llIsStrType(arg.Type()) {
p.builtin_print_str(expr, builtin, arg)
continue
}
switch typ := arg.Type().(type) {
case *lltypes.IntType:
switch typ.BitSize {
case 32:
p.builtin_print_int(expr, builtin, arg)
case 64:
p.builtin_print_int64(expr, builtin, arg)
}
default:
// todo: string => *lltypes.StructType
fmt.Printf("callBuiltin: %T, %v\n", typ, p.llIsStrType(typ))
}
}
if builtin.Name() == "println" {
p.builtin_print_newline(expr, builtin)
}
return nil
}
return nil
}
func (p *Compiler) builtin_print_str(expr *ssa.Call, builtin *ssa.Builtin, arg llvalue.Value) llvalue.Value {
llirBlock := p.curBlockEntries[expr.Block()]
switch x := arg.(type) {
case *llir.Param:
logger.Panicf("TODO: arg: %T, %v", arg, arg)
panic("unreachable")
case *llconstant.Struct:
data := x.Fields[0].(*llconstant.CharArray)
_p0 := llirBlock.NewAlloca(data.Typ)
llirBlock.NewStore(data, _p0)
_p_data00 := llirBlock.NewGetElementPtr(
data.Typ, _p0,
llconstant.NewInt(lltypes.I64, 0),
llconstant.NewInt(lltypes.I64, 0),
)
_size32 := llconstant.NewInt(lltypes.I32, int64(len(data.X)))
llirBlock.NewCall(p.getFunc("ugo_print_cstring_len"), _p_data00, _size32)
return nil
default:
logger.Panicf("arg: %T, %v", arg, arg)
panic("unreachable")
}
}
func (p *Compiler) builtin_print_newline(expr *ssa.Call, builtin *ssa.Builtin) llvalue.Value {
llirBlock := p.curBlockEntries[expr.Block()]
llirBlock.NewCall(p.getFunc("ugo_print_rune"), llconstant.NewInt(lltypes.I32, '\n'))
return nil
}
func (p *Compiler) builtin_print_int(expr *ssa.Call, builtin *ssa.Builtin, arg llvalue.Value) llvalue.Value {
llirBlock := p.curBlockEntries[expr.Block()]
llirBlock.NewCall(p.getFunc("ugo_print_int"), arg)
return nil
}
func (p *Compiler) builtin_print_int64(expr *ssa.Call, builtin *ssa.Builtin, arg llvalue.Value) llvalue.Value {
llirBlock := p.curBlockEntries[expr.Block()]
llirBlock.NewCall(p.getFunc("ugo_print_int64"), arg)
return nil
}
func (p *Compiler) builtin_print_rune(expr *ssa.Call, builtin *ssa.Builtin, arg rune) llvalue.Value {
llirBlock := p.curBlockEntries[expr.Block()]
llirBlock.NewCall(p.getFunc("ugo_print_rune"), llconstant.NewInt(lltypes.I32, int64(arg)))
return nil
}
func (p *Compiler) builtin_print_space(expr *ssa.Call, builtin *ssa.Builtin) llvalue.Value {
llirBlock := p.curBlockEntries[expr.Block()]
llirBlock.NewCall(p.getFunc("ugo_print_rune"), llconstant.NewInt(lltypes.I32, ' '))
return nil
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"fmt"
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/logger"
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/types"
)
func (p *Compiler) getLLType(typName string) lltypes.Type {
for _, typ := range p.module.TypeDefs {
if typ.Name() == typName {
return typ
}
}
return nil
}
func (p *Compiler) getLLFunc(fnName string) *llir.Func {
for _, x := range p.module.Funcs {
if x.Name() == fnName {
return x
}
}
return nil
}
// 定义全局变量
func (p *Compiler) defGlobal(g *ssa.Global) {
mangledName := fmt.Sprintf("%s.%s", g.Pkg.Pkg.Path(), g.Name())
// 全局变量类似一个地址, 需要取其指向的元素类型
typ := p.toLLType(g.Type().(*types.Pointer).Elem())
glob := p.module.NewGlobal(mangledName, typ)
glob.Init = llconstant.NewZeroInitializer(typ)
}
// 根据名字查询全局变量
func (p *Compiler) getGlobal(g *ssa.Global) *llir.Global {
mangledName := fmt.Sprintf("%s.%s", g.Pkg.Pkg.Path(), g.Name())
for _, x := range p.module.Globals {
if x.Name() == mangledName {
return x
}
}
return nil
}
func (p *Compiler) getLocal(expr ssa.Value) llvalue.Value {
x, ok := p.curLocals[expr]
if !ok {
logger.Debugln(expr, "not found")
}
return x
}
func (p *Compiler) defLocal(block *llir.Block, expr ssa.Value) llvalue.Value {
if x, ok := p.curLocals[expr]; ok {
return x
}
x := block.NewAlloca(p.toLLType(expr.Type()))
p.curLocals[expr] = x
return x
}
func (p *Compiler) getFunc(name string) *llir.Func {
for _, fn := range p.module.Funcs {
if fn.Name() == name {
return fn
}
}
return nil
}
func (p *Compiler) mustGetFunc(name string) *llir.Func {
if fn := p.getFunc(name); fn != nil {
return fn
}
panic(fmt.Sprintf("mustGetFunc: %s not found", name))
}
func (p *Compiler) getBlock(name string) *llir.Block {
if p.curFunc == nil {
return nil
}
for _, block := range p.curFunc.Blocks {
if block.Name() == name {
return block
}
}
return nil
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"fmt"
"github.com/wa-lang/wa/internal/ssa"
)
func (p *Compiler) compileInstruction(ins ssa.Instruction) error {
switch ins := ins.(type) {
default:
return p.compileInstruction_value(ins)
case *ssa.DebugRef:
return p.compileInstruction_DebugRef(ins)
case *ssa.Defer:
return p.compileInstruction_Defer(ins)
case *ssa.If:
return p.compileInstruction_If(ins)
case *ssa.Jump:
return p.compileInstruction_Jump(ins)
case *ssa.MapUpdate:
return p.compileInstruction_MapUpdate(ins)
case *ssa.Panic:
return p.compileInstruction_Panic(ins)
case *ssa.Return:
return p.compileInstruction_Return(ins)
case *ssa.RunDefers:
return p.compileInstruction_RunDefers(ins)
case *ssa.Store:
return p.compileInstruction_Store(ins)
}
}
func (p *Compiler) compileInstruction_value(ins ssa.Instruction) error {
if ssaValue, ok := ins.(ssa.Value); ok {
p.curLocals[ssaValue] = p.getValue(ssaValue)
return nil
}
return fmt.Errorf("unknown Instruction(%T)", ins)
}
func (p *Compiler) compileInstruction_DebugRef(ins *ssa.DebugRef) error {
panic("TODO: *ssa.DebugRef")
}
func (p *Compiler) compileInstruction_Defer(ins *ssa.Defer) error {
panic("TODO: *ssa.Defer")
}
func (p *Compiler) compileInstruction_If(ins *ssa.If) error {
llirBlock := p.curBlockEntries[ins.Block()]
cond := p.getValue(ins.Cond)
blockTrue := p.curBlockEntries[ins.Block().Succs[0]]
blockElse := p.curBlockEntries[ins.Block().Succs[1]]
llirBlock.NewCondBr(cond, blockTrue, blockElse)
return nil
}
func (p *Compiler) compileInstruction_Jump(ins *ssa.Jump) error {
llirBlock := p.curBlockEntries[ins.Block()]
blockJump := p.curBlockEntries[ins.Block().Succs[0]]
llirBlock.NewBr(blockJump)
return nil
}
func (p *Compiler) compileInstruction_MapUpdate(ins *ssa.MapUpdate) error {
panic("TODO: *ssa.MapUpdate")
}
func (p *Compiler) compileInstruction_Panic(ins *ssa.Panic) error {
panic("TODO: *ssa.Panic")
}
func (p *Compiler) compileInstruction_Return(ins *ssa.Return) error {
llirBlock := p.curBlockEntries[ins.Block()]
switch {
case len(ins.Results) == 0:
llirBlock.NewRet(nil)
case len(ins.Results) == 1:
llirBlock.NewRet(p.getValue(ins.Results[0]))
default:
return fmt.Errorf("todo: Multiple return values")
}
return nil
}
func (p *Compiler) compileInstruction_RunDefers(ins *ssa.RunDefers) error {
panic("TODO: *ssa.RunDefers")
}
func (p *Compiler) compileInstruction_Store(ins *ssa.Store) error {
llirBlock := p.curBlockEntries[ins.Block()]
dst := p.getValue(ins.Addr)
src := p.getValue(ins.Val)
llirBlock.NewStore(src, dst)
return nil
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"fmt"
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/llenum"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/token"
)
func (p *Compiler) getValue(expr ssa.Value) (v llvalue.Value) {
if x, ok := p.curLocals[expr]; ok {
return x
}
defer func() {
p.curLocals[expr] = v
}()
switch expr := expr.(type) {
case *ssa.Const:
return p.compileValue_Const(expr)
case *ssa.Function:
return p.compileValue_Function(expr)
case *ssa.Global:
return p.compileValue_Global(expr)
case *ssa.Convert:
return p.compileValue_Convert(expr)
case *ssa.UnOp:
return p.compileValue_UnOp(expr)
case *ssa.Parameter:
return p.compileValue_Parameter(expr)
case *ssa.BinOp:
return p.compileValue_BinOp(expr)
case *ssa.Phi:
return p.compileValue_Phi(expr)
case *ssa.Call:
return p.compileValue_Call(expr)
}
fmt.Printf("todo: Compiler.getValue(expr.type=%T, expr.val=%+v)\n", expr, expr)
return nil
}
func (p *Compiler) compileValue_Const(expr *ssa.Const) (v llvalue.Value) {
return p.constValue(expr)
}
func (p *Compiler) compileValue_Function(expr *ssa.Function) (v llvalue.Value) {
panic("TODO")
}
func (p *Compiler) compileValue_Global(expr *ssa.Global) (v llvalue.Value) {
return p.getGlobal(expr)
}
func (p *Compiler) compileValue_Convert(expr *ssa.Convert) (v llvalue.Value) {
llirBlock := p.curBlockEntries[expr.Block()]
return llirBlock.NewTrunc(p.getValue(expr.X), p.toLLType(expr.Type()))
}
func (p *Compiler) compileValue_UnOp(expr *ssa.UnOp) (v llvalue.Value) {
llirBlock := p.curBlockEntries[expr.Block()]
switch expr.Op {
case token.MUL:
return llirBlock.NewLoad(p.toLLType(expr.Type()), p.getValue(expr.X))
default:
panic("TODO")
}
}
func (p *Compiler) compileValue_Parameter(expr *ssa.Parameter) (v llvalue.Value) {
for i, x := range expr.Parent().Params {
if x == expr {
return p.curFunc.Params[i]
}
}
return nil
}
func (p *Compiler) compileValue_BinOp(expr *ssa.BinOp) (v llvalue.Value) {
llirBlock := p.curBlockEntries[expr.Block()]
switch expr.Op {
case token.ADD:
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isStrType(expr.X.Type()) {
llirBlock := p.curBlockEntries[expr.Block()]
return llirBlock.NewCall(p.getLLFunc("ugo_cstring_join"), x, y)
}
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFAdd(x, y)
}
return llirBlock.NewAdd(x, y)
case token.SUB:
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFSub(x, y)
}
return llirBlock.NewSub(x, y)
case token.MUL:
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFMul(x, y)
}
return llirBlock.NewMul(x, y)
case token.QUO:
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFDiv(x, y)
}
return llirBlock.NewSDiv(x, y)
case token.REM: // %
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFRem(x, y)
}
return llirBlock.NewSRem(x, y)
case token.EQL: // ==
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isStrType(expr.X.Type()) {
llirBlock := p.curBlockEntries[expr.Block()]
cmpRet := llirBlock.NewCall(p.getLLFunc("ugo_cstring_cmp"), x, y)
cond := llirBlock.NewICmp(llenum.IPredNE, cmpRet, llconstant.NewInt(lltypes.I32, 0))
return cond
}
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFCmp(llenum.FPredOEQ, x, y)
}
return llirBlock.NewICmp(llenum.IPredEQ, x, y)
case token.NEQ: // !=
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isStrType(expr.X.Type()) {
llirBlock := p.curBlockEntries[expr.Block()]
cmpRet := llirBlock.NewCall(p.getLLFunc("ugo_cstring_cmp"), x, y)
cond := llirBlock.NewICmp(llenum.IPredEQ, cmpRet, llconstant.NewInt(lltypes.I32, 0))
return cond
}
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFCmp(llenum.FPredONE, x, y)
}
return llirBlock.NewICmp(llenum.IPredNE, x, y)
case token.LSS: // <
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFCmp(llenum.FPredOLT, x, y)
}
return llirBlock.NewICmp(llenum.IPredSLT, x, y)
case token.GTR: // >
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFCmp(llenum.FPredOGT, x, y)
}
return llirBlock.NewICmp(llenum.IPredSGT, x, y)
case token.LEQ: // <=
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFCmp(llenum.FPredOLE, x, y)
}
return llirBlock.NewICmp(llenum.IPredSLE, x, y)
case token.GEQ: // <=
x := p.getValue(expr.X)
y := p.getValue(expr.Y)
if p.isFloatType(expr.X.Type()) {
return llirBlock.NewFCmp(llenum.FPredOGE, x, y)
}
return llirBlock.NewICmp(llenum.IPredSGE, x, y)
}
panic(fmt.Sprintf("TODO: op: %+v", expr.Op))
}
func (p *Compiler) compileValue_Phi(expr *ssa.Phi) (v llvalue.Value) {
llirBlock := p.curBlockEntries[expr.Block()]
var incomings []*llir.Incoming
for i, edge := range expr.Edges {
x := p.zeroValue(edge.Type())
pred := p.curBlockEntries[expr.Block().Preds[i]]
incomings = append(incomings, llir.NewIncoming(x, pred))
}
phi := llirBlock.NewPhi(incomings...)
p.phis[expr] = phi
return phi
}
func (p *Compiler) compileValue_Call(expr *ssa.Call) (v llvalue.Value) {
if builtin, ok := expr.Call.Value.(*ssa.Builtin); ok {
return p.callBuiltin(expr, builtin)
}
if expr.Call.Method == nil {
if fn, ok := expr.Call.Value.(*ssa.Function); ok {
var mangledName string
if fn.Pkg.Pkg.Name() == "main" {
mangledName = fmt.Sprintf("%s.%s", fn.Pkg.Pkg.Name(), fn.Name())
} else {
mangledName = fmt.Sprintf("%s.%s", fn.Pkg.Pkg.Path(), fn.Name())
}
fn := p.getFunc(mangledName)
var args []llvalue.Value
for _, arg := range expr.Common().Args {
args = append(args, p.getValue(arg))
}
llirBlock := p.curBlockEntries[expr.Block()]
return llirBlock.NewCall(fn, args...)
}
}
panic("TODO")
}
package compiler
import "github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
func (p *Compiler) llGetNamedType(mangledName string) lltypes.Type {
return p.llNamedTypeMap[mangledName]
}
func (p *Compiler) llGetTypeName(typ lltypes.Type) string {
return p.llTypeNameMap[typ]
}
func (p *Compiler) llRegTypeName(typ lltypes.Type, name string) {
p.llTypeNameMap[typ] = name
p.llNamedTypeMap[name] = typ
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/types"
)
func (p *Compiler) compileType(pkg *ssa.Package, typMember *ssa.Type) error {
if typ, ok := typMember.Type().(*types.Named); ok {
if ty, ok := typ.Underlying().(*types.Struct); ok {
p.module.NewTypeDef(typ.Obj().Id(), p.toLLType(ty))
}
}
return nil
}
func (p *Compiler) isBoolType(typ types.Type) bool {
if t, ok := typ.Underlying().(*types.Basic); ok {
return t.Info()&types.IsBoolean != 0
}
return false
}
func (p *Compiler) isIntType(typ types.Type) bool {
if t, ok := typ.Underlying().(*types.Basic); ok {
return t.Info()&types.IsInteger != 0
}
return false
}
func (p *Compiler) isUIntType(typ types.Type) bool {
if t, ok := typ.Underlying().(*types.Basic); ok {
return t.Info()&types.IsUnsigned != 0
}
return false
}
func (p *Compiler) isFloatType(typ types.Type) bool {
if t, ok := typ.Underlying().(*types.Basic); ok {
return t.Info()&types.IsFloat != 0
}
return false
}
func (p *Compiler) isComplexType(typ types.Type) bool {
if t, ok := typ.Underlying().(*types.Basic); ok {
return t.Info()&types.IsComplex != 0
}
return false
}
func (p *Compiler) isStrType(typ types.Type) bool {
if t, ok := typ.Underlying().(*types.Basic); ok {
return t.Info()&types.IsString != 0
}
return false
}
func (p *Compiler) llIsStrType(typ lltypes.Type) bool {
for _, t := range p.module.TypeDefs {
if t == typ {
return t.Name() == g_typ_string_name
}
}
return false
}
func (p *Compiler) waIsStrType(typ types.Type) bool {
if x, ok := typ.(*types.Basic); ok {
if x.Kind() == types.String || x.Kind() == types.UntypedString {
return true
}
}
return false
}
func (p *Compiler) waIsComplexType(typ types.Type) bool {
if x, ok := typ.(*types.Basic); ok {
if x.Kind() == types.Complex64 || x.Kind() == types.Complex128 {
return true
}
}
return false
}
func (p *Compiler) isPointerType(typ types.Type) bool {
if _, ok := typ.(*types.Pointer); ok {
return true
} else if typ, ok := typ.(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
return true
} else {
return false
}
}
func (p *Compiler) toLLFuncType(t types.Type) *lltypes.FuncType {
return p.toLLType(t).(*lltypes.FuncType)
}
func (p *Compiler) toLLType(t types.Type) lltypes.Type {
switch t := t.(type) {
case *types.Basic:
switch t.Kind() {
case types.Int, types.Uint:
return lltypes.I64
case types.Uintptr:
return lltypes.I64
case types.UnsafePointer:
return lltypes.NewPointer(nil)
case types.Bool, types.UntypedBool:
return lltypes.I1
case types.Int8, types.Uint8:
return lltypes.I8
case types.Int16, types.Uint16:
return lltypes.I16
case types.Int32, types.Uint32:
return lltypes.I32
case types.Int64, types.Uint64:
return lltypes.I64
case types.Float32:
return lltypes.Float
case types.Float64:
return lltypes.Double
case types.Complex64:
structType := lltypes.NewStruct(lltypes.Float, lltypes.Float)
return structType
case types.Complex128:
return lltypes.NewStruct(lltypes.Double, lltypes.Double)
case types.String, types.UntypedString:
return p.getLLType(g_typ_string_name)
default:
panic("unreachable")
}
case *types.Pointer:
return lltypes.NewPointer(p.toLLType(t.Elem()))
case *types.Array:
return lltypes.NewArray(uint64(t.Len()), p.toLLType(t.Elem()))
case *types.Slice:
return lltypes.NewStruct(
p.toLLType(t.Elem()),
lltypes.I64, // len
lltypes.I64, // cap
)
case *types.Struct:
fields := make([]lltypes.Type, t.NumFields())
for i := 0; i < t.NumFields(); i++ {
fields[i] = p.toLLType(t.Field(i).Type())
}
return lltypes.NewStruct(fields...)
case *types.Tuple:
fields := make([]lltypes.Type, t.Len())
for i := 0; i < t.Len(); i++ {
fields[i] = p.toLLType(t.At(i).Type())
}
return lltypes.NewStruct(fields...)
case *types.Map:
// todo
case *types.Interface:
// todo
case *types.Named:
if st, ok := t.Underlying().(*types.Struct); ok {
fields := make([]lltypes.Type, st.NumFields())
for i := 0; i < st.NumFields(); i++ {
fields[i] = p.toLLType(st.Field(i).Type())
}
t2 := lltypes.NewStruct(fields...)
// t2.TypeName = "TODO"
return t2
}
return p.toLLType(t.Underlying())
case *types.Signature:
var returnType lltypes.Type
switch t.Results().Len() {
case 0:
returnType = lltypes.Void
case 1:
returnType = p.toLLType(t.Results().At(0).Type())
default:
fields := make([]lltypes.Type, t.Results().Len())
for i := 0; i < t.Results().Len(); i++ {
fields[i] = p.toLLType(t.Results().At(i).Type())
}
returnType = lltypes.NewStruct(fields...)
}
var paramTypes []lltypes.Type
if t.Recv() != nil {
recv := p.toLLType(t.Recv().Type())
paramTypes = append(paramTypes, recv)
}
for i := 0; i < t.Params().Len(); i++ {
subType := p.toLLType(t.Params().At(i).Type())
paramTypes = append(paramTypes, subType)
}
return lltypes.NewFunc(returnType, paramTypes...)
default:
panic("unknown type: " + t.String())
}
return nil
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/constant"
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/types"
)
// 暂时全部用 I64 表示 int 和 指针
func (p *Compiler) constValue(expr *ssa.Const) llvalue.Value {
t := expr.Type().Underlying()
switch t := t.(type) {
case *types.Basic:
switch t.Kind() {
case types.Int, types.Uint:
n, _ := constant.Int64Val(expr.Value)
return llconstant.NewInt(lltypes.I64, n)
case types.Uintptr:
n, _ := constant.Int64Val(expr.Value)
return llconstant.NewInt(lltypes.I64, n)
case types.Bool, types.UntypedBool:
return llconstant.NewBool(constant.BoolVal(expr.Value))
case types.Int8, types.Uint8:
n, _ := constant.Int64Val(expr.Value)
return llconstant.NewInt(lltypes.I8, n)
case types.Int16, types.Uint16:
n, _ := constant.Int64Val(expr.Value)
return llconstant.NewInt(lltypes.I16, n)
case types.Int32, types.Uint32:
n, _ := constant.Int64Val(expr.Value)
return llconstant.NewInt(lltypes.I32, n)
case types.Int64, types.Uint64:
n, _ := constant.Int64Val(expr.Value)
return llconstant.NewInt(lltypes.I64, n)
case types.Float32:
v, _ := constant.Float64Val(expr.Value)
return llconstant.NewFloat(lltypes.Float, v)
case types.Float64:
v, _ := constant.Float64Val(expr.Value)
return llconstant.NewFloat(lltypes.Double, v)
case types.Complex64:
real_v, _ := constant.Float64Val(constant.Real(expr.Value))
imag_v, _ := constant.Float64Val(constant.Imag(expr.Value))
return llconstant.NewStruct(
p.getLLType(g_typ_complex64_name).(*lltypes.StructType),
llconstant.NewFloat(lltypes.Float, real_v),
llconstant.NewFloat(lltypes.Float, imag_v),
)
case types.Complex128:
real_v, _ := constant.Float64Val(constant.Real(expr.Value))
imag_v, _ := constant.Float64Val(constant.Imag(expr.Value))
return llconstant.NewStruct(
p.getLLType(g_typ_complex128_name).(*lltypes.StructType),
llconstant.NewFloat(lltypes.Double, real_v),
llconstant.NewFloat(lltypes.Double, imag_v),
)
case types.String, types.UntypedString:
s := constant.StringVal(expr.Value)
return llconstant.NewStruct(
p.getLLType(g_typ_string_name).(*lltypes.StructType),
llconstant.NewCharArray(append([]byte(s), 0)),
llconstant.NewInt(lltypes.I64, int64(len(s)+1)),
)
}
}
panic("unknown const type: " + t.String())
}
// 版权 @2021 凹语言 作者。保留所有权利。
package compiler
import (
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/types"
)
func (p *Compiler) zeroValue(t types.Type) llvalue.Value {
switch t := t.(type) {
case *types.Basic:
switch t.Kind() {
case types.Int, types.Uint:
return llconstant.NewInt(lltypes.I64, 0)
case types.Uintptr:
return llconstant.NewInt(lltypes.I64, 0)
case types.Bool, types.UntypedBool:
return llconstant.NewBool(false)
case types.Int8, types.Uint8:
return llconstant.NewInt(lltypes.I8, 0)
case types.Int16, types.Uint16:
return llconstant.NewInt(lltypes.I16, 0)
case types.Int32, types.Uint32:
return llconstant.NewInt(lltypes.I32, 0)
case types.Int64, types.Uint64:
return llconstant.NewInt(lltypes.I64, 102) // todo: debug
case types.Float32:
return llconstant.NewFloat(lltypes.Float, 0)
case types.Float64:
return llconstant.NewFloat(lltypes.Double, 0)
case types.Complex64:
return llconstant.NewStruct(
lltypes.NewStruct(lltypes.Float, lltypes.Float),
llconstant.NewFloat(lltypes.Float, 0),
llconstant.NewFloat(lltypes.Float, 0),
)
case types.Complex128:
return llconstant.NewStruct(
lltypes.NewStruct(lltypes.Double, lltypes.Double),
llconstant.NewFloat(lltypes.Double, 0),
llconstant.NewFloat(lltypes.Double, 0),
)
case types.String, types.UntypedString:
return llconstant.NewStruct(
p.getLLType(g_typ_string_name).(*lltypes.StructType),
llconstant.NewCharArray(append([]byte(""), 0)),
llconstant.NewInt(lltypes.I64, 0),
)
}
}
panic("unknown const type: " + t.String())
}
// 版权 @2021 凹语言 作者。保留所有权利。
package llutil
import (
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
)
func GetType(m *llir.Module, typName string) lltypes.Type {
for _, typ := range m.TypeDefs {
if typ.Name() == typName {
return typ
}
}
return nil
}
func GetFunc(m *llir.Module, fnName string) *llir.Func {
for _, x := range m.Funcs {
if x.Name() == fnName {
return x
}
}
return nil
}
func PtrElemType(src llvalue.Value) lltypes.Type {
return src.Type().(*lltypes.PointerType).ElemType
}
func StrConstant(in string) *llconstant.CharArray {
return llconstant.NewCharArray(append([]byte(in), 0))
}
func StrToi8Ptr(block *llir.Block, src llvalue.Value) *llir.InstGetElementPtr {
return block.NewGetElementPtr(
PtrElemType(src), src,
llconstant.NewInt(lltypes.I32, 0),
llconstant.NewInt(lltypes.I32, 0),
)
}
func StrLen(block *llir.Block, src llvalue.Value) llvalue.Value {
if _, ok := src.Type().(*lltypes.PointerType); ok {
l := block.NewGetElementPtr(
PtrElemType(src), src,
llconstant.NewInt(lltypes.I32, 0),
llconstant.NewInt(lltypes.I32, 0),
)
return block.NewLoad(PtrElemType(l), l)
}
return block.NewExtractValue(src, 0)
}
func StrToI8Ptr(block *llir.Block, src llvalue.Value) llvalue.Value {
if _, ok := src.Type().(*lltypes.PointerType); ok {
l := block.NewGetElementPtr(
PtrElemType(src), src,
llconstant.NewInt(lltypes.I32, 0),
llconstant.NewInt(lltypes.I32, 1),
)
return block.NewLoad(PtrElemType(l), l)
}
return block.NewExtractValue(src, 1)
}
func Slice(itemType lltypes.Type) *lltypes.StructType {
return lltypes.NewStruct(
lltypes.I32, // Len
lltypes.I32, // Cap
lltypes.I32, // Array Offset
lltypes.NewPointer(itemType), // Content
)
}
func String() *lltypes.StructType {
return lltypes.NewStruct(
lltypes.NewPointer(lltypes.I8), // Content
lltypes.I32, // String length
)
}
func StringLen(stringType lltypes.Type) *llir.Func {
param := llir.NewParam("input", stringType)
res := llir.NewFunc("string_len", lltypes.I64, param)
block := res.NewBlock("entry")
block.NewRet(block.NewExtractValue(param, 0))
return res
}
package compiler
const (
g_typ_string_name = "ugo_string_t"
g_typ_complex64_name = "ugo_complex64_t"
g_typ_complex128_name = "ugo_complex128_t"
)
package syscall
import (
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/backends/compiler_ll/llutil"
)
func Print(block *llir.Block, value llvalue.Value, goos string) {
asmFunc := llir.NewInlineAsm(
lltypes.NewPointer(lltypes.NewFunc(lltypes.I64)),
"syscall", "=r,{rax},{rdi},{rsi},{rdx}",
)
asmFunc.SideEffect = true
strPtr := llutil.StrToI8Ptr(block, value)
strLen := llutil.StrLen(block, value)
block.NewCall(asmFunc,
llconstant.NewInt(lltypes.I64, Convert(WRITE, goos)), // rax
llconstant.NewInt(lltypes.I64, 1), // rdi, stdout
strPtr, // rsi
strLen, // rdx
)
}
package syscall
// https://opensource.apple.com/source/xnu/xnu-2782.20.48/bsd/kern/syscalls.master
type fn string
const (
EXIT fn = "EXIT"
WRITE fn = "WRITE"
)
var convDarwin = map[fn]int64{
EXIT: 0x2000001,
WRITE: 0x2000004,
}
var convLinux = map[fn]int64{
EXIT: 60,
WRITE: 1,
}
func Convert(f fn, goos string) int64 {
switch goos {
case "darwin":
return convDarwin[f]
case "linux":
return convLinux[f]
default:
panic("unknown goos")
}
}
package types
import "github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
var (
I8 = &Int{Type: lltypes.I8, TypeName: "int8", TypeSize: 8 / 8, Signed: true}
U8 = &Int{Type: lltypes.I8, TypeName: "uint8", TypeSize: 8 / 8}
I16 = &Int{Type: lltypes.I16, TypeName: "int16", TypeSize: 18 / 8, Signed: true}
U16 = &Int{Type: lltypes.I16, TypeName: "uint16", TypeSize: 18 / 8}
I32 = &Int{Type: lltypes.I32, TypeName: "int32", TypeSize: 32 / 8, Signed: true}
U32 = &Int{Type: lltypes.I32, TypeName: "uint32", TypeSize: 32 / 8}
I64 = &Int{Type: lltypes.I64, TypeName: "int64", TypeSize: 64 / 8, Signed: true}
U64 = &Int{Type: lltypes.I64, TypeName: "uint64", TypeSize: 64 / 8}
Uintptr = &Int{Type: lltypes.I64, TypeName: "uintptr", TypeSize: 64 / 8}
Void = &VoidType{}
Bool = &BoolType{}
String = &StringType{}
)
package types
import (
"fmt"
"sort"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
)
type Interface struct {
backingType
SourceName string
RequiredMethods map[string]InterfaceMethod
}
func (i Interface) Name() string {
return fmt.Sprintf("interface(%s)", i.SourceName)
}
// SortedRequiredMethods returns a sorted slice of all method names
// The returned order is the order the methods will be layed out in the JumpTable
func (i Interface) SortedRequiredMethods() []string {
var orderedMethods []string
for methodName := range i.RequiredMethods {
orderedMethods = append(orderedMethods, methodName)
}
sort.Strings(orderedMethods)
return orderedMethods
}
func (i Interface) JumpTable() *lltypes.StructType {
orderedMethods := i.SortedRequiredMethods()
var ifaceTableMethods []lltypes.Type
for _, methodName := range orderedMethods {
methodSignature := i.RequiredMethods[methodName]
var retType lltypes.Type = lltypes.Void
if len(methodSignature.ReturnTypes) > 0 {
retType = methodSignature.ReturnTypes[0].LLVM()
}
paramTypes := []lltypes.Type{lltypes.NewPointer(lltypes.I8)}
for _, argType := range methodSignature.ArgumentTypes {
paramTypes = append(paramTypes, argType.LLVM())
}
ifaceTableMethods = append(ifaceTableMethods, lltypes.NewPointer(lltypes.NewFunc(retType, paramTypes...)))
}
return lltypes.NewStruct(ifaceTableMethods...)
}
func (i Interface) LLVM() lltypes.Type {
return lltypes.NewStruct(
// Pointer to the backing data
lltypes.NewPointer(lltypes.I8),
// Backing data type
lltypes.I32,
// Interface table
// Used for method resolving
lltypes.NewPointer(i.JumpTable()),
)
}
func (Interface) Size() int64 {
return 64 / 8 * 3
}
type InterfaceMethod struct {
backingType
LlvmJumpFunction llvalue.Named
ArgumentTypes []Type
ReturnTypes []Type
}
func (InterfaceMethod) LLVM() lltypes.Type {
panic("InterfaceMethod has no LLVM value")
}
func (InterfaceMethod) Name() string {
return "InterfaceMethod"
}
package types
import "github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
type PackageInstance struct {
backingType
name string
funcs map[string]*Function
}
func (p *PackageInstance) SetName(name string) {
p.name = name
}
func (p *PackageInstance) SetFunc(name string, val *Function) {
if p.funcs == nil {
p.funcs = make(map[string]*Function)
}
p.funcs[name] = val
}
func (p *PackageInstance) GetFunc(name string) (*Function, bool) {
v, ok := p.funcs[name]
return v, ok
}
func (PackageInstance) LLVM() lltypes.Type {
// TODO: Packages are not values, and should be represented some other way
// Maybe via LLVM IR modules?
panic("Package does not have LLVM defined")
}
func (p PackageInstance) Name() string {
return p.name
}
package types
import (
"fmt"
"math/big"
"github.com/wa-lang/wa/internal/3rdparty/llir"
"github.com/wa-lang/wa/internal/3rdparty/llir/llconstant"
"github.com/wa-lang/wa/internal/3rdparty/llir/lltypes"
"github.com/wa-lang/wa/internal/3rdparty/llir/llvalue"
"github.com/wa-lang/wa/internal/backends/compiler_ll/llutil"
)
type Type interface {
LLVM() lltypes.Type
Name() string
// Size of type in bytes
Size() int64
AddMethod(string, *Method)
GetMethod(string) (*Method, bool)
Zero(*llir.Block, llvalue.Value)
IsSigned() bool
}
type backingType struct {
methods map[string]*Method
}
func (b *backingType) AddMethod(name string, method *Method) {
if b.methods == nil {
b.methods = make(map[string]*Method)
}
b.methods[name] = method
}
func (b *backingType) GetMethod(name string) (*Method, bool) {
m, ok := b.methods[name]
return m, ok
}
func (backingType) Size() int64 {
panic("Type does not have size set")
}
func (backingType) Zero(*llir.Block, llvalue.Value) {
// NOOP
}
func (backingType) IsSigned() bool {
return false
}
type Struct struct {
backingType
Members map[string]Type
MemberIndexes map[string]int
IsHeapAllocated bool
SourceName string
Type lltypes.Type
}
func (s Struct) LLVM() lltypes.Type {
return s.Type
}
func (s Struct) Name() string {
return fmt.Sprintf("struct(%s)", s.SourceName)
}
func (s Struct) Zero(block *llir.Block, alloca llvalue.Value) {
for key, valType := range s.Members {
ptr := block.NewGetElementPtr(llutil.PtrElemType(alloca), alloca,
llconstant.NewInt(lltypes.I32, 0),
llconstant.NewInt(lltypes.I32, int64(s.MemberIndexes[key])),
)
valType.Zero(block, ptr)
}
}
func (s Struct) Size() int64 {
var sum int64
for _, valType := range s.Members {
sum += valType.Size()
}
return sum
}
type Method struct {
backingType
Function *Function
LlvmFunction llvalue.Named
PointerReceiver bool
MethodName string
}
func (m Method) LLVM() lltypes.Type {
return m.Function.LLVM()
}
func (m Method) Name() string {
return m.MethodName
}
type Function struct {
backingType
// LlvmFunction llvalue.Named
FuncType lltypes.Type
// The return type of the LLVM function (is always 1)
LlvmReturnType Type
// Return types of the Tre function
ReturnTypes []Type
IsVariadic bool
ArgumentTypes []Type
IsExternal bool
// Is used when calling an interface method
JumpFunction *llir.Func
}
func (f Function) LLVM() lltypes.Type {
return f.FuncType
}
func (f Function) Name() string {
return "func"
}
type BoolType struct {
backingType
}
func (BoolType) LLVM() lltypes.Type {
return lltypes.I1
}
func (BoolType) Name() string {
return "bool"
}
func (BoolType) Size() int64 {
return 1
}
func (b BoolType) Zero(block *llir.Block, alloca llvalue.Value) {
block.NewStore(llconstant.NewInt(lltypes.I1, 0), alloca)
}
type VoidType struct {
backingType
}
func (VoidType) LLVM() lltypes.Type {
return lltypes.Void
}
func (VoidType) Name() string {
return "void"
}
func (VoidType) Size() int64 {
return 0
}
type Int struct {
backingType
Type *lltypes.IntType
TypeName string
TypeSize int64
Signed bool
}
func (i Int) LLVM() lltypes.Type {
return i.Type
}
func (i Int) Name() string {
return i.TypeName
}
func (i Int) Size() int64 {
return i.TypeSize
}
func (i Int) Zero(block *llir.Block, alloca llvalue.Value) {
b := big.NewInt(0)
if !i.IsSigned() {
b.SetUint64(0)
}
c := &llconstant.Int{
Typ: i.Type,
X: b,
}
block.NewStore(c, alloca)
}
func (i Int) IsSigned() bool {
return i.Signed
}
type StringType struct {
backingType
Type lltypes.Type
}
// Populated by compiler.go
var ModuleStringType lltypes.Type
var EmptyStringConstant *llir.Global
func (StringType) LLVM() lltypes.Type {
return ModuleStringType
}
func (StringType) Name() string {
return "string"
}
func (StringType) Size() int64 {
return 16
}
func (s StringType) Zero(block *llir.Block, alloca llvalue.Value) {
lenPtr := block.NewGetElementPtr(llutil.PtrElemType(alloca), alloca, llconstant.NewInt(lltypes.I32, 0), llconstant.NewInt(lltypes.I32, 0))
backingDataPtr := block.NewGetElementPtr(llutil.PtrElemType(alloca), alloca, llconstant.NewInt(lltypes.I32, 0), llconstant.NewInt(lltypes.I32, 1))
block.NewStore(llconstant.NewInt(lltypes.I64, 0), lenPtr)
block.NewStore(llutil.StrToi8Ptr(block, EmptyStringConstant), backingDataPtr)
}
type Array struct {
backingType
Type Type
Len uint64
LlvmType lltypes.Type
}
func (a Array) LLVM() lltypes.Type {
return a.LlvmType
}
func (a Array) Name() string {
return "array"
}
func (a Array) Zero(block *llir.Block, alloca llvalue.Value) {
for i := uint64(0); i < a.Len; i++ {
ptr := block.NewGetElementPtr(llutil.PtrElemType(alloca), alloca, llconstant.NewInt(lltypes.I64, 0), llconstant.NewInt(lltypes.I64, int64(i)))
a.Type.Zero(block, ptr)
}
}
type Slice struct {
backingType
Type Type // type of the items in the slice []int => int
LlvmType lltypes.Type
}
func (s Slice) LLVM() lltypes.Type {
return s.LlvmType
}
func (Slice) Name() string {
return "slice"
}
func (Slice) Size() int64 {
return 3*4 + 8 // 3 int32s and a pointer
}
func (s Slice) SliceZero(block *llir.Block, mallocFunc llvalue.Named, initCap int, emptySlice llvalue.Value) {
// The cap must always be larger than 0
// Use 2 as the default value
if initCap < 2 {
initCap = 2
}
len := block.NewGetElementPtr(llutil.PtrElemType(emptySlice), emptySlice, llconstant.NewInt(lltypes.I32, 0), llconstant.NewInt(lltypes.I32, 0))
len.SetName("len")
cap := block.NewGetElementPtr(llutil.PtrElemType(emptySlice), emptySlice, llconstant.NewInt(lltypes.I32, 0), llconstant.NewInt(lltypes.I32, 1))
cap.SetName("cap")
offset := block.NewGetElementPtr(llutil.PtrElemType(emptySlice), emptySlice, llconstant.NewInt(lltypes.I32, 0), llconstant.NewInt(lltypes.I32, 2))
offset.SetName("offset")
backingArray := block.NewGetElementPtr(llutil.PtrElemType(emptySlice), emptySlice, llconstant.NewInt(lltypes.I32, 0), llconstant.NewInt(lltypes.I32, 3))
backingArray.SetName("backing")
block.NewStore(llconstant.NewInt(lltypes.I32, 0), len)
block.NewStore(llconstant.NewInt(lltypes.I32, int64(initCap)), cap)
block.NewStore(llconstant.NewInt(lltypes.I32, 0), offset)
mallocatedSpaceRaw := block.NewCall(mallocFunc, llconstant.NewInt(lltypes.I64, int64(initCap)*s.Type.Size()))
mallocatedSpaceRaw.SetName("slicezero")
bitcasted := block.NewBitCast(mallocatedSpaceRaw, lltypes.NewPointer(s.Type.LLVM()))
block.NewStore(bitcasted, backingArray)
}
type Pointer struct {
backingType
Type Type
IsNonAllocDereference bool
LlvmType lltypes.Type
}
func (p Pointer) LLVM() lltypes.Type {
return lltypes.NewPointer(p.Type.LLVM())
}
func (p Pointer) Name() string {
return fmt.Sprintf("pointer(%s)", p.Type.Name())
}
func (p Pointer) Size() int64 {
return 8
}
// MultiValue is used when returning multiple values from a function
type MultiValue struct {
backingType
Types []Type
}
func (m MultiValue) Name() string {
return "multivalue"
}
func (m MultiValue) LLVM() lltypes.Type {
panic("MutliValue has no LLVM type")
}
type UntypedConstantNumber struct {
backingType
}
func (m UntypedConstantNumber) Name() string {
return "UntypedConstantNumber"
}
func (m UntypedConstantNumber) LLVM() lltypes.Type {
panic("UntypedConstantNumber has no LLVM type")
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册