Beispiel #1
0
// 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
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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))
}
Beispiel #4
0
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")
	}
}
Beispiel #5
0
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")
	}
}
Beispiel #6
0
// 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)
	}
}
Beispiel #7
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")
	}
}
Beispiel #8
0
// 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)
	}
}
Beispiel #9
0
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)
	}
}
Beispiel #10
0
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
}
Beispiel #11
0
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))
}