diff --git a/cl/_testrt/mask/in.go b/cl/_testrt/mask/in.go index 18211c06..f5e266e5 100644 --- a/cl/_testrt/mask/in.go +++ b/cl/_testrt/mask/in.go @@ -2,7 +2,41 @@ package main func main() { println(mask(1)) + println(mask_shl(127, 5)) + println(mask_shl8(127, 5)) + println(mask_shl8u(127, 5)) + println(mask_shl8(127, 16)) + println(mask_shl8u(127, 16)) + println(mask_shr(127, 5)) + println(mask_shr8(127, 5)) + println(mask_shr8u(127, 5)) + println(mask_shr8(127, 16)) } + func mask(x int8) int32 { return int32(x) << 31 >> 31 } + +func mask_shl8(x int8, y int) int8 { + return x << y +} + +func mask_shl8u(x uint8, y int) uint8 { + return x << y +} + +func mask_shl(x int, y int) int { + return x << y +} + +func mask_shr8(x int8, y int) int8 { + return x >> y +} + +func mask_shr8u(x uint8, y int) uint8 { + return x >> y +} + +func mask_shr(x int, y int) int { + return x >> y +} diff --git a/cl/_testrt/mask/out.ll b/cl/_testrt/mask/out.ll index bea4f657..c64b738f 100644 --- a/cl/_testrt/mask/out.ll +++ b/cl/_testrt/mask/out.ll @@ -7,6 +7,21 @@ source_filename = "main" @__llgo_argc = global ptr null @__llgo_argv = global ptr null @0 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@1 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@2 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@3 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@4 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@5 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@6 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@7 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@8 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@9 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 +@10 = private unnamed_addr constant [22 x i8] c"negative shift amount\00", align 1 +@11 = private unnamed_addr constant [22 x i8] c"negative shift amount\00", align 1 +@12 = private unnamed_addr constant [22 x i8] c"negative shift amount\00", align 1 +@13 = private unnamed_addr constant [22 x i8] c"negative shift amount\00", align 1 +@14 = private unnamed_addr constant [22 x i8] c"negative shift amount\00", align 1 +@15 = private unnamed_addr constant [22 x i8] c"negative shift amount\00", align 1 define void @main.init() { _llgo_0: @@ -32,6 +47,49 @@ _llgo_0: call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %3) %4 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @0, i64 1) call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %4) + %5 = call i64 @main.mask_shl(i64 127, i64 5) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %5) + %6 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @1, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %6) + %7 = call i8 @main.mask_shl8(i8 127, i64 5) + %8 = sext i8 %7 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %8) + %9 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @2, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %9) + %10 = call i8 @main.mask_shl8u(i8 127, i64 5) + %11 = sext i8 %10 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 %11) + %12 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @3, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %12) + %13 = call i8 @main.mask_shl8(i8 127, i64 16) + %14 = sext i8 %13 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %14) + %15 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @4, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %15) + %16 = call i8 @main.mask_shl8u(i8 127, i64 16) + %17 = sext i8 %16 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 %17) + %18 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @5, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %18) + %19 = call i64 @main.mask_shr(i64 127, i64 5) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %19) + %20 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @6, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %20) + %21 = call i8 @main.mask_shr8(i8 127, i64 5) + %22 = sext i8 %21 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %22) + %23 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @7, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %23) + %24 = call i8 @main.mask_shr8u(i8 127, i64 5) + %25 = sext i8 %24 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64 %25) + %26 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @8, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %26) + %27 = call i8 @main.mask_shr8(i8 127, i64 16) + %28 = sext i8 %27 to i64 + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %28) + %29 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @9, i64 1) + call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" %29) ret void } @@ -39,8 +97,79 @@ define i32 @main.mask(i8 %0) { _llgo_0: %1 = sext i8 %0 to i32 %2 = shl i32 %1, 31 - %3 = ashr i32 %2, 31 - ret i32 %3 + %3 = select i1 false, i32 0, i32 %2 + %4 = ashr i32 %3, 31 + ret i32 %4 +} + +define i64 @main.mask_shl(i64 %0, i64 %1) { +_llgo_0: + %2 = icmp slt i64 %1, 0 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @10, i64 21) + call void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1 %2, %"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = icmp uge i64 %1, 64 + %5 = shl i64 %0, %1 + %6 = select i1 %4, i64 0, i64 %5 + ret i64 %6 +} + +define i8 @main.mask_shl8(i8 %0, i64 %1) { +_llgo_0: + %2 = icmp slt i64 %1, 0 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @11, i64 21) + call void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1 %2, %"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = trunc i64 %1 to i8 + %5 = icmp uge i8 %4, 8 + %6 = shl i8 %0, %4 + %7 = select i1 %5, i8 0, i8 %6 + ret i8 %7 +} + +define i8 @main.mask_shl8u(i8 %0, i64 %1) { +_llgo_0: + %2 = icmp slt i64 %1, 0 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @12, i64 21) + call void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1 %2, %"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = trunc i64 %1 to i8 + %5 = icmp uge i8 %4, 8 + %6 = shl i8 %0, %4 + %7 = select i1 %5, i8 0, i8 %6 + ret i8 %7 +} + +define i64 @main.mask_shr(i64 %0, i64 %1) { +_llgo_0: + %2 = icmp slt i64 %1, 0 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @13, i64 21) + call void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1 %2, %"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = icmp uge i64 %1, 64 + %5 = select i1 %4, i64 63, i64 %1 + %6 = ashr i64 %0, %5 + ret i64 %6 +} + +define i8 @main.mask_shr8(i8 %0, i64 %1) { +_llgo_0: + %2 = icmp slt i64 %1, 0 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @14, i64 21) + call void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1 %2, %"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = trunc i64 %1 to i8 + %5 = icmp uge i8 %4, 8 + %6 = select i1 %5, i8 7, i8 %4 + %7 = ashr i8 %0, %6 + ret i8 %7 +} + +define i8 @main.mask_shr8u(i8 %0, i64 %1) { +_llgo_0: + %2 = icmp slt i64 %1, 0 + %3 = call %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr @15, i64 21) + call void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1 %2, %"github.com/goplus/llgo/internal/runtime.String" %3) + %4 = trunc i64 %1 to i8 + %5 = icmp uge i8 %4, 8 + %6 = lshr i8 %0, %4 + %7 = select i1 %5, i8 0, i8 %6 + ret i8 %7 } declare void @"github.com/goplus/llgo/internal/runtime.init"() @@ -50,3 +179,7 @@ declare void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64) declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String") declare %"github.com/goplus/llgo/internal/runtime.String" @"github.com/goplus/llgo/internal/runtime.NewString"(ptr, i64) + +declare void @"github.com/goplus/llgo/internal/runtime.PrintUint"(i64) + +declare void @"github.com/goplus/llgo/internal/runtime.CheckRuntimeError"(i1, %"github.com/goplus/llgo/internal/runtime.String") diff --git a/internal/runtime/error.go b/internal/runtime/error.go new file mode 100644 index 00000000..a33d69db --- /dev/null +++ b/internal/runtime/error.go @@ -0,0 +1,15 @@ +package runtime + +type errorString string + +func (e errorString) RuntimeError() {} + +func (e errorString) Error() string { + return "runtime error: " + string(e) +} + +func CheckRuntimeError(b bool, s string) { + if b { + panic(errorString(s).Error()) + } +} diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla index 908e7b58..652fbb7f 100644 Binary files a/internal/runtime/llgo_autogen.lla and b/internal/runtime/llgo_autogen.lla differ diff --git a/ssa/expr.go b/ssa/expr.go index 7dfa45a0..1ebf1973 100644 --- a/ssa/expr.go +++ b/ssa/expr.go @@ -320,20 +320,36 @@ func (b Builder) BinOp(op token.Token, x, y Expr) Expr { } } case isLogicOp(op): // op: & | ^ << >> &^ - if op == token.AND_NOT { + switch op { + case token.AND_NOT: return Expr{b.impl.CreateAnd(x.impl, b.impl.CreateNot(y.impl, ""), ""), x.Type} - } - kind := x.kind - llop := logicOpToLLVM[op-logicOpBase] - if op == token.SHR && kind == vkUnsigned { - llop = llvm.LShr // Logical Shift Right - } - if op == token.SHL || op == token.SHR { - if b.Prog.SizeOf(x.Type) != b.Prog.SizeOf(y.Type) { + case token.SHL, token.SHR: + if y.kind == vkSigned { + check := Expr{b.impl.CreateICmp(llvm.IntSLT, y.impl, llvm.ConstInt(y.ll, 0, false), ""), b.Prog.Bool()} + b.InlineCall(b.Func.Pkg.rtFunc("CheckRuntimeError"), check, b.Str("negative shift amount")) + } + xsize, ysize := b.Prog.SizeOf(x.Type), b.Prog.SizeOf(y.Type) + if xsize != ysize { y = b.Convert(x.Type, y) } + overflows := b.impl.CreateICmp(llvm.IntUGE, y.impl, llvm.ConstInt(y.ll, xsize*8, false), "") + xzero := llvm.ConstInt(x.ll, 0, false) + if op == token.SHL { + rhs := b.impl.CreateShl(x.impl, y.impl, "") + return Expr{b.impl.CreateSelect(overflows, xzero, rhs, ""), x.Type} + } else { + if x.kind == vkSigned { + rhs := b.impl.CreateSelect(overflows, llvm.ConstInt(y.ll, 8*xsize-1, false), y.impl, "") + return Expr{b.impl.CreateAShr(x.impl, rhs, ""), x.Type} + } else { + rsh := b.impl.CreateLShr(x.impl, y.impl, "") + return Expr{b.impl.CreateSelect(overflows, xzero, rsh, ""), x.Type} + } + } + default: + llop := logicOpToLLVM[op-logicOpBase] + return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type} } - return Expr{llvm.CreateBinOp(b.impl, llop, x.impl, y.impl), x.Type} case isPredOp(op): // op: == != < <= < >= tret := b.Prog.Bool() kind := x.kind diff --git a/ssa/ssa_test.go b/ssa/ssa_test.go index 13a98552..daac56f2 100644 --- a/ssa/ssa_test.go +++ b/ssa/ssa_test.go @@ -446,7 +446,7 @@ func TestUnOp(t *testing.T) { b := fn.MakeBody(1) ptr := fn.Param(0) val := b.UnOp(token.MUL, ptr) - val2 := b.BinOp(token.SHR, val, prog.Val(1)) + val2 := b.BinOp(token.XOR, val, prog.Val(1)) b.Store(ptr, val2) b.Return(val2) assertPkg(t, pkg, `; ModuleID = 'foo/bar' @@ -455,7 +455,7 @@ source_filename = "foo/bar" define i64 @fn(ptr %0) { _llgo_0: %1 = load i64, ptr %0, align 4 - %2 = ashr i64 %1, 1 + %2 = xor i64 %1, 1 store i64 %2, ptr %0, align 4 ret i64 %2 }