// TODO this really should return a negative value func (v allocator) valOffset(val ssa.Value) int { off := v.valOffsets[val] if off == 0 { panic("no: " + val.Name()) } return off }
func (v Target) moveFloatToSSEReg(a *allocator, val ssa.Value, reg string) { float := val.Type().(*types.Float) com := moveInstrForFloatType(float.Type()) if lit, ok := val.(*ssa.FloatLiteral); ok { v.wop("pushq $0x%x", lit.LiteralValue()) v.wop("%s (#rsp), %s", com, reg) v.wop("addq $8, #rsp") } else { v.wop("%s %s, #%s", com, a.valStr(val), reg) } }
func (v Target) moveRegToVal(a *allocator, reg string, val ssa.Value) { storesz := TypeStoreSizeInBits(val.Type()) reg = regToSize(reg, storesz) if storesz > 64 { panic("unim") } if !isPow2(storesz) { panic("unim") } v.wop("mov%s #%s, %s", sizeSuffixBits(storesz), reg, a.valStr(val)) }
func (v Target) winSaveFunctionParameter(a *allocator, par ssa.Value, i int) { reg := i < 4 storesz := TypeStoreSizeInBits(par.Type()) if winIsMemory(par.Type()) { if reg { v.moveMemToMem(winIntRegs[i], "rbp", 0, -a.valOffset(par), storesz/8) } else { v.wop("movq $%d(#rbp), #r11", 16+i*8) v.moveMemToMem("r11", "rbp", 0, -a.valOffset(par), storesz/8) } } else if winIsInteger(par.Type()) { if reg { v.wop("mov%s #%s, %d(#rbp)", sizeSuffixBits(storesz), regToSize(winIntRegs[i], storesz), -a.valOffset(par)) } else { v.wop("movq $%d(#rbp), #r11", 16+i*8) v.wop("mov%s #%s, %d(#rbp)", sizeSuffixBits(storesz), regToSize("r11", storesz), -a.valOffset(par)) } } else if winIsFloat(par.Type()) { if reg { v.moveSSERegToFloat(a, winSseRegs[i], par) } else { //v.moveValToMem(a, arg, "rsp", 0) panic("unim") } } else { panic("unim") } }
func (v Target) sysVCopyReturnValue(a *allocator, val ssa.Value, saving bool) { if val == nil { return } if _, ok := val.Type().(types.Void); ok { return } classList := sysVClassifyType(val.Type()) switch val.Type().(type) { case *types.Struct, *types.Array: panic("unim") } if len(classList) != 1 { panic("internal error: non-aggregate type has ABI classList of length > 1") } class := classList[0] switch class { case sysVClassINTEGER: storesz := TypeStoreSizeInBits(val.Type()) if saving { v.wop("mov%s #%s, %s", sizeSuffixBits(storesz), regToSize("rax", storesz), a.valStr(val)) } else { v.moveIntToReg(a, val, "rax") } default: panic("unim") } }
// non-float types of sz <= 64, where sz is pow 2 are returned in rax // float types are returned in xmm0 // everything else is returned via memory, location is returned in rax // assumes memory return location is saved in %r15 func (v Target) winCopyReturnValue(a *allocator, val ssa.Value, saving bool) { if _, ok := val.Type().(types.Void); ok { return } storesz := TypeStoreSizeInBits(val.Type()) if _, ok := val.Type().(*types.Float); ok { if saving { v.moveSSERegToFloat(a, "xmm0", val) } else { v.moveFloatToSSEReg(a, val, "xmm0") } return } if storesz <= 64 && isPow2(storesz) { if saving { v.wop("mov%s #%s, %s", sizeSuffixBits(storesz), regToSize("rax", storesz), a.valStr(val)) } else { v.moveIntToReg(a, val, "rax") } return } if saving { v.moveMemToMem("rax", "rbp", 0, -a.valOffset(val), storesz/8) } else { v.wop("movq #r15, #rax") v.moveValToMem(a, val, "rax", 0) } }
func (v Target) moveValToMem(a *allocator, src ssa.Value, memReg string, memOffset int) { /*if !src.Type().Equals(dest.Type()) { panic("internal error") }*/ checkTypeSupported(src.Type()) storesz := TypeStoreSizeInBits(src.Type()) switch src.Type().(type) { case *types.Int, *types.Pointer: if lit, ok := src.(*ssa.IntLiteral); ok { v.wop("mov%s $%d, %d(#%s)", sizeSuffixBits(storesz), lit.LiteralValue(), memOffset, memReg) } else { v.wop("mov%s %s, #%s", sizeSuffixBits(storesz), a.valStr(src), regToSize("rax", storesz)) v.wop("mov%s #%s, %d(#%s)", sizeSuffixBits(storesz), regToSize("rax", storesz), memOffset, memReg) } default: panic("unim") } }
// TODO rename func (v Target) moveIntToReg(a *allocator, val ssa.Value, reg string) { storesz := TypeStoreSizeInBits(val.Type()) reg = regToSize(reg, storesz) reg64 := regToSize(reg, 64) if storesz > 64 { panic("unim") } if !isPow2(storesz) { panic("unim") } if storesz != 64 { v.wop("xorq #%s, #%s", reg64, reg64) } if lit, ok := val.(*ssa.IntLiteral); ok { v.wop("mov%s $%d, #%s", sizeSuffixBits(storesz), lit.LiteralValue(), reg) } else { v.wop("mov%s %s, #%s", sizeSuffixBits(storesz), a.valStr(val), reg) } }
func (v Target) winLoadCallArgument(a *allocator, arg ssa.Value, i int) { reg := i < 4 if !reg { v.wop("subq $8, #rsp") } if winIsMemory(arg.Type()) { storesz := TypeStoreSizeInBits(arg.Type()) v.moveValToMem(a, arg, "r11", 0) if reg { v.wop("movq #r11, #%s", winIntRegs[i]) } else { v.wop("movq #r11, #rsp") } addbits := storesz for addbits%(16*8) != 0 { // TODO do this better addbits++ } v.wop("addq $%d, #r11", addbits/8) } else if winIsInteger(arg.Type()) { if reg { v.moveIntToReg(a, arg, winIntRegs[i]) } else { v.moveValToMem(a, arg, "rsp", 0) } } else if winIsFloat(arg.Type()) { if reg { v.moveIntToReg(a, arg, winIntRegs[i]) v.moveFloatToSSEReg(a, arg, winSseRegs[i]) } else { v.moveValToMem(a, arg, "rsp", 0) } } else { panic(arg) } }
func (v *allocator) allocateValue(val ssa.Value) { if _, ok := val.Type().(types.Void); ok { return } if _, ok := v.valOffsets[val]; ok { panic("duplicate val") } sz := TypeStoreSizeInBits(val.Type()) / 8 align := TypeAlignmentInBits(val.Type()) / 8 v.stackSize += sz for v.stackSize%align != 0 { v.stackSize++ } v.valOffsets[val] = v.stackSize }
func (v Target) moveSSERegToFloat(a *allocator, reg string, val ssa.Value) { float := val.Type().(*types.Float) com := moveInstrForFloatType(float.Type()) v.wop("%s #%s, %s", com, reg, a.valStr(val)) }