// NewGlobalDef returns a new global variable definition of the given name and // initial value. The variable is read-only if immutable is true. func NewGlobalDef(name string, val value.Value, immutable bool) (*GlobalDecl, error) { d, err := NewGlobalDecl(name, val.Type(), immutable) if err != nil { return nil, errutil.Err(err) } d.val = val return d, nil }
// 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) }
// NewLoad returns a new load instruction based on the given source address. // // Pre-conditions: // 1. srcAddr is of pointer type func NewLoad(srcAddr value.Value) (*Load, error) { // Validate that srcAddr is of pointer type. srcAddrType, ok := srcAddr.Type().(*types.Pointer) if !ok { return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type()) } // Determine result type. typ := srcAddrType.Elem() return &Load{srcAddr: srcAddr, typ: typ}, nil }
// NewBr returns a new conditional branch instruction based on the given // branching condition, and the true and false target branches. func NewBr(cond value.Value, trueBranch, falseBranch value.NamedValue) (*Br, error) { // TODO: Validate that trueBranch and falseBranch are of type *ir.BasicBlock. // Better yet, chance the signature of NewBr to enforce this. Another // approach, is to simply check that the type of trueBranch and falseBranch // are both "label". if !types.Equal(cond.Type(), types.I1) { return nil, errutil.Newf("conditional type mismatch; expected i1, got %v", cond.Type()) } return &Br{cond: cond, trueBranch: trueBranch, falseBranch: falseBranch}, nil }
// NewSelect returns a new select instruction based on the given selection // condition, and operands. // // Pre-condition: cond is of boolean or boolean vector type. x and y are of // identical types. func NewSelect(cond, x, y value.Value) (*Select, error) { // Validate that cond is of boolean or boolean vector type. if !types.IsBools(cond.Type()) { return nil, errutil.Newf("invalid selection condition type; expected boolean or boolean vector, got %v", cond.Type()) } // Validate that x and y are of identical types. if !types.Equal(x.Type(), y.Type()) { return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type()) } return &Select{cond: cond, x: x, y: y}, nil }
// NewStore returns a new store instruction based on the given source value and // destination address. // // Pre-condition: // 1. dstAddr is of pointer type // 2. src is of identical type as the element type of dstAddr func NewStore(src, dstAddr value.Value) (*Store, error) { // Validate that dstAddr is of pointer type. dstAddrType, ok := dstAddr.Type().(*types.Pointer) if !ok { return nil, errutil.Newf("invalid destination address pointer type; expected *types.Pointer, got %T", dstAddr.Type()) } // Validate that src is of identical type as the element type of dstAddr. if !types.Equal(src.Type(), dstAddrType.Elem()) { return nil, errutil.Newf("type mismatch between source value (%v) and destination address element type (%v)", src.Type(), dstAddrType.Elem()) } return &Store{src: src, dstAddr: dstAddr}, nil }
// NewGetElementPtr returns a new getelementptr instruction based on the given // source address and element indices. // // Pre-condition: // 1. srcAddr is of pointer type // 2. indices used to index structure fields are integer constants func NewGetElementPtr(srcAddr value.Value, indices []value.Value) (*GetElementPtr, error) { // Validate that srcAddr is of pointer type. srcAddrType, ok := srcAddr.Type().(*types.Pointer) if !ok { return nil, errutil.Newf("invalid source address pointer type; expected *types.Pointer, got %T", srcAddr.Type()) } // Validate that indices used to index structure fields are integer // constants. e := srcAddrType.Elem() for i, index := range indices { if i == 0 { // Ignore checking the 0th index as it simply follows the pointer of // srcAddr. // // ref: http://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required continue } switch ee := e.(type) { case *types.Pointer: // ref: http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep return nil, errutil.Newf(`unable to index into element of pointer type; for more information, see http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep`) case *types.Array: e = ee.Elem() case *types.Struct: idx, ok := index.(*constant.Int) if !ok { return nil, errutil.Newf("invalid index type for structure element; expected *constant.Int, got %T", index) } e = ee.Fields()[idx.Value().Int64()] default: panic(fmt.Sprintf("instruction.NewGetElementPtr: support for indexing element type %T not yet implemented", e)) } } // Determine result type. typ, err := types.NewPointer(e) if err != nil { return nil, errutil.Err(err) } // Determine element type. elem := srcAddrType.Elem() return &GetElementPtr{srcAddr: srcAddr, indices: indices, typ: typ, elem: elem}, nil }
// NewGetElementPtr returns a new getelementptr expression based on the given // element type, address and element indices. // // Preconditions: // * elem is of the same type as addr.Type().Elem(). // * addr is of pointer type. // * indices used to index structure fields are integer constants. func NewGetElementPtr(elem types.Type, addr value.Value, indices []Constant) (*GetElementPtr, error) { // Sanity checks. addrType, ok := addr.Type().(*types.Pointer) if !ok { return nil, errutil.Newf("invalid pointer type; expected *types.Pointer, got %T", addr.Type()) } if !types.Equal(elem, addrType.Elem()) { return nil, errutil.Newf("type mismatch between %v and %v", elem, addrType.Elem()) } e := addrType.Elem() for i, index := range indices { if i == 0 { // Ignore checking the 0th index as it simply follows the pointer of // addr. // // ref: http://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required continue } switch ee := e.(type) { case *types.Pointer: // ref: http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep return nil, errutil.Newf(`unable to index into element of pointer type; for more information, see http://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep`) case *types.Array: e = ee.Elem() case *types.Struct: idx, ok := index.(*Int) if !ok { return nil, errutil.Newf("invalid index type for structure element; expected *constant.Int, got %T", index) } e = ee.Fields()[idx.Value().Int64()] default: panic(fmt.Sprintf("constant.NewGetElementPtr: support for indexing element type %T not yet implemented", e)) } } typ, err := types.NewPointer(e) if err != nil { return nil, errutil.Err(err) } return &GetElementPtr{typ: typ, elem: elem, addr: addr, indices: indices}, nil }
// NewRet returns a new ret instruction based on the given return value. A nil // return value indicates a "void" return instruction. func NewRet(val value.Value) (*Ret, error) { if val != nil && types.IsVoid(val.Type()) { return nil, errutil.Newf(`expected no return value for return type "void"; got %q`, val) } return &Ret{val: val}, nil }
// NewFAdd returns a new fadd instruction based on the given operands. func NewFAdd(x, y value.Value) (*FAdd, error) { if !types.Equal(x.Type(), y.Type()) { return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type()) } return &FAdd{x: x, y: y}, nil }
// NewICmp returns a new icmp instruction based on the given condition and // operands. // // Pre-condition: x and y are of identical types. x and y are of integer, // integer vector, pointer or pointer vector type. func NewICmp(cond ICond, x, y value.Value) (*ICmp, error) { // Validate that x and y are of identical types. if !types.Equal(x.Type(), y.Type()) { return nil, errutil.Newf("type mismatch between x (%v) and y (%v)", x.Type(), y.Type()) } // Validate that x and y are of integer, integer vector, pointer or pointer // vector type. if !types.IsInts(x.Type()) && !types.IsPointers(x.Type()) { return nil, errutil.Newf("invalid x operand type; expected integer, integer vector, pointer or pointer vector, got %v", x.Type()) } if !types.IsInts(y.Type()) && !types.IsPointers(y.Type()) { return nil, errutil.Newf("invalid y operand type; expected integer, integer vector, pointer or pointer vector, got %v", y.Type()) } return &ICmp{cond: cond, x: x, y: y}, nil }
// 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 }