Implement unsigned integers
Этот коммит содержится в:
родитель
75fce0f949
коммит
5067891236
2 изменённых файлов: 61 добавлений и 19 удалений
|
@ -10,20 +10,24 @@ func printstring(s string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printuint(n uint) {
|
||||||
|
// TODO: don't recurse, but still be compact (and don't divide/mod
|
||||||
|
// more than necessary).
|
||||||
|
prevdigits := n / 10
|
||||||
|
if prevdigits != 0 {
|
||||||
|
printuint(prevdigits)
|
||||||
|
}
|
||||||
|
C.putchar(C.int((n % 10) + '0'))
|
||||||
|
}
|
||||||
|
|
||||||
func printint(n int) {
|
func printint(n int) {
|
||||||
// Print integer in signed big-endian base-10 notation, for humans to
|
// Print integer in signed big-endian base-10 notation, for humans to
|
||||||
// read.
|
// read.
|
||||||
// TODO: don't recurse, but still be compact (and don't divide/mod
|
|
||||||
// more than necessary).
|
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
C.putchar('-')
|
C.putchar('-')
|
||||||
n = -n
|
n = -n
|
||||||
}
|
}
|
||||||
prevdigits := n / 10
|
printuint(uint(n))
|
||||||
if prevdigits != 0 {
|
|
||||||
printint(prevdigits)
|
|
||||||
}
|
|
||||||
C.putchar(C.int((n % 10) + '0'))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func printbyte(c uint8) {
|
func printbyte(c uint8) {
|
||||||
|
|
62
tgo.go
62
tgo.go
|
@ -47,6 +47,7 @@ type Compiler struct {
|
||||||
boundsCheckFunc llvm.Value
|
boundsCheckFunc llvm.Value
|
||||||
printstringFunc llvm.Value
|
printstringFunc llvm.Value
|
||||||
printintFunc llvm.Value
|
printintFunc llvm.Value
|
||||||
|
printuintFunc llvm.Value
|
||||||
printbyteFunc llvm.Value
|
printbyteFunc llvm.Value
|
||||||
printspaceFunc llvm.Value
|
printspaceFunc llvm.Value
|
||||||
printnlFunc llvm.Value
|
printnlFunc llvm.Value
|
||||||
|
@ -109,6 +110,8 @@ func NewCompiler(pkgName, triple string) (*Compiler, error) {
|
||||||
c.printstringFunc = llvm.AddFunction(c.mod, "runtime.printstring", printstringType)
|
c.printstringFunc = llvm.AddFunction(c.mod, "runtime.printstring", printstringType)
|
||||||
printintType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{c.intType}, false)
|
printintType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{c.intType}, false)
|
||||||
c.printintFunc = llvm.AddFunction(c.mod, "runtime.printint", printintType)
|
c.printintFunc = llvm.AddFunction(c.mod, "runtime.printint", printintType)
|
||||||
|
printuintType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{c.intType}, false)
|
||||||
|
c.printuintFunc = llvm.AddFunction(c.mod, "runtime.printuint", printuintType)
|
||||||
printbyteType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.Int8Type()}, false)
|
printbyteType := llvm.FunctionType(llvm.VoidType(), []llvm.Type{llvm.Int8Type()}, false)
|
||||||
c.printbyteFunc = llvm.AddFunction(c.mod, "runtime.printbyte", printbyteType)
|
c.printbyteFunc = llvm.AddFunction(c.mod, "runtime.printbyte", printbyteType)
|
||||||
printspaceType := llvm.FunctionType(llvm.VoidType(), nil, false)
|
printspaceType := llvm.FunctionType(llvm.VoidType(), nil, false)
|
||||||
|
@ -273,12 +276,16 @@ func (c *Compiler) getLLVMType(goType types.Type) (llvm.Type, error) {
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case types.Bool:
|
case types.Bool:
|
||||||
return llvm.Int1Type(), nil
|
return llvm.Int1Type(), nil
|
||||||
case types.Uint8:
|
case types.Int8, types.Uint8:
|
||||||
return llvm.Int8Type(), nil
|
return llvm.Int8Type(), nil
|
||||||
case types.Int:
|
case types.Int16, types.Uint16:
|
||||||
return c.intType, nil
|
return llvm.Int16Type(), nil
|
||||||
case types.Int32:
|
case types.Int32, types.Uint32:
|
||||||
return llvm.Int32Type(), nil
|
return llvm.Int32Type(), nil
|
||||||
|
case types.Int, types.Uint:
|
||||||
|
return c.intType, nil
|
||||||
|
case types.Int64, types.Uint64:
|
||||||
|
return llvm.Int64Type(), nil
|
||||||
case types.String:
|
case types.String:
|
||||||
return c.stringType, nil
|
return c.stringType, nil
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
|
@ -501,6 +508,8 @@ func (c *Compiler) parseBuiltin(frame *Frame, args []ssa.Value, callName string)
|
||||||
c.builder.CreateCall(c.printbyteFunc, []llvm.Value{value}, "")
|
c.builder.CreateCall(c.printbyteFunc, []llvm.Value{value}, "")
|
||||||
case types.Int, types.Int32: // TODO: assumes a 32-bit int type
|
case types.Int, types.Int32: // TODO: assumes a 32-bit int type
|
||||||
c.builder.CreateCall(c.printintFunc, []llvm.Value{value}, "")
|
c.builder.CreateCall(c.printintFunc, []llvm.Value{value}, "")
|
||||||
|
case types.Uint, types.Uint32:
|
||||||
|
c.builder.CreateCall(c.printuintFunc, []llvm.Value{value}, "")
|
||||||
case types.String:
|
case types.String:
|
||||||
c.builder.CreateCall(c.printstringFunc, []llvm.Value{value}, "")
|
c.builder.CreateCall(c.printstringFunc, []llvm.Value{value}, "")
|
||||||
default:
|
default:
|
||||||
|
@ -730,7 +739,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
switch typ := expr.X.Type().(type) {
|
switch typ := expr.X.Type().(type) {
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
itfValueType := llvm.PointerType(llvm.Int8Type(), 0)
|
itfValueType := llvm.PointerType(llvm.Int8Type(), 0)
|
||||||
if typ.Info() & types.IsInteger != 0 {
|
if typ.Info() & types.IsInteger != 0 { // TODO: 64-bit int on 32-bit platform
|
||||||
itfValue = c.builder.CreateIntToPtr(val, itfValueType, "")
|
itfValue = c.builder.CreateIntToPtr(val, itfValueType, "")
|
||||||
} else if typ.Kind() == types.String {
|
} else if typ.Kind() == types.String {
|
||||||
// TODO: escape analysis
|
// TODO: escape analysis
|
||||||
|
@ -805,6 +814,7 @@ func (c *Compiler) parseBinOp(frame *Frame, binop *ssa.BinOp) (llvm.Value, error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
|
signed := binop.X.Type().(*types.Basic).Info() & types.IsUnsigned == 0
|
||||||
switch binop.Op {
|
switch binop.Op {
|
||||||
case token.ADD: // +
|
case token.ADD: // +
|
||||||
return c.builder.CreateAdd(x, y, ""), nil
|
return c.builder.CreateAdd(x, y, ""), nil
|
||||||
|
@ -813,9 +823,17 @@ func (c *Compiler) parseBinOp(frame *Frame, binop *ssa.BinOp) (llvm.Value, error
|
||||||
case token.MUL: // *
|
case token.MUL: // *
|
||||||
return c.builder.CreateMul(x, y, ""), nil
|
return c.builder.CreateMul(x, y, ""), nil
|
||||||
case token.QUO: // /
|
case token.QUO: // /
|
||||||
return c.builder.CreateSDiv(x, y, ""), nil // TODO: UDiv (unsigned)
|
if signed {
|
||||||
|
return c.builder.CreateSDiv(x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateUDiv(x, y, ""), nil
|
||||||
|
}
|
||||||
case token.REM: // %
|
case token.REM: // %
|
||||||
return c.builder.CreateSRem(x, y, ""), nil // TODO: URem (unsigned)
|
if signed {
|
||||||
|
return c.builder.CreateSRem(x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateURem(x, y, ""), nil
|
||||||
|
}
|
||||||
case token.AND: // &
|
case token.AND: // &
|
||||||
return c.builder.CreateAnd(x, y, ""), nil
|
return c.builder.CreateAnd(x, y, ""), nil
|
||||||
case token.OR: // |
|
case token.OR: // |
|
||||||
|
@ -825,7 +843,11 @@ func (c *Compiler) parseBinOp(frame *Frame, binop *ssa.BinOp) (llvm.Value, error
|
||||||
case token.SHL: // <<
|
case token.SHL: // <<
|
||||||
return c.builder.CreateShl(x, y, ""), nil
|
return c.builder.CreateShl(x, y, ""), nil
|
||||||
case token.SHR: // >>
|
case token.SHR: // >>
|
||||||
return c.builder.CreateAShr(x, y, ""), nil // TODO: LShr (unsigned)
|
if signed {
|
||||||
|
return c.builder.CreateAShr(x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateLShr(x, y, ""), nil
|
||||||
|
}
|
||||||
case token.AND_NOT: // &^
|
case token.AND_NOT: // &^
|
||||||
// Go specific. Calculate "and not" with x & (~y)
|
// Go specific. Calculate "and not" with x & (~y)
|
||||||
inv := c.builder.CreateNot(y, "") // ~y
|
inv := c.builder.CreateNot(y, "") // ~y
|
||||||
|
@ -835,13 +857,29 @@ func (c *Compiler) parseBinOp(frame *Frame, binop *ssa.BinOp) (llvm.Value, error
|
||||||
case token.NEQ: // !=
|
case token.NEQ: // !=
|
||||||
return c.builder.CreateICmp(llvm.IntNE, x, y, ""), nil
|
return c.builder.CreateICmp(llvm.IntNE, x, y, ""), nil
|
||||||
case token.LSS: // <
|
case token.LSS: // <
|
||||||
return c.builder.CreateICmp(llvm.IntSLT, x, y, ""), nil // TODO: ULT
|
if signed {
|
||||||
|
return c.builder.CreateICmp(llvm.IntSLT, x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateICmp(llvm.IntULT, x, y, ""), nil
|
||||||
|
}
|
||||||
case token.LEQ: // <=
|
case token.LEQ: // <=
|
||||||
return c.builder.CreateICmp(llvm.IntSLE, x, y, ""), nil // TODO: ULE
|
if signed {
|
||||||
|
return c.builder.CreateICmp(llvm.IntSLE, x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateICmp(llvm.IntULE, x, y, ""), nil
|
||||||
|
}
|
||||||
case token.GTR: // >
|
case token.GTR: // >
|
||||||
return c.builder.CreateICmp(llvm.IntSGT, x, y, ""), nil // TODO: UGT
|
if signed {
|
||||||
|
return c.builder.CreateICmp(llvm.IntSGT, x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateICmp(llvm.IntUGT, x, y, ""), nil
|
||||||
|
}
|
||||||
case token.GEQ: // >=
|
case token.GEQ: // >=
|
||||||
return c.builder.CreateICmp(llvm.IntSGE, x, y, ""), nil // TODO: UGE
|
if signed {
|
||||||
|
return c.builder.CreateICmp(llvm.IntSGE, x, y, ""), nil
|
||||||
|
} else {
|
||||||
|
return c.builder.CreateICmp(llvm.IntUGE, x, y, ""), nil
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, errors.New("unknown binop")
|
return llvm.Value{}, errors.New("unknown binop")
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче