func (f *Function) BinOpLoadXY(instr *ssa.BinOp) (asm string, x *register, y *register, err *Error) { if isPointer(instr.Type()) { panic("ptr") } if ident := f.Ident(instr); ident == nil { return "", nil, nil, ErrorMsg2(fmt.Sprintf("Cannot alloc value: %v", instr)) } if ident := f.Ident(instr.X); ident == nil { return "", nil, nil, ErrorMsg2(fmt.Sprintf("Cannot alloc value: %v", instr.X)) } if ident := f.Ident(instr.Y); ident == nil { return "", nil, nil, ErrorMsg2(fmt.Sprintf("Cannot alloc value: %v", instr.Y)) } var a string asm = "// BEGIN BinOpLoadXY\n" if isPointer(instr.X.Type()) { panic("ptr") } a, x, err = f.LoadValue(instr, instr.X, 0, f.sizeof(instr.X)) x.inUse = true if err != nil { return "", nil, nil, err } else { asm += a } if isPointer(f.Ident(instr.Y).typ) { panic("ptr") } a, y, err = f.LoadValue(instr, instr.Y, 0, f.sizeof(instr.Y)) y.inUse = true if err != nil { return "", nil, nil, err } else { asm += a } asm += "// END BinOpLoadXY\n" return asm, x, y, nil }
func visitBinOp(inst *ssa.BinOp, fr *frame) { switch inst.Op { case token.EQL: if selTuple, isSelTuple := fr.env.selIdx[inst.X]; isSelTuple { branchID := int(inst.Y.(*ssa.Const).Int64()) fr.env.selTest[inst] = struct { idx int tpl ssa.Value }{ branchID, selTuple, } } else { fmt.Fprintf(os.Stderr, " # %s = "+red("%s")+"\n", inst.Name(), inst.String()) } default: fmt.Fprintf(os.Stderr, " # %s = "+red("%s")+"\n", inst.Name(), inst.String()) } }
func (f *Function) BinOp(instr *ssa.BinOp) (string, *Error) { ctx := context{f, instr} ident := f.Ident(instr) if ident == nil { return ErrorMsg(fmt.Sprintf("Cannot alloc value: %v", instr)) } var regX, regY, regVal *register size := f.sizeof(instr) xIsSigned := signed(instr.X.Type()) var a string // comparison op results are size 1 byte, but that's not supported if size == 1 { a, regVal = f.allocIdentReg(instr, ident, 8*size) } else { a, regVal = f.allocIdentReg(instr, ident, size) } asm := a asmload, regX, regY, err := f.BinOpLoadXY(instr) asm += asmload if err != nil { return asm, err } size = f.sizeof(instr.X) switch instr.Op { default: ice(fmt.Sprintf("unknown op (%v)", instr.Op)) case token.ADD, token.SUB, token.MUL, token.QUO, token.REM: optypes := GetOpDataType(instr.Type()) asm += ArithOp(ctx, optypes, instr.Op, regX, regY, regVal) case token.AND, token.OR, token.XOR, token.SHL, token.SHR, token.AND_NOT: asm += BitwiseOp(ctx, instr.Op, xIsSigned, regX, regY, regVal, size) case token.EQL, token.NEQ, token.LEQ, token.GEQ, token.LSS, token.GTR: if size != f.sizeof(instr.Y) { ice("comparing two different size values") } optypes := GetOpDataType(instr.X.Type()) asm += CmpOp(ctx, optypes, instr.Op, regX, regY, regVal) } f.freeReg(regX) f.freeReg(regY) addr, ok := f.identifiers[instr.Name()] if !ok { ice(fmt.Sprintf("unknown name (%v), instr (%v)\n", instr.Name(), instr)) } a1, err := f.StoreValue(instr, addr, regVal) if err != nil { return asm, err } else { asm += a1 } f.freeReg(regVal) asm = fmt.Sprintf("// BEGIN ssa.BinOp, %v = %v\n", instr.Name(), instr) + asm asm += fmt.Sprintf("// END ssa.BinOp, %v = %v\n", instr.Name(), instr) return asm, nil }