From e9df3881f74e784b06f11c5343437a3d92362da8 Mon Sep 17 00:00:00 2001 From: Ben Shi Date: Wed, 23 Nov 2022 15:52:50 +0800 Subject: [PATCH] llvm: implement translation of bitwise logic and shift operations. --- _examples/llvm/bitwise_logic.wa | 33 +++++++++++ _examples/llvm/shift.wa | 46 +++++++++++++++ .../backends/compiler_llvm/compile_value.go | 59 ++++++++++++++++--- 3 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 _examples/llvm/bitwise_logic.wa create mode 100644 _examples/llvm/shift.wa diff --git a/_examples/llvm/bitwise_logic.wa b/_examples/llvm/bitwise_logic.wa new file mode 100644 index 0000000..dc258a1 --- /dev/null +++ b/_examples/llvm/bitwise_logic.wa @@ -0,0 +1,33 @@ +# Test the llvm backend. +# Test bitwise logic. + +var a i64 = 0x55555555 +var b i64 = 0x33333333 +var c i16 = 0x5555 +var d i16 = 0x3333 +var e u8 = 0x55 +var f u8 = 0x33 + +fn main() { + println("not ", 0x55555555, " = ", bw_not(0x55555555)) + println("not ", 0xaaaaaaaa, " = ", bw_not(0xaaaaaaaa)) + println(a, " and ", b, " = ", bw_and(a, b), "(", 0x11111111, ")") + println(c, " or ", d, " = ", bw_or(c, d), "(", 0x7777, ")") + println(e, " xor ", f, " = ", bw_xor(e, f), "(", 0x66, ")") +} + +fn bw_not(a u32) u32 { + return ^a +} + +fn bw_and(a i64, b i64) i64 { + return a & b +} + +fn bw_or(a i16, b i16) i16 { + return a | b +} + +fn bw_xor(a u8, b u8) u8 { + return a ^ b +} diff --git a/_examples/llvm/shift.wa b/_examples/llvm/shift.wa new file mode 100644 index 0000000..80364ef --- /dev/null +++ b/_examples/llvm/shift.wa @@ -0,0 +1,46 @@ +# Test the llvm backend. +# Test logical/arithmetic shift operations. + +var ga i32 = -15 +var gb i32 = 15 +var gc i64 = -15 +var gd i64 = 15 +var ge u16 = 0xffcc + +fn main() { + println(ga, " << ", 2, " = ", test_shl_0(ga, 2)) + println(gb, " << ", 2, " = ", test_shl_1(gb, 2)) + println(ga, " << ", 2, " = ", test_shl_2(ga, 2)) + println(gc, " >> ", 2, " = ", test_ashr_0(gc, 2)) + println(gd, " >> ", 2, " = ", test_ashr_1(gd, 2)) + println(ge, " >> ", 2, " = ", test_lshr_0(ge, 2), "(", 0x3ff3, ")") + println(ge, " >> ", 2, " = ", test_lshr_1(ge, 2), "(", 0x3ff3, ")") +} + +fn test_shl_0(a i32, b i64) i32 { + return a << b +} + +fn test_shl_1(a i32, b i16) i32 { + return a << b +} + +fn test_shl_2(a i32, b u16) i32 { + return a << b +} + +fn test_ashr_0(a i64, b i64) i64 { + return a >> b +} + +fn test_ashr_1(a i64, b u32) i64 { + return a >> b +} + +fn test_lshr_0(a u16, b i32) u16 { + return a >> b +} + +fn test_lshr_1(a u16, b u8) u16 { + return a >> b +} diff --git a/internal/backends/compiler_llvm/compile_value.go b/internal/backends/compiler_llvm/compile_value.go index e6d6c87..25c2479 100644 --- a/internal/backends/compiler_llvm/compile_value.go +++ b/internal/backends/compiler_llvm/compile_value.go @@ -218,9 +218,15 @@ func (p *Compiler) compileUnOp(val *ssa.UnOp) error { p.output.WriteString(" ") p.output.WriteString(getValueStr(val.X)) + case token.XOR: + p.output.WriteString("xor ") + p.output.WriteString(getTypeStr(val.X.Type(), p.target)) + p.output.WriteString(" ") + p.output.WriteString(getValueStr(val.X)) + p.output.WriteString(", -1") + default: - p.output.WriteString(" ; " + val.Name() + " = " + val.String()) - // panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") + panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") } p.output.WriteString("\n") @@ -240,6 +246,11 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { token.GTR: "icmp sgt", token.LEQ: "icmp sle", token.GEQ: "icmp sge", + token.AND: "and", + token.OR: "or", + token.XOR: "xor", + token.SHL: "shl", + token.SHR: "ashr", } uintOpMap := map[token.Token]string{ token.ADD: "add", @@ -253,6 +264,11 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { token.GTR: "icmp ugt", token.LEQ: "icmp ule", token.GEQ: "icmp uge", + token.AND: "and", + token.OR: "or", + token.XOR: "xor", + token.SHL: "shl", + token.SHR: "lshr", } floatOpMap := map[token.Token]string{ token.ADD: "fadd", @@ -278,8 +294,39 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { opMap = uintOpMap } - // Special process for float32 constants. + // Special process for shift operations. xStr, yStr := "", "" + if val.Op == token.SHL || val.Op == token.SHR { + tyCOp := "" + switch { + case getTypeSize(val.X.Type(), p.target) < getTypeSize(val.Y.Type(), p.target): + tyCOp = "trunc" + case getTypeSize(val.X.Type(), p.target) > getTypeSize(val.Y.Type(), p.target): + _, yIsSigned := checkType(val.Y.Type()) + if !isSigned || !yIsSigned { + tyCOp = "zext" + } else { + tyCOp = "sext" + } + default: + } + if tyCOp != "" { + yStr = fmt.Sprintf("%%tmp%d", rand.Int()) + p.output.WriteString(" ") + p.output.WriteString(yStr) + p.output.WriteString(" = ") + p.output.WriteString(tyCOp) + p.output.WriteString(" ") + p.output.WriteString(getTypeStr(val.Y.Type(), p.target)) + p.output.WriteString(" ") + p.output.WriteString(getValueStr(val.Y)) + p.output.WriteString(" to ") + p.output.WriteString(getTypeStr(val.X.Type(), p.target)) + p.output.WriteString("\n") + } + } + + // Special process for float32 constants. if isConstFloat32(val.X) { xStr = p.wrapConstFloat32(val.X) } else { @@ -287,7 +334,7 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { } if isConstFloat32(val.Y) { yStr = p.wrapConstFloat32(val.Y) - } else { + } else if yStr == "" { yStr = getValueStr(val.Y) } @@ -307,9 +354,7 @@ func (p *Compiler) compileBinOp(val *ssa.BinOp) error { return nil } - p.output.WriteString(" ; " + val.Name() + " = " + val.String() + "\n") - return nil - // panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") + panic("unsupported Value '" + val.Name() + " = " + val.String() + "'") } func (p *Compiler) compileCall(val *ssa.Call) error { -- GitLab