func (f *Function) UnOp(instr *ssa.UnOp) (string, *Error) { var err *Error asm := "" switch instr.Op { default: ice(fmt.Sprintf("unknown Op token (%v): \"%v\"", instr.Op, instr)) case token.NOT: // logical negation asm, err = f.UnOpXor(instr, 1) case token.XOR: //bitwise negation asm, err = f.UnOpXor(instr, -1) case token.SUB: // arithmetic negation e.g. x=>-x asm, err = f.UnOpSub(instr) case token.MUL: //pointer indirection asm, err = f.UnOpPointer(instr) } asm = fmt.Sprintf("// BEGIN ssa.UnOp: %v = %v\n", instr.Name(), instr) + asm asm += fmt.Sprintf("// END ssa.UnOp: %v = %v\n", instr.Name(), instr) return asm, err }
// arithmetic negation func (f *Function) UnOpSub(instr *ssa.UnOp) (string, *Error) { ctx := context{f, instr} if ident := f.Ident(instr); ident == nil { return ErrorMsg(fmt.Sprintf("Cannot alloc value: %v", instr)) } var regSubX, regX, regVal *register var a1, a2 string a1, regVal = f.allocReg(instr, regType(instr.Type()), f.sizeof(instr)) a2, regSubX = f.allocReg(instr, regType(instr.X.Type()), f.sizeof(instr.X)) addr, ok := f.identifiers[instr.Name()] if !ok { msg := fmt.Sprintf("unknown name (%v), instr (%v)\n", instr.Name(), instr) ice(msg) } a3, regX, err := f.LoadValueSimple(instr, instr.X) asm := a1 + a2 + a3 if err != nil { return asm, err } asm += ZeroReg(ctx, regSubX) optypes := GetOpDataType(instr.Type()) asm += ArithOp(ctx, optypes, token.SUB, regSubX, regX, regVal) f.freeReg(regX) f.freeReg(regSubX) a, err := f.StoreValue(instr, addr, regVal) if err != nil { return asm, err } else { asm += a } f.freeReg(regVal) asm = fmt.Sprintf("// BEGIN ssa.UnOpSub, %v = %v\n", instr.Name(), instr) + asm asm += fmt.Sprintf("// END ssa.UnOpSub, %v = %v\n", instr.Name(), instr) return asm, nil }
// bitwise negation func (f *Function) UnOpXor(instr *ssa.UnOp, xorVal int32) (string, *Error) { ctx := context{f, instr} if ident := f.Ident(instr); ident == nil { return ErrorMsg(fmt.Sprintf("Cannot alloc value: %v", instr)) } addr, ok := f.identifiers[instr.Name()] if !ok { msg := fmt.Sprintf("unknown name (%v), instr (%v)\n", instr.Name(), instr) ice(msg) } asm, reg, err := f.LoadValueSimple(instr, instr.X) if err != nil { return asm, err } if reg.size() < 8 { asm += XorImm32Reg(ctx, xorVal, reg, reg.size(), true) } else { asm += XorImm64Reg(ctx, int64(xorVal), reg, reg.size(), true) } a, err := f.StoreValue(instr, addr, reg) f.freeReg(reg) if err != nil { return asm, err } else { asm += a } asm = fmt.Sprintf("// BEGIN ssa.UnOpNot, %v = %v\n", instr.Name(), instr) + asm asm += fmt.Sprintf("// END ssa.UnOpNot, %v = %v\n", instr.Name(), instr) return asm, nil }
//pointer indirection, in assignment such as "z = *x" func (f *Function) UnOpPointer(instr *ssa.UnOp) (string, *Error) { asm := "" assignment := f.Ident(instr) if assignment == nil { return ErrorMsg(fmt.Sprintf("Cannot alloc value: %v", instr)) } xName := instr.X.Name() xInfo, okX := f.identifiers[xName] if !xInfo.isSsaLocal() && xInfo.param == nil && xInfo.ptr == nil { panic("unexpected nil ptr") } else if !xInfo.isSsaLocal() && xInfo.param == nil { asm += xInfo.ptr.spillAllRegisters(instr) } // TODO add complex64/128 support if isComplex(instr.Type()) || isComplex(instr.X.Type()) { return ErrorMsg("complex64/complex128 unimplemented") } if !okX { msgstr := "Unknown name for UnOp X (%v), instr \"(%v)\"" ice(fmt.Sprintf(msgstr, instr.X, instr)) } if xInfo.local == nil && xInfo.param == nil && !xInfo.isPointer() { fmtstr := "in UnOp, X (%v) isn't a pointer, X.type (%v), instr \"(%v)\"" msg := fmt.Sprintf(fmtstr, instr.X, instr.X.Type(), instr) ice(msg) } _, _, size := assignment.Addr() if xInfo.isSsaLocal() { ctx := context{f, instr} a, reg := xInfo.load(ctx) asm += a asm += assignment.newValue(ctx, reg, 0, xInfo.size()) f.freeReg(reg) } else { var tmpData *register var a1 string if isXmm(instr.Type()) { a1, tmpData = f.allocReg(instr, XMM_REG, XmmRegSize) } else { a1, tmpData = f.allocReg(instr, regType(instr.Type()), DataRegSize) } asm += a1 var a2 string var tmpAddr *register a2, tmpAddr = f.allocReg(instr, DATA_REG, DataRegSize) asm += a2 src, ok := xInfo.storage.(*memory) if !ok { ice("cannot dereference pointer to constant") } dst, ok := assignment.storage.(*memory) if !ok { ice("cannot modify constant") } dst.removeAliases() ctx := context{f, instr} a, srcReg := src.load(ctx, src.ownerRegion()) asm += a aReg, aOffset, _ := assignment.Addr() asm += MovRegIndirectMem(ctx, dst.optype(), srcReg, assignment.name, aOffset, &aReg, size, tmpAddr, tmpData) dst.setInitialized(region{0, size}) f.freeReg(srcReg) f.freeReg(tmpAddr) f.freeReg(tmpData) } asm = fmt.Sprintf("// BEGIN ssa.UnOpPointer, %v = %v\n", instr.Name(), instr) + asm asm += fmt.Sprintf("// END ssa.UnOpPointer, %v = %v\n", instr.Name(), instr) return asm, nil }