提交 82df5ecc 编写于 作者: B Ben Shi

Implement translation of unary and binary operations.

上级 25e94ac9
......@@ -6,9 +6,13 @@ fn main {
print('言')
print('\n')
println(add(40, 2))
println(calc0(42, 5, 3))
}
fn add(a: i32, b: i32) => i32 {
return a + b
fn calc0(a: i32, b: i32, c: i32) => i32 {
return a * 5 / (b - c + 1)
}
fn calc2(a: float32, b: float32, c: float32) => float32 {
return a * 5 / (b - c + 1)
}
......@@ -54,18 +54,19 @@ func (p *Compiler) compileInstr(instr ssa.Instruction) error {
case 0:
p.output.WriteString(" ret void\n")
case 1: // ret %type %value
p.output.WriteString(" ; ret ")
p.output.WriteString(" ret ")
p.output.WriteString(getTypeStr(instr.Results[0].Type(), p.target))
p.output.WriteString(" %" + instr.Results[0].Name())
p.output.WriteString("\n")
p.output.WriteString(" ret " + getTypeStr(instr.Results[0].Type(), p.target) + " 1")
p.output.WriteString(" ")
p.output.WriteString(getValueStr(instr.Results[0]))
p.output.WriteString("\n")
default:
return errors.New("multiple return values are not supported")
}
case ssa.Value:
p.output.WriteString(" ; " + instr.Name() + " = " + instr.String() + "\n")
if err := p.compileValue(instr); err != nil {
return err
}
default:
p.output.WriteString(" ; " + instr.String() + "\n")
......
// 版权 @2022 凹语言 作者。保留所有权利。
package compiler_llvm
import (
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/token"
)
func (p *Compiler) compileValue(val ssa.Value) error {
switch val := val.(type) {
case *ssa.UnOp:
if err := p.compileUnOp(val); err != nil {
return err
}
case *ssa.BinOp:
if err := p.compileBinOp(val); err != nil {
return err
}
case *ssa.Call:
if err := p.compileCall(val); err != nil {
return err
}
default:
p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n")
// panic("unsupported Value '" + val.Name() + " = " + val.String() + "'")
}
return nil
}
func (p *Compiler) compileUnOp(val *ssa.UnOp) error {
switch val.Op {
case token.SUB:
p.output.WriteString(" ")
p.output.WriteString("%" + val.Name())
p.output.WriteString(" = ")
if isFloat, _ := checkType(val.X.Type()); isFloat {
p.output.WriteString("fneg ")
p.output.WriteString(getTypeStr(val.X.Type(), p.target))
p.output.WriteString(" ")
} else {
p.output.WriteString("sub ")
p.output.WriteString(getTypeStr(val.X.Type(), p.target))
p.output.WriteString(" 0, ")
}
p.output.WriteString(getValueStr(val.X))
p.output.WriteString("\n")
default:
p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n")
// panic("unsupported Value '" + val.Name() + " = " + val.String() + "'")
}
return nil
}
func (p *Compiler) compileBinOp(val *ssa.BinOp) error {
sintOpMap := map[token.Token]string{
token.ADD: "add",
token.SUB: "sub",
token.MUL: "mul",
token.QUO: "sdiv",
token.REM: "srem",
}
uintOpMap := map[token.Token]string{
token.ADD: "add",
token.SUB: "sub",
token.MUL: "mul",
token.QUO: "udiv",
token.REM: "urem",
}
floatOpMap := map[token.Token]string{
token.ADD: "fadd",
token.SUB: "fsub",
token.MUL: "fmul",
token.QUO: "fdiv",
}
// Type float, signed int, unsigned int each has its own LLVM-IR.
var opMap map[token.Token]string
isFloat, isSigned := checkType(val.X.Type())
if isFloat {
opMap = floatOpMap
} else if isSigned {
opMap = sintOpMap
} else {
opMap = uintOpMap
}
if op, ok := opMap[val.Op]; ok {
p.output.WriteString(" ")
p.output.WriteString("%" + val.Name())
p.output.WriteString(" = ")
p.output.WriteString(op)
p.output.WriteString(" ")
p.output.WriteString(getTypeStr(val.X.Type(), p.target))
p.output.WriteString(" ")
p.output.WriteString(getValueStr(val.X))
p.output.WriteString(", ")
p.output.WriteString(getValueStr(val.Y))
p.output.WriteString("\n")
return nil
}
p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n")
return nil
// panic("unsupported Value '" + val.Name() + " = " + val.String() + "'")
}
func (p *Compiler) compileCall(val *ssa.Call) error {
p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n")
return nil
}
......@@ -3,8 +3,11 @@
package compiler_llvm
import (
"fmt"
"strconv"
"strings"
"github.com/wa-lang/wa/internal/ssa"
"github.com/wa-lang/wa/internal/types"
)
......@@ -16,6 +19,26 @@ func getArch(arch string) string {
return arch[0:pos]
}
func checkType(from types.Type) (isFloat bool, isSigned bool) {
switch t := from.(type) {
case *types.Basic:
switch t.Kind() {
case types.Float32, types.Float64, types.UntypedFloat:
return true, true
case types.Uint8, types.Uint16, types.Uint32, types.Uint64,
types.Uint:
return false, false
case types.Bool, types.UntypedBool, types.Int8, types.Int16,
types.Int32, types.Int64, types.Int, types.UntypedInt:
return false, true
default:
panic("unknown basic type")
}
default:
panic("basic type is expected")
}
}
func getTypeStr(from types.Type, target string) string {
// feasible types on different targets
defInt := map[string]string{
......@@ -41,9 +64,9 @@ func getTypeStr(from types.Type, target string) string {
types.Uint32: "i32",
types.Int64: "i64",
types.Uint64: "i64",
types.Float32: "f32",
types.Float64: "f64",
types.UntypedFloat: "f32",
types.Float32: "float",
types.Float64: "double",
types.UntypedFloat: "float",
}
switch t := from.(type) {
......@@ -68,3 +91,24 @@ func getTypeStr(from types.Type, target string) string {
panic("unknown type")
}
}
func getValueStr(val ssa.Value) string {
switch val.(type) {
case *ssa.Const:
name := val.Name()
if pos := strings.Index(name, ":"); pos > 0 {
name = name[0:pos]
// Special form for float32/float64 constants as LLVM-IR requested.
if isFloat, _ := checkType(val.Type()); isFloat {
if f, err := strconv.ParseFloat(name, 64); err == nil {
name = fmt.Sprintf("%e", f)
}
}
}
return name
case *ssa.Parameter:
return "%" + val.Name()
default:
return "%" + val.Name()
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册