// constOne returns the integer constant one of the given type. func constOne(typ irtypes.Type) constant.Constant { one, err := constant.NewInt(typ, "1") if err != nil { panic(fmt.Sprintf("unable to create integer constant one; %v", err)) } return one }
// constZero returns the integer constant zero of the given type. func constZero(typ irtypes.Type) constant.Constant { zero, err := constant.NewInt(typ, "0") if err != nil { panic(fmt.Sprintf("unable to create integer constant zero; %v", err)) } return zero }
// globalVarDecl lowers the given global variable declaration to LLVM IR, // emitting code to m. func (m *Module) globalVarDecl(n *ast.VarDecl) { // Input: // int x; // Output: // @x = global i32 0 ident := n.Name() dbg.Printf("create global variable: %v", n) typ := toIrType(n.Type()) var val value.Value switch { case n.Val != nil: panic("support for global variable initializer not yet implemented") case irtypes.IsInt(typ): var err error val, err = constant.NewInt(typ, "0") if err != nil { panic(fmt.Sprintf("unable to create integer constant; %v", err)) } default: val = constant.NewZeroInitializer(typ) } global, err := ir.NewGlobalDef(ident.Name, val, false) if err != nil { panic(fmt.Sprintf("unable to create global variable definition %q", ident)) } m.setIdentValue(ident, global) // Emit global variable definition. m.emitGlobal(global) }
// 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) }
// basicLit lowers the given basic literal to LLVM IR, emitting code to f. func (m *Module) basicLit(f *Function, n *ast.BasicLit) value.Value { typ := m.typeOf(n) switch n.Kind { case token.CharLit: s, err := strconv.Unquote(n.Val) if err != nil { panic(fmt.Sprintf("unable to unquote character literal; %v", err)) } val, err := constant.NewInt(typ, strconv.Itoa(int(s[0]))) if err != nil { panic(fmt.Sprintf("unable to create integer constant; %v", err)) } return val case token.IntLit: val, err := constant.NewInt(typ, n.Val) if err != nil { panic(fmt.Sprintf("unable to create integer constant; %v", err)) } return val default: panic(fmt.Sprintf("support for basic literal kind %v not yet implemented", n.Kind)) } }
// NewValue returns a new value based on the given type and value. func NewValue(typ, val interface{}) (value.Value, error) { // TODO: Verify type equality between typ and val.Type(). // * handled by constant.NewInt // * ... if typ, ok := typ.(types.Type); ok { switch val := val.(type) { case *LocalDummy: return val, nil case *Global: // TODO: Retreive type from val.typ once support for forward reference // of global variable declarations have been added. // TODO: Add type-check between ptrType and val.typ. if typ, ok := typ.(*types.Pointer); ok { return constant.NewPointer(typ, val.name) } return nil, errutil.Newf("invalid global type; expected *types.Pointer, got %T", typ) case *IntConst: return constant.NewInt(typ, val.val) case *NullPointerConst: if typ, ok := typ.(*types.Pointer); ok { return constant.NewNullPointer(typ) } return nil, errutil.Newf("invalid null pointer type; expected *types.Pointer, got %T", typ) case *CharArrayConst: return constant.NewCharArray(typ, val.val) case *ZeroInitializer: return constant.NewZeroInitializer(typ), nil case *GetElementPtrExpr: return constant.NewGetElementPtr(val.elem, val.addr, val.indices) default: pretty.Println(val) panic(fmt.Sprintf("support for value type %T not yet implemented", val)) } } return nil, errutil.Newf("invalid value type; expected types.Type, got %T", typ) }
func init() { // i1 var err error i1Typ, err = types.NewInt(1) if err != nil { log.Fatalln(err) } // i3 i3Typ, err = types.NewInt(3) if err != nil { log.Fatalln(err) } // i5 i5Typ, err = types.NewInt(5) if err != nil { log.Fatalln(err) } // i8 i8Typ, err = types.NewInt(8) if err != nil { log.Fatalln(err) } // i32 i32Typ, err = types.NewInt(32) if err != nil { log.Fatalln(err) } // i64 i64Typ, err = types.NewInt(64) if err != nil { log.Fatalln(err) } // float f32Typ, err = types.NewFloat(types.Float32) if err != nil { log.Fatalln(err) } // double f64Typ, err = types.NewFloat(types.Float64) if err != nil { log.Fatalln(err) } // fp128 f128Typ, err = types.NewFloat(types.Float128) if err != nil { log.Fatalln(err) } // ppc_fp128 f128_ppcTyp, err = types.NewFloat(types.Float128_PPC) if err != nil { log.Fatalln(err) } // <2 x i32> i32x2VecTyp, err = types.NewVector(i32Typ, 2) if err != nil { log.Fatalln(err) } // <3 x i32> i32x3VecTyp, err = types.NewVector(i32Typ, 3) if err != nil { log.Fatalln(err) } // <2 x float> f32x2VecTyp, err = types.NewVector(f32Typ, 2) if err != nil { log.Fatalln(err) } // <3 x float> f32x3VecTyp, err = types.NewVector(f32Typ, 3) if err != nil { log.Fatalln(err) } // [2 x i32] i32x2ArrTyp, err = types.NewArray(i32Typ, 2) if err != nil { log.Fatalln(err) } // {i32, i8} i32i8StructTyp, err = types.NewStruct([]types.Type{i32Typ, i8Typ}, false) if err != nil { log.Fatalln(err) } // [2 x {i32, i8}] i32i8x2ArrTyp, err = types.NewArray(i32i8StructTyp, 2) if err != nil { log.Fatalln(err) } // i1 1 i1One, err = constant.NewInt(i1Typ, "1") if err != nil { log.Fatalln(err) } // i8 3 i8Three, err = constant.NewInt(i8Typ, "3") if err != nil { log.Fatalln(err) } // i8 4 i8Four, err = constant.NewInt(i8Typ, "4") if err != nil { log.Fatalln(err) } // i32 -13 i32MinusThirteen, err = constant.NewInt(i32Typ, "-13") if err != nil { log.Fatalln(err) } // i32 -4 i32MinusFour, err = constant.NewInt(i32Typ, "-4") if err != nil { log.Fatalln(err) } // i32 -3 i32MinusThree, err = constant.NewInt(i32Typ, "-3") if err != nil { log.Fatalln(err) } // i32 1 i32One, err = constant.NewInt(i32Typ, "1") if err != nil { log.Fatalln(err) } // i32 2 i32Two, err = constant.NewInt(i32Typ, "2") if err != nil { log.Fatalln(err) } // i32 3 i32Three, err = constant.NewInt(i32Typ, "3") if err != nil { log.Fatalln(err) } // i32 4 i32Four, err = constant.NewInt(i32Typ, "4") if err != nil { log.Fatalln(err) } // i32 15 i32Fifteen, err = constant.NewInt(i32Typ, "15") if err != nil { log.Fatalln(err) } // i32 42 i32FortyTwo, err = constant.NewInt(i32Typ, "42") if err != nil { log.Fatalln(err) } // float -3.0 f32MinusThree, err = constant.NewFloat(f32Typ, "-3.0") if err != nil { log.Fatalln(err) } // float -4.0 f32MinusFour, err = constant.NewFloat(f32Typ, "-4.0") if err != nil { log.Fatalln(err) } // float 1.0 f32One, err = constant.NewFloat(f32Typ, "1.0") if err != nil { log.Fatalln(err) } // float 2.0 f32Two, err = constant.NewFloat(f32Typ, "2.0") if err != nil { log.Fatalln(err) } // float 3.0 f32Three, err = constant.NewFloat(f32Typ, "3.0") if err != nil { log.Fatalln(err) } // float 4.0 f32Four, err = constant.NewFloat(f32Typ, "4.0") if err != nil { log.Fatalln(err) } // double 4.0 f64Four, err = constant.NewFloat(f64Typ, "4.0") if err != nil { log.Fatalln(err) } // TODO: Uncomment when fp128 and ppc_fp128 are supported. /* // fp128 3.0 f128Three, err = constant.NewFloat(f128Typ, "3.0") if err != nil { log.Fatalln(err) } // ppc_fp128 4.0 f128_ppcFour, err = constant.NewFloat(f128_ppcTyp, "4.0") if err != nil { log.Fatalln(err) } */ // <3 x i32> <i32 1, i32 2, i32 3> i32x3OneTwoThree, err = constant.NewVector(i32x3VecTyp, []constant.Constant{i32One, i32Two, i32Three}) if err != nil { log.Fatalln(err) } // <2 x i32> <i32 3, i32 42> i32x2VecThreeFortyTwo, err = constant.NewVector(i32x2VecTyp, []constant.Constant{i32Three, i32FortyTwo}) if err != nil { log.Fatalln(err) } // <2 x i32> <i32 -3, i32 15> i32x2VecMinusThreeFifteen, err = constant.NewVector(i32x2VecTyp, []constant.Constant{i32MinusThree, i32Fifteen}) if err != nil { log.Fatalln(err) } // <2 x float> <float 3.0, float 4.0> f32x2VecThreeFour, err = constant.NewVector(f32x2VecTyp, []constant.Constant{f32Three, f32Four}) if err != nil { log.Fatalln(err) } // <2 x float> <float -3.0, float 4.0> f32x2VecMinusThreeFour, err = constant.NewVector(f32x2VecTyp, []constant.Constant{f32MinusThree, f32Four}) if err != nil { log.Fatalln(err) } // <3 x float> <float 3.0, float 2.0, float 1.0> f32x3VecThreeFourFifteen, err = constant.NewVector(f32x3VecTyp, []constant.Constant{f32Three, f32Two, f32One}) if err != nil { log.Fatalln(err) } // {i32, i8} {i32 4, i8 3} i32i8FourThree, err = constant.NewStruct(i32i8StructTyp, []constant.Constant{i32Four, i8Three}) if err != nil { log.Fatalln(err) } // {i32, i8} {i32 3, i8 4} i32i8ThreeFour, err = constant.NewStruct(i32i8StructTyp, []constant.Constant{i32Three, i8Four}) if err != nil { log.Fatalln(err) } }
func TestIntString(t *testing.T) { golden := []struct { input string typ types.Type want string err string }{ // i=0 { input: "true", typ: i1Typ, want: "i1 true", }, // i=1 { input: "1", typ: i1Typ, want: "i1 true", }, // i=2 { input: "false", typ: i1Typ, want: "i1 false", }, // i=3 { input: "0", typ: i1Typ, want: "i1 false", }, // i=4 { input: "2", typ: i1Typ, want: "", err: `invalid integer constant "2" for boolean type`, }, // i=5 { input: "true", typ: i32Typ, want: "", err: `integer constant "true" type mismatch; expected i1, got i32`, }, // i=6 { input: "false", typ: i32Typ, want: "", err: `integer constant "false" type mismatch; expected i1, got i32`, }, // i=7 { input: "42", typ: i32Typ, want: "i32 42", }, // i=8 { input: "-137438953472", typ: i64Typ, want: "i64 -137438953472", }, // i=9 { input: "3.0", typ: f32Typ, want: "", err: `invalid type "float" for integer constant`, }, // i=10 { input: "foo", typ: i64Typ, want: "", err: `unable to parse integer constant "foo"`, }, } for i, g := range golden { v, err := constant.NewInt(g.typ, g.input) if !sameError(err, g.err) { t.Errorf("i=%d: error mismatch; expected %v, got %v", i, g.err, err) continue } else if err != nil { // Expected error match, check next test case. continue } got := fmt.Sprintf("%s %s", v.Type(), v) if got != g.want { t.Errorf("i=%d: string mismatch; expected %v, got %v", i, g.want, got) } } }