Skip to content

Commit

Permalink
irgen: Add initial implementation of implicit conversion.
Browse files Browse the repository at this point in the history
Updates #69.
  • Loading branch information
mewmew committed Jun 18, 2016
1 parent 55ee8f1 commit 12442ba
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 3 deletions.
2 changes: 2 additions & 0 deletions irgen/irgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,11 @@ func TestGen(t *testing.T) {
got, want := module.String(), string(buf)
if got != want {
t.Errorf("%q: module mismatch; expected `%v`, got `%v`", g.path, want, got)
// TODO: Remove debug output.
fmt.Println("### FAIL:", g.path)
continue
}
// TODO: Remove debug output.
fmt.Println("PASS:", g.path)
}
}
22 changes: 19 additions & 3 deletions irgen/lower.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ func (m *Module) funcParam(f *Function, param *irtypes.Param) value.Value {
panic(fmt.Sprintf("unable to create alloca instruction; %v", err))
}
// Emit local variable definition for the given function parameter.
p := f.emitInst(allocaInst)
storeInst, err := instruction.NewStore(param, p)
addr := f.emitInst(allocaInst)
storeInst, err := instruction.NewStore(param, addr)
if err != nil {
panic(fmt.Sprintf("unable to create store instruction; %v", err))
}
f.curBlock.AppendInst(storeInst)
return p
return addr
}

// --- [ Global variable declaration ] -----------------------------------------
Expand Down Expand Up @@ -320,6 +320,7 @@ func (m *Module) returnStmt(f *Function, stmt *ast.ReturnStmt) {
return
}
result := m.expr(f, stmt.Result)
// Implicit conversion.
resultType := f.Sig().Result()
result = m.convert(f, result, resultType)
term, err := instruction.NewRet(result.Type(), result)
Expand Down Expand Up @@ -428,6 +429,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// +
case token.Add:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
addInst, err := instruction.NewAdd(x, y)
if err != nil {
panic(fmt.Sprintf("unable to create add instruction; %v", err))
Expand All @@ -438,6 +440,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// -
case token.Sub:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
subInst, err := instruction.NewSub(x, y)
if err != nil {
panic(fmt.Sprintf("unable to create sub instruction; %v", err))
Expand All @@ -448,6 +451,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// *
case token.Mul:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
mulInst, err := instruction.NewMul(x, y)
if err != nil {
panic(fmt.Sprintf("unable to create mul instruction; %v", err))
Expand All @@ -458,6 +462,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// /
case token.Div:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
// TODO: Add support for unsigned division.
sdivInst, err := instruction.NewSDiv(x, y)
if err != nil {
Expand All @@ -469,6 +474,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// <
case token.Lt:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
icmpInst, err := instruction.NewICmp(instruction.ICondSLT, x, y)
if err != nil {
panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
Expand All @@ -479,6 +485,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// >
case token.Gt:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
icmpInst, err := instruction.NewICmp(instruction.ICondSGT, x, y)
if err != nil {
panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
Expand All @@ -489,6 +496,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// <=
case token.Le:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
icmpInst, err := instruction.NewICmp(instruction.ICondSLE, x, y)
if err != nil {
panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
Expand All @@ -499,6 +507,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// >=
case token.Ge:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
icmpInst, err := instruction.NewICmp(instruction.ICondSGE, x, y)
if err != nil {
panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
Expand All @@ -509,6 +518,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// !=
case token.Ne:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
icmpInst, err := instruction.NewICmp(instruction.ICondNE, x, y)
if err != nil {
panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
Expand All @@ -519,6 +529,7 @@ func (m *Module) binaryExpr(f *Function, n *ast.BinaryExpr) value.Value {
// ==
case token.Eq:
x, y := m.expr(f, n.X), m.expr(f, n.Y)
x, y = m.implicitConversion(f, x, y)
icmpInst, err := instruction.NewICmp(instruction.ICondEq, x, y)
if err != nil {
panic(fmt.Sprintf("unable to create icmp instruction; %v", err))
Expand Down Expand Up @@ -636,6 +647,11 @@ func (m *Module) identUse(f *Function, ident *ast.Ident) value.Value {
// f.
func (m *Module) identDef(f *Function, ident *ast.Ident, v value.Value) {
addr := m.ident(f, ident)
addrType, ok := addr.Type().(*irtypes.Pointer)
if !ok {
panic(fmt.Sprintf("invalid pointer type; expected *types.Pointer, got %T", addr.Type()))
}
v = m.convert(f, v, addrType.Elem())
storeInst, err := instruction.NewStore(v, addr)
if err != nil {
panic(fmt.Sprintf("unable to create store instruction; %v", err))
Expand Down
29 changes: 29 additions & 0 deletions irgen/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ import (
uctypes "github.com/mewmew/uc/types"
)

// implicitConversion implicitly converts the value of the smallest type to the
// largest type of x and y, emitting code to f. The new values of x and y are
// returned.
func (m *Module) implicitConversion(f *Function, x, y value.Value) (value.Value, value.Value) {
// Implicit conversion.
switch {
case isLarger(x.Type(), y.Type()):
y = m.convert(f, y, x.Type())
case isLarger(y.Type(), x.Type()):
x = m.convert(f, x, y.Type())
}
return x, y
}

// convert converts the given value to the specified type, emitting code to f.
// No conversion is made, if v is already of the correct type.
func (m *Module) convert(f *Function, v value.Value, to irtypes.Type) value.Value {
Expand Down Expand Up @@ -65,6 +79,21 @@ func (m *Module) convert(f *Function, v value.Value, to irtypes.Type) value.Valu
return f.emitInst(sextInst)
}

// isLarger reports whether t has higher precision than u.
func isLarger(t, u irtypes.Type) bool {
// A Sizer is a type with a size in number of bits.
type Sizer interface {
// Size returns the size of t in number of bits.
Size() int
}
if t, ok := t.(Sizer); ok {
if u, ok := u.(Sizer); ok {
return t.Size() > u.Size()
}
}
return false
}

// isRef reports whether the given type is a reference type; e.g. pointer or
// array.
func isRef(typ irtypes.Type) bool {
Expand Down

0 comments on commit 12442ba

Please sign in to comment.