github.com/goplus/gossa@v0.3.25/binop_gen.go (about) 1 //go:build ignore 2 // +build ignore 3 4 package main 5 6 import ( 7 "bytes" 8 "fmt" 9 "go/format" 10 "io/ioutil" 11 "os" 12 "strings" 13 ) 14 15 var ( 16 ints = []string{"int", "int8", "int16", "int32", "int64", 17 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr"} 18 floats = []string{"float32", "float64"} 19 comps = []string{"complex64", "complex128"} 20 str = []string{"string"} 21 ) 22 23 func json(kinds ...[]string) (r []string) { 24 for _, kind := range kinds { 25 r = append(r, kind...) 26 } 27 return 28 } 29 30 func main() { 31 var buf bytes.Buffer 32 buf.WriteString(pkg_head) 33 34 makeFuncOp(&buf, "makeBinOpADD", "+", json(ints, floats, comps, str)) 35 makeFuncOp(&buf, "makeBinOpSUB", "-", json(ints, floats, comps)) 36 makeFuncOp(&buf, "makeBinOpMUL", "*", json(ints, floats, comps)) 37 makeFuncOp(&buf, "makeBinOpQUO", "/", json(ints, floats, comps)) 38 39 makeFuncOp(&buf, "makeBinOpREM", "%", json(ints)) 40 makeFuncOp(&buf, "makeBinOpAND", "&", json(ints)) 41 makeFuncOp(&buf, "makeBinOpOR", "|", json(ints)) 42 makeFuncOp(&buf, "makeBinOpXOR", "^", json(ints)) 43 makeFuncOp(&buf, "makeBinOpANDNOT", "&^", json(ints)) 44 45 makeFuncCmp(&buf, "makeBinOpLSS", "<", json(ints, floats, str)) 46 makeFuncCmp(&buf, "makeBinOpLEQ", "<=", json(ints, floats, str)) 47 makeFuncCmp(&buf, "makeBinOpGTR", ">", json(ints, floats, str)) 48 makeFuncCmp(&buf, "makeBinOpGEQ", ">=", json(ints, floats, str)) 49 50 data, err := format.Source(buf.Bytes()) 51 if err != nil { 52 fmt.Println("format error", err) 53 os.Exit(2) 54 } 55 ioutil.WriteFile("./binop.go", data, 0666) 56 } 57 58 func makeFuncOp(buf *bytes.Buffer, fnname string, op string, kinds []string) { 59 buf.WriteString(strings.Replace(func_head_op, "$NAME", fnname, 1)) 60 buf.WriteString(`if typ.PkgPath() == "" { 61 switch typ.Kind() { 62 `) 63 var div_case1 string 64 var div_case2 string 65 if op == "/" { 66 div_case1 = get_func_case1_div() 67 div_case2 = get_func_case2_div() 68 } 69 for _, kind := range kinds { 70 r := strings.NewReplacer( 71 "Int", strings.Title(kind), 72 "int", kind, 73 "+", op) 74 if op == "/" && strings.Contains(kind, "int") { 75 r.WriteString(buf, div_case1) 76 } else { 77 r.WriteString(buf, func_case1) 78 } 79 } 80 buf.WriteString(`} 81 } else { 82 t := xtype.TypeOfType(typ) 83 switch typ.Kind() { 84 `) 85 for _, kind := range kinds { 86 r := strings.NewReplacer( 87 "Int", strings.Title(kind), 88 "int", kind, 89 "+", op) 90 if op == "/" && strings.Contains(kind, "int") { 91 r.WriteString(buf, div_case2) 92 } else { 93 r.WriteString(buf, func_case2) 94 } 95 } 96 buf.WriteString(`} 97 } 98 panic("unreachable") 99 }`) 100 } 101 102 func makeFuncCmp(buf *bytes.Buffer, fnname string, op string, kinds []string) { 103 buf.WriteString(strings.Replace(func_head_cmp, "$NAME", fnname, 1)) 104 buf.WriteString(`if typ.PkgPath() == "" { 105 switch typ.Kind() { 106 `) 107 for _, kind := range kinds { 108 r := strings.NewReplacer( 109 "Int", strings.Title(kind), 110 "int", kind, 111 "+", op) 112 r.WriteString(buf, func_case1) 113 } 114 buf.WriteString(`} 115 } else { 116 switch typ.Kind() { 117 `) 118 for _, kind := range kinds { 119 r := strings.NewReplacer( 120 "Int", strings.Title(kind), 121 "int", kind, 122 "<", op) 123 r.WriteString(buf, func_case2_cmp) 124 } 125 buf.WriteString(`} 126 } 127 panic("unreachable") 128 }`) 129 } 130 131 var pkg_head = `package gossa 132 133 import ( 134 "reflect" 135 136 "github.com/goplus/gossa/internal/xtype" 137 "golang.org/x/tools/go/ssa" 138 ) 139 ` 140 141 var func_head_op = ` 142 func $NAME(pfn *function, instr *ssa.BinOp) func(fr *frame) { 143 ir := pfn.regIndex(instr) 144 ix, kx, vx := pfn.regIndex3(instr.X) 145 iy, ky, vy := pfn.regIndex3(instr.Y) 146 typ := pfn.Interp.preToType(instr.Type()) 147 ` 148 149 var func_head_cmp = ` 150 func $NAME(pfn *function, instr *ssa.BinOp) func(fr *frame) { 151 ir := pfn.regIndex(instr) 152 ix, kx, vx := pfn.regIndex3(instr.X) 153 iy, ky, vy := pfn.regIndex3(instr.Y) 154 typ := pfn.Interp.preToType(instr.X.Type()) 155 ` 156 157 func get_func_case1_div() string { 158 return strings.Replace(func_case1, 159 "v := vx.(int)+vy.(int)", 160 `x := vx.(int) 161 y := vy.(int) 162 if y == 0 { 163 return func(fr *frame) { fr.setReg(ir, x/y) } 164 } 165 v := x/y`, 1) 166 } 167 168 var func_case1 = `case reflect.Int: 169 if kx == kindConst && ky == kindConst { 170 v := vx.(int)+vy.(int) 171 return func(fr *frame) { fr.setReg(ir, v) } 172 } else if kx == kindConst { 173 x := vx.(int) 174 return func(fr *frame) { fr.setReg(ir, x+fr.reg(iy).(int)) } 175 } else if ky == kindConst { 176 y := vy.(int) 177 return func(fr *frame) { fr.setReg(ir, fr.reg(ix).(int)+y) } 178 } else { 179 return func(fr *frame) { fr.setReg(ir, fr.reg(ix).(int)+fr.reg(iy).(int)) } 180 } 181 ` 182 183 func get_func_case2_div() string { 184 return strings.Replace(func_case2, 185 "v := xtype.Make(t,xtype.Int(vx)+xtype.Int(vy))", 186 `x := xtype.Int(vx) 187 y := xtype.Int(vy) 188 if y == 0 { 189 return func(fr *frame) { fr.setReg(ir, xtype.Make(t,x/y)) } 190 } 191 v := xtype.Make(t,x/y)`, 1) 192 } 193 194 var func_case2 = `case reflect.Int: 195 if kx == kindConst && ky == kindConst { 196 v := xtype.Make(t,xtype.Int(vx)+xtype.Int(vy)) 197 return func(fr *frame) { fr.setReg(ir, v) } 198 } else if kx == kindConst { 199 x := xtype.Int(vx) 200 return func(fr *frame) { fr.setReg(ir, xtype.Make(t,x+fr.int(iy))) } 201 } else if ky == kindConst { 202 y := xtype.Int(vy) 203 return func(fr *frame) { fr.setReg(ir, xtype.Make(t,fr.int(ix)+y)) } 204 } else { 205 return func(fr *frame) { fr.setReg(ir, xtype.Make(t,fr.int(ix)+fr.int(iy))) } 206 } 207 ` 208 209 var func_case2_cmp = `case reflect.Int: 210 if kx == kindConst && ky == kindConst { 211 v := xtype.Int(vx)<xtype.Int(vy) 212 return func(fr *frame) { fr.setReg(ir, v) } 213 } else if kx == kindConst { 214 x := xtype.Int(vx) 215 return func(fr *frame) { fr.setReg(ir, x<fr.int(iy)) } 216 } else if ky == kindConst { 217 y := xtype.Int(vy) 218 return func(fr *frame) { fr.setReg(ir, fr.int(ix)<y) } 219 } else { 220 return func(fr *frame) { fr.setReg(ir, fr.int(ix)<fr.int(iy)) } 221 } 222 `