@@ -1476,7 +1476,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
14761476 case * ssa.BinOp :
14771477 x := b .getValue (expr .X )
14781478 y := b .getValue (expr .Y )
1479- return b .createBinOp (expr .Op , expr .X .Type (), x , y , expr .Pos ())
1479+ return b .createBinOp (expr .Op , expr .X .Type (), expr . Y . Type (), x , y , expr .Pos ())
14801480 case * ssa.Call :
14811481 return b .createFunctionCall (expr .Common ())
14821482 case * ssa.ChangeInterface :
@@ -1925,7 +1925,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
19251925// same type, even for bitshifts. Also, signedness in Go is encoded in the type
19261926// and is encoded in the operation in LLVM IR: this is important for some
19271927// operations such as divide.
1928- func (b * builder ) createBinOp (op token.Token , typ types.Type , x , y llvm.Value , pos token.Pos ) (llvm.Value , error ) {
1928+ func (b * builder ) createBinOp (op token.Token , typ , ytyp types.Type , x , y llvm.Value , pos token.Pos ) (llvm.Value , error ) {
19291929 switch typ := typ .Underlying ().(type ) {
19301930 case * types.Basic :
19311931 if typ .Info ()& types .IsInteger != 0 {
@@ -1957,32 +1957,49 @@ func (b *builder) createBinOp(op token.Token, typ types.Type, x, y llvm.Value, p
19571957 case token .XOR : // ^
19581958 return b .CreateXor (x , y , "" ), nil
19591959 case token .SHL , token .SHR :
1960+ if ytyp .Underlying ().(* types.Basic ).Info ()& types .IsUnsigned == 0 {
1961+ // Ensure that y is not negative.
1962+ b .createNegativeShiftCheck (y )
1963+ }
1964+
19601965 sizeX := b .targetData .TypeAllocSize (x .Type ())
19611966 sizeY := b .targetData .TypeAllocSize (y .Type ())
1962- if sizeX > sizeY {
1963- // x and y must have equal sizes, make Y bigger in this case.
1964- // y is unsigned, this has been checked by the Go type checker.
1967+
1968+ // Check if the shift is bigger than the bit-width of the shifted value.
1969+ // This is UB in LLVM, so it needs to be handled seperately.
1970+ // The Go spec indirectly defines the result as 0.
1971+ // Negative shifts are handled earlier, so we can treat y as unsigned.
1972+ overshifted := b .CreateICmp (llvm .IntUGE , y , llvm .ConstInt (y .Type (), 8 * sizeX , false ), "shift.overflow" )
1973+
1974+ // Adjust the size of y to match x.
1975+ switch {
1976+ case sizeX > sizeY :
19651977 y = b .CreateZExt (y , x .Type (), "" )
1966- } else if sizeX < sizeY {
1967- // What about shifting more than the integer width?
1968- // I'm not entirely sure what the Go spec is on that, but as
1969- // Intel CPUs have undefined behavior when shifting more
1970- // than the integer width I'm assuming it is also undefined
1971- // in Go.
1978+ case sizeX < sizeY :
1979+ // If it gets truncated, overshifted will be true and it will not matter.
19721980 y = b .CreateTrunc (y , x .Type (), "" )
19731981 }
1982+
1983+ // Create a shift operation.
1984+ var val llvm.Value
19741985 switch op {
19751986 case token .SHL : // <<
1976- return b .CreateShl (x , y , "" ), nil
1987+ val = b .CreateShl (x , y , "" )
19771988 case token .SHR : // >>
19781989 if signed {
1990+ // Arithmetic right shifts work differently, since shifting a negative number right yields -1.
1991+ // Cap the shift input rather than selecting the output.
1992+ y = b .CreateSelect (overshifted , llvm .ConstInt (y .Type (), 8 * sizeX - 1 , false ), y , "shift.offset" )
19791993 return b .CreateAShr (x , y , "" ), nil
19801994 } else {
1981- return b .CreateLShr (x , y , "" ), nil
1995+ val = b .CreateLShr (x , y , "" )
19821996 }
19831997 default :
19841998 panic ("unreachable" )
19851999 }
2000+
2001+ // Select between the shift result and zero depending on whether there was an overshift.
2002+ return b .CreateSelect (overshifted , llvm .ConstInt (val .Type (), 0 , false ), val , "shift.result" ), nil
19862003 case token .EQL : // ==
19872004 return b .CreateICmp (llvm .IntEQ , x , y , "" ), nil
19882005 case token .NEQ : // !=
@@ -2218,7 +2235,7 @@ func (b *builder) createBinOp(op token.Token, typ types.Type, x, y llvm.Value, p
22182235 for i := 0 ; i < int (typ .Len ()); i ++ {
22192236 xField := b .CreateExtractValue (x , i , "" )
22202237 yField := b .CreateExtractValue (y , i , "" )
2221- fieldEqual , err := b .createBinOp (token .EQL , typ .Elem (), xField , yField , pos )
2238+ fieldEqual , err := b .createBinOp (token .EQL , typ .Elem (), typ . Elem (), xField , yField , pos )
22222239 if err != nil {
22232240 return llvm.Value {}, err
22242241 }
@@ -2246,7 +2263,7 @@ func (b *builder) createBinOp(op token.Token, typ types.Type, x, y llvm.Value, p
22462263 fieldType := typ .Field (i ).Type ()
22472264 xField := b .CreateExtractValue (x , i , "" )
22482265 yField := b .CreateExtractValue (y , i , "" )
2249- fieldEqual , err := b .createBinOp (token .EQL , fieldType , xField , yField , pos )
2266+ fieldEqual , err := b .createBinOp (token .EQL , fieldType , fieldType , xField , yField , pos )
22502267 if err != nil {
22512268 return llvm.Value {}, err
22522269 }
0 commit comments