ssa: binop check shl/shr

This commit is contained in:
visualfc
2024-05-16 15:09:00 +08:00
parent 07e55c3d89
commit 98945926ca
6 changed files with 212 additions and 14 deletions

View File

@@ -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
}

View File

@@ -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
View 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.

View File

@@ -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

View File

@@ -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
}