MCPcopy
hub / github.com/tinygo-org/tinygo / createBinOp

Method createBinOp

compiler/compiler.go:2642–3050  ·  view source on GitHub ↗

createBinOp creates a LLVM binary operation (add, sub, mul, etc) for a Go binary operation. This is almost a direct mapping, but there are some subtle differences such as the requirement in LLVM IR that both sides must have the same type, even for bitshifts. Also, signedness in Go is encoded in the

(op token.Token, typ, ytyp types.Type, x, y llvm.Value, pos token.Pos)

Source from the content-addressed store, hash-verified

2640// and is encoded in the operation in LLVM IR: this is important for some
2641// operations such as divide.
2642func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Value, pos token.Pos) (llvm.Value, error) {
2643 switch typ := typ.Underlying().(type) {
2644 case *types.Basic:
2645 if typ.Info()&types.IsInteger != 0 {
2646 // Operations on integers
2647 signed := typ.Info()&types.IsUnsigned == 0
2648 switch op {
2649 case token.ADD: // +
2650 return b.CreateAdd(x, y, ""), nil
2651 case token.SUB: // -
2652 return b.CreateSub(x, y, ""), nil
2653 case token.MUL: // *
2654 return b.CreateMul(x, y, ""), nil
2655 case token.QUO, token.REM: // /, %
2656 // Check for a divide by zero. If y is zero, the Go
2657 // specification says that a runtime error must be triggered.
2658 b.createDivideByZeroCheck(y)
2659
2660 if signed {
2661 // Deal with signed division overflow.
2662 // The LLVM LangRef says:
2663 //
2664 // Overflow also leads to undefined behavior; this is a
2665 // rare case, but can occur, for example, by doing a
2666 // 32-bit division of -2147483648 by -1.
2667 //
2668 // The Go specification however says this about division:
2669 //
2670 // The one exception to this rule is that if the dividend
2671 // x is the most negative value for the int type of x, the
2672 // quotient q = x / -1 is equal to x (and r = 0) due to
2673 // two's-complement integer overflow.
2674 //
2675 // In other words, in the special case that the lowest
2676 // possible signed integer is divided by -1, the result of
2677 // the division is the same as x (the dividend).
2678 // This is implemented by checking for this condition and
2679 // changing y to 1 if it occurs, for example for 32-bit
2680 // ints:
2681 //
2682 // if x == -2147483648 && y == -1 {
2683 // y = 1
2684 // }
2685 //
2686 // Dividing x by 1 obviously returns x, therefore satisfying
2687 // the Go specification without a branch.
2688 llvmType := x.Type()
2689 minusOne := llvm.ConstSub(llvm.ConstInt(llvmType, 0, false), llvm.ConstInt(llvmType, 1, false))
2690 lowestInteger := llvm.ConstInt(x.Type(), 1<<(llvmType.IntTypeWidth()-1), false)
2691 yIsMinusOne := b.CreateICmp(llvm.IntEQ, y, minusOne, "")
2692 xIsLowestInteger := b.CreateICmp(llvm.IntEQ, x, lowestInteger, "")
2693 hasOverflow := b.CreateAnd(yIsMinusOne, xIsLowestInteger, "")
2694 y = b.CreateSelect(hasOverflow, llvm.ConstInt(llvmType, 1, true), y, "")
2695
2696 if op == token.QUO {
2697 return b.CreateSDiv(x, y, ""), nil
2698 } else {
2699 return b.CreateSRem(x, y, ""), nil

Callers 2

createBuiltinMethod · 0.95
createExprMethod · 0.95

Calls 13

TypeMethod · 0.95
createRuntimeCallMethod · 0.95
extractFuncScalarMethod · 0.95
InfoMethod · 0.80
makeErrorMethod · 0.80
StringMethod · 0.65
KindMethod · 0.65
LenMethod · 0.65
ElemMethod · 0.65
NameMethod · 0.65

Tested by

no test coverage detected