ssa: binop check shl/shr
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
15
internal/runtime/error.go
Normal file
15
internal/runtime/error.go
Normal file
@@ -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())
|
||||
}
|
||||
}
|
||||
Binary file not shown.
32
ssa/expr.go
32
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}
|
||||
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"))
|
||||
}
|
||||
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) {
|
||||
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}
|
||||
}
|
||||
case isPredOp(op): // op: == != < <= < >=
|
||||
tret := b.Prog.Bool()
|
||||
kind := x.kind
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user