// 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 { // Early return if v is already of the correct type. from := v.Type() if irtypes.Equal(from, to) { return v } fromType, ok := from.(*irtypes.Int) if !ok { panic(fmt.Sprintf("support for converting from type %T not yet implemented", from)) } toType, ok := to.(*irtypes.Int) if !ok { panic(fmt.Sprintf("support for converting to type %T not yet implemented", to)) } // Convert constant values. if v, ok := v.(constant.Constant); ok { switch v := v.(type) { case *constant.Int: v, err := constant.NewInt(toType, v.ValueString()) if err != nil { panic(fmt.Sprintf("unable to create integer constant; %v", err)) } return v default: panic(fmt.Sprintf("support for converting type %T not yet implemented", v)) } } // TODO: Add proper support for converting signed and unsigned values, using // sext and zext, respectively. // Convert unsigned values. if irtypes.IsBool(fromType) { // Zero extend boolean values. zextInst, err := instruction.NewZExt(v, toType) if err != nil { panic(fmt.Sprintf("unable to create sext instruction; %v", err)) } return f.emitInst(zextInst) } // Convert signed values. if toType.Size() > fromType.Size() { // Sign extend. sextInst, err := instruction.NewSExt(v, toType) if err != nil { panic(fmt.Sprintf("unable to create sext instruction; %v", err)) } return f.emitInst(sextInst) } // Truncate. truncInst, err := instruction.NewTrunc(v, toType) if err != nil { panic(fmt.Sprintf("unable to create trunc instruction; %v", err)) } return f.emitInst(truncInst) }
// NewZExtInst returns a new zext instruction based on the given value and // target type. func NewZExtInst(fromType, fromVal, to interface{}) (*instruction.ZExt, error) { from, err := NewValue(fromType, fromVal) if err != nil { return nil, errutil.Err(err) } if to, ok := to.(types.Type); ok { return instruction.NewZExt(from, to) } return nil, errutil.Newf("invalid target type; expected types.Type, got %T", to) }
// unaryExpr lowers the given unary expression to LLVM IR, emitting code to f. func (m *Module) unaryExpr(f *Function, n *ast.UnaryExpr) value.Value { switch n.Op { // -expr case token.Sub: // Input: // void f() { // int x; // -x; // <-- relevant line // } // Output: // %2 = sub i32 0, %1 expr := m.expr(f, n.X) zero := constZero(expr.Type()) subInst, err := instruction.NewSub(zero, expr) if err != nil { panic(fmt.Sprintf("unable to create sub instruction; %v", err)) } // Emit sub instruction. return f.emitInst(subInst) // !expr case token.Not: // TODO: Replace `(x != 0) ^ 1` with `x == 0`. Using the former for now to // simplify test cases, as they are generated by Clang. // Input: // int g() { // int y; // !y; // <-- relevant line // } // Output: // %2 = icmp ne i32 %1, 0 // %3 = xor i1 %2, true cond := m.cond(f, n.X) one := constOne(cond.Type()) xorInst, err := instruction.NewXor(cond, one) if err != nil { panic(fmt.Sprintf("unable to create xor instruction; %v", err)) } // Emit xor instruction. notCond := f.emitInst(xorInst) zextInst, err := instruction.NewZExt(notCond, m.typeOf(n.X)) if err != nil { panic(fmt.Sprintf("unable to create zext instruction; %v", err)) } // Emit zext instruction. return f.emitInst(zextInst) default: panic(fmt.Sprintf("support for unary operator %v not yet implemented", n.Op)) } }
// fixValueInst replaces dummy values within the given value instruction with // their corresponding local variables. func (m dummyMap) fixValueInst(oldValInst instruction.ValueInst) instruction.ValueInst { switch oldValInst := oldValInst.(type) { // Binary Operations case *instruction.Add: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewAdd(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FAdd: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFAdd(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Sub: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSub(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FSub: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFSub(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Mul: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewMul(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FMul: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFMul(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.UDiv: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewUDiv(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SDiv: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSDiv(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FDiv: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFDiv(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.URem: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewURem(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SRem: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSRem(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FRem: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewFRem(x, y) if err != nil { panic(errutil.Err(err)) } return inst // Bitwise Binary Operations case *instruction.ShL: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewShL(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.LShR: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewLShR(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.AShR: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewAShR(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.And: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewAnd(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Or: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewOr(x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Xor: x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewXor(x, y) if err != nil { panic(errutil.Err(err)) } return inst // Vector Operations case *instruction.ExtractElement: panic("irx.dummyMap.fixValueInst: ExtractElement not yet implemented") case *instruction.InsertElement: panic("irx.dummyMap.fixValueInst: InsertElement not yet implemented") case *instruction.ShuffleVector: panic("irx.dummyMap.fixValueInst: ShuffleVector not yet implemented") // Aggregate Operations case *instruction.ExtractValue: panic("irx.dummyMap.fixValueInst: ExtractValue not yet implemented") case *instruction.InsertValue: panic("irx.dummyMap.fixValueInst: InsertValue not yet implemented") // Memory Access and Addressing Operations case *instruction.Alloca: // Nothing to do; alloca contains no dummy values. return oldValInst case *instruction.Load: srcAddr := m.fixValue(oldValInst.SrcAddr()) inst, err := instruction.NewLoad(srcAddr) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.CmpXchg: panic("irx.dummyMap.fixValueInst: CmpXchg not yet implemented") case *instruction.AtomicRMW: panic("irx.dummyMap.fixValueInst: AtomicRMW not yet implemented") case *instruction.GetElementPtr: srcAddr := m.fixValue(oldValInst.SrcAddr()) var indices []value.Value for _, oldIndex := range oldValInst.Indices() { index := m.fixValue(oldIndex) indices = append(indices, index) } inst, err := instruction.NewGetElementPtr(srcAddr, indices) if err != nil { panic(errutil.Err(err)) } return inst // Conversion Operations case *instruction.Trunc: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewTrunc(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.ZExt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewZExt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SExt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewSExt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPTrunc: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPTrunc(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPExt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPExt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPToUI: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPToUI(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FPToSI: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewFPToSI(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.UIToFP: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewUIToFP(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.SIToFP: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewSIToFP(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.PtrToInt: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewPtrToInt(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.IntToPtr: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewIntToPtr(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.BitCast: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewBitCast(from, to) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.AddrSpaceCast: from := m.fixValue(oldValInst.From()) to := oldValInst.RetType() inst, err := instruction.NewAddrSpaceCast(from, to) if err != nil { panic(errutil.Err(err)) } return inst // Other Operations case *instruction.ICmp: cond := oldValInst.Cond() x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewICmp(cond, x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.FCmp: panic("irx.dummyMap.fixValueInst: FCmp not yet implemented") case *instruction.PHI: oldIncs := oldValInst.Incs() var incs []*instruction.Incoming for _, oldInc := range oldIncs { val := m.fixValue(oldInc.Value()) pred := m.fixNamedValue(oldInc.Pred()) inc, err := instruction.NewIncoming(val, pred) if err != nil { panic(errutil.Err(err)) } incs = append(incs, inc) } inst, err := instruction.NewPHI(incs) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Select: cond := m.fixValue(oldValInst.Cond()) x := m.fixValue(oldValInst.X()) y := m.fixValue(oldValInst.Y()) inst, err := instruction.NewSelect(cond, x, y) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.Call: result := oldValInst.RetType() // TODO: Fix value of callee if the type of Callee changes from string to // value.Value. callee := oldValInst.Callee() var args []value.Value for _, oldArg := range oldValInst.Args() { arg := m.fixValue(oldArg) args = append(args, arg) } inst, err := instruction.NewCall(result, callee, args) if err != nil { panic(errutil.Err(err)) } return inst case *instruction.VAArg: panic("irx.dummyMap.fixValueInst: VAArg not yet implemented") case *instruction.LandingPad: panic("irx.dummyMap.fixValueInst: LandingPad not yet implemented") case *instruction.CatchPad: panic("irx.dummyMap.fixValueInst: CatchPad not yet implemented") case *instruction.CleanupPad: panic("irx.dummyMap.fixValueInst: CleanupPad not yet implemented") default: panic("irx.dummyMap.fixValueInst: not yet implemented") } }