From 5aebda553609b86967c885d9d1c8e5cb37048eb4 Mon Sep 17 00:00:00 2001 From: Ben Shi Date: Sat, 5 Nov 2022 14:38:16 +0800 Subject: [PATCH] llvm: implement translation of type convertion. --- _examples/misc/native_test.wa | 70 +++++++++++++++++ .../backends/compiler_llvm/compile_value.go | 75 +++++++++++++++++++ internal/backends/compiler_llvm/utils.go | 53 ++++++++++++- 3 files changed, 197 insertions(+), 1 deletion(-) diff --git a/_examples/misc/native_test.wa b/_examples/misc/native_test.wa index 96f9720..984a8af 100644 --- a/_examples/misc/native_test.wa +++ b/_examples/misc/native_test.wa @@ -33,6 +33,11 @@ fn main { test_pointer() + test_convert0() + test_convert1() + test_convert2() + test_convert3() + bye() } @@ -175,3 +180,68 @@ fn new_int() *i32 { fn set_int(p: *i32) { *p = 13 } + +fn convert_i32_to_i16(a: i32) i16 { + return i16(a) +} + +fn convert_i32_to_u16(a: i32) u16 { + return u16(a) +} + +fn convert_i16_to_i32(a: i16) i32 { + return i32(a) +} + +fn convert_u16_to_i32(a: u16) i32 { + return i32(a) +} + +fn test_convert0() { + println(i32(convert_i32_to_i16(65537))) + println(u32(convert_i32_to_u16(65537))) + println(convert_i16_to_i32(100)) + println(convert_i16_to_i32(-100)) + println(convert_u16_to_i32(100)) + println(convert_u16_to_i32(65530)) +} + +fn convert_f64_to_f32(a: f64) f32 { + return f32(a) +} + +fn test_convert1() { + println(float64(convert_f64_to_f32(3.1415926535))) +} + +fn convert_i16_to_f64(a: i16) f64 { + return f64(a) +} + +fn convert_u16_to_f64(a: u16) f64 { + return f64(a) +} + +fn test_convert2() { + println(convert_i16_to_f64(100)) + println(convert_i16_to_f64(-100)) + println(convert_u16_to_f64(100)) + println(convert_u16_to_f64(65530)) +} + +fn convert_f64_to_i32(a: f64) i32 { + return i32(a) +} + +fn convert_f64_to_u32(a: f64) u32 { + return u32(a) +} + +fn test_convert3() { + println(convert_f64_to_i32(100.001)) + println(convert_f64_to_u32(100.001)) + println(convert_f64_to_i32(99.99)) + println(convert_f64_to_u32(99.99)) + println(convert_f64_to_i32(-100.001)) + println(convert_f64_to_u32(-100.001)) +} diff --git a/internal/backends/compiler_llvm/compile_value.go b/internal/backends/compiler_llvm/compile_value.go index 8bcbc6c..2224ebe 100644 --- a/internal/backends/compiler_llvm/compile_value.go +++ b/internal/backends/compiler_llvm/compile_value.go @@ -96,6 +96,11 @@ func (p *Compiler) compileValue(val ssa.Value) error { p.output.WriteString(strconv.Itoa(val.Field)) p.output.WriteString("\n") + case *ssa.Convert: + if err := p.compileConvert(val); err != nil { + return err + } + default: p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n") // panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") @@ -104,6 +109,76 @@ func (p *Compiler) compileValue(val ssa.Value) error { return nil } +func (p *Compiler) compileConvert(val *ssa.Convert) error { + frIsFloat, frIsSigned := checkType(val.X.Type()) + toIsFloat, toIsSigned := checkType(val.Type()) + frSize := getTypeSize(val.X.Type(), p.target) + toSize := getTypeSize(val.Type(), p.target) + + p.output.WriteString(" ") + p.output.WriteString(getValueStr(val)) + p.output.WriteString(" = ") + + switch { + case !frIsFloat && !toIsFloat: // integral type -> integral type + switch { + case frSize == toSize: + p.output.WriteString("add ") + p.output.WriteString(getTypeStr(val.Type(), p.target)) + p.output.WriteString(" ") + p.output.WriteString(getValueStr(val.X)) + p.output.WriteString(", 0\n") + return nil + + case frSize > toSize: + p.output.WriteString("trunc ") + case frSize < toSize: + if !toIsSigned || !frIsSigned { + p.output.WriteString("zext ") + } else { + p.output.WriteString("sext ") + } + default: + panic("unkown type convert: " + val.String()) + } + + case frIsFloat && toIsFloat: // float point type -> float point type + switch { + case frSize > toSize: + p.output.WriteString("fptrunc ") + case frSize < toSize: + p.output.WriteString("fpext ") + default: + panic("unkown type convert: " + val.String()) + } + + case !frIsFloat && toIsFloat: // integeral type -> float point type + if frIsSigned { + p.output.WriteString("sitofp ") + } else { + p.output.WriteString("uitofp ") + } + + case frIsFloat && !toIsFloat: //float point type -> integral type + if toIsSigned { + p.output.WriteString("fptosi ") + } else { + p.output.WriteString("fptoui ") + } + + default: + panic("unkown type convert: " + val.String()) + } + + p.output.WriteString(getTypeStr(val.X.Type(), p.target)) + p.output.WriteString(" ") + p.output.WriteString(getValueStr(val.X)) + p.output.WriteString(" to ") + p.output.WriteString(getTypeStr(val.Type(), p.target)) + p.output.WriteString("\n") + return nil +} + func (p *Compiler) compileUnOp(val *ssa.UnOp) error { p.output.WriteString(" ") p.output.WriteString(getValueStr(val)) diff --git a/internal/backends/compiler_llvm/utils.go b/internal/backends/compiler_llvm/utils.go index e1d42ec..c925652 100644 --- a/internal/backends/compiler_llvm/utils.go +++ b/internal/backends/compiler_llvm/utils.go @@ -183,7 +183,58 @@ func getTypeStr(ty types.Type, target string) string { return getTypeStr(t.Underlying(), target) default: - // TODO: support pointer, array and struct types + panic("unknown type") + } +} + +func getTypeSize(ty types.Type, target string) int { + // feasible types on different targets + defInt := map[string]int{ + "avr": 2, + "thumb": 2, + "arm": 4, + "aarch64": 8, + "riscv32": 4, + "riscv64": 8, + "x86": 4, + "x86_64": 8, + } + // fixed types + expTy := map[types.BasicKind]int{ + types.Bool: 1, + types.UntypedBool: 1, + types.Int8: 1, + types.Uint8: 1, + types.Int16: 2, + types.Uint16: 2, + types.Int32: 4, + types.Uint32: 4, + types.Int64: 8, + types.Uint64: 8, + types.Float32: 4, + types.Float64: 8, + types.UntypedFloat: 4, + } + + switch t := ty.(type) { + case *types.Basic: + // return size of a fixed type + if sz, ok := expTy[t.Kind()]; ok { + return sz + } + // return size of a feasible type + switch t.Kind() { + case types.Int, types.Uint, types.UntypedInt: + if sz, ok := defInt[getArch(target)]; ok { + return sz + } + return 8 + // should never reach here + default: + panic("unknown basic type") + } + + default: panic("unknown type") } } -- GitLab