Example #1
0
File: x86.go Project: tsavola/wag
// OpLoadROIntIndex32ScaleDisp must not allocate registers.
func (mach X86) OpLoadROIntIndex32ScaleDisp(code gen.Coder, t types.T, reg regs.R, regZeroExt bool, scale uint8, addr int32) (resultZeroExt bool) {
	if !regZeroExt {
		Mov.opFromReg(code, types.I32, reg, reg)
	}

	Mov.opFromAddr(code, t, reg, scale, reg, code.RODataAddr()+addr)
	resultZeroExt = true
	return
}
Example #2
0
func (mach X86) opConvertUnsignedI64ToFloat(code gen.Coder, resultType types.T, inputReg regs.R) {
	// this algorithm is copied from code generated by gcc and clang:

	var done links.L
	var huge links.L

	// TODO: allocate target reg

	Test.opFromReg(code, types.I64, inputReg, inputReg)
	Js.rel8.opStub(code)
	huge.AddSite(code.Len())

	// max. 63-bit value
	Cvtsi2sSSE.opReg(code, resultType, types.I64, regResult, inputReg)

	JmpRel.rel8.opStub(code)
	done.AddSite(code.Len())

	huge.Addr = code.Len()
	mach.updateBranches8(code, &huge)

	// 64-bit value
	Mov.opFromReg(code, types.I64, regScratch, inputReg)
	And.opImm(code, types.I64, regScratch, 1)
	ShrImm.op(code, types.I64, inputReg, 1)
	Or.opFromReg(code, types.I64, inputReg, regScratch)
	Cvtsi2sSSE.opReg(code, resultType, types.I64, regResult, inputReg)
	AddsSSE.opFromReg(code, resultType, regResult, regResult)

	done.Addr = code.Len()
	mach.updateBranches8(code, &done)
}
Example #3
0
File: x86.go Project: tsavola/wag
// OpStoreStack must not allocate registers.
func (mach X86) OpStoreStack(code gen.Coder, offset int32, x values.Operand) {
	var reg regs.R

	if x.Storage.IsReg() {
		reg = x.Reg()
	} else {
		reg = regScratch
		mach.OpMove(code, reg, x, true)
	}

	mach.OpStoreStackReg(code, x.Type, offset, reg)

	if x.Storage == values.TempReg {
		code.FreeReg(x.Type, reg)
	}
}
Example #4
0
File: x86.go Project: tsavola/wag
// OpPush must not allocate registers, and must not update CPU's condition
// flags unless the operand is the condition flags.
func (mach X86) OpPush(code gen.Coder, x values.Operand) {
	var reg regs.R

	switch {
	case x.Storage.IsReg():
		reg = x.Reg()

	case x.Storage == values.Imm:
		value := x.ImmValue()

		switch {
		case value >= -0x80 && value < 0x80:
			PushImm8.op(code, imm{int8(value)})
			return

		case value >= -0x80000000 && value < 0x80000000:
			PushImm32.op(code, imm{int32(value)})
			return
		}

		fallthrough

	default:
		reg = regScratch
		mach.OpMove(code, reg, x, true)
	}

	switch x.Type.Category() {
	case types.Int:
		Push.op(code, reg)

	case types.Float:
		pushFloatOp(code, x.Type, reg)

	default:
		panic(x)
	}

	if x.Storage == values.TempReg {
		code.FreeReg(x.Type, reg)
	}
}
Example #5
0
File: x86.go Project: tsavola/wag
func (mach X86) OpBranchIf(code gen.Coder, x values.Operand, yes bool, addr int32) (sites []int32) {
	var cond values.Condition

	if x.Storage == values.ConditionFlags {
		cond = x.Condition()
	} else {
		reg, _, own := mach.opBorrowMaybeScratchReg(code, x, false)
		if own {
			defer code.FreeReg(types.I32, reg)
		}

		Test.opFromReg(code, types.I32, reg, reg)
		cond = values.Ne
	}

	if !yes {
		cond = values.InvertedConditions[cond]
	}

	var end links.L

	switch {
	case cond >= values.MinUnorderedOrCondition:
		Jp.op(code, addr)
		sites = append(sites, code.Len())

	case cond >= values.MinOrderedAndCondition:
		Jp.rel8.opStub(code)
		end.AddSite(code.Len())
	}

	conditionInsns[cond].jcc.op(code, addr)
	sites = append(sites, code.Len())

	end.Addr = code.Len()
	mach.updateBranches8(code, &end)
	return
}
Example #6
0
File: x86.go Project: tsavola/wag
func (mach X86) OpTrapIfStackExhausted(code gen.Coder) (stackCheckAddr int32) {
	var checked links.L

	Lea.opFromStack(code, types.I64, regScratch, -0x80000000) // reserve 32-bit displacement
	stackCheckAddr = code.Len()

	Cmp.opFromReg(code, types.I64, regScratch, regStackLimit)

	Jge.rel8.opStub(code)
	checked.AddSite(code.Len())

	code.OpTrapCall(traps.CallStackExhausted)

	checked.Addr = code.Len()
	mach.updateBranches8(code, &checked)
	return
}
Example #7
0
File: x86.go Project: tsavola/wag
func (mach X86) OpCall(code gen.Coder, addr int32) (retAddr int32) {
	if addr == 0 {
		if Native {
			// address slot must be aligned
			if relPos := (code.Len() + CallRel.size()) & 3; relPos > 0 {
				padSize := 4 - relPos
				code.Write(nopSequences[padSize-1])
			}
		}
		CallRel.opMissingFunction(code)
	} else {
		CallRel.op(code, addr)
	}
	return code.Len()
}
Example #8
0
File: x86.go Project: tsavola/wag
// OpBranchIfOutOfBounds must not allocate registers.  indexReg will be
// zero-extended.
func (mach X86) OpBranchIfOutOfBounds(code gen.Coder, indexReg regs.R, upperBound, addr int32) int32 {
	mach.opCompareBounds(code, indexReg, upperBound)
	Jle.op(code, addr) // TODO: is this the correct comparison?
	return code.Len()
}
Example #9
0
File: x86.go Project: tsavola/wag
func (mach X86) OpBranch(code gen.Coder, addr int32) int32 {
	JmpRel.op(code, addr)
	return code.Len()
}
Example #10
0
File: x86.go Project: tsavola/wag
// OpMove must not update CPU's condition flags if preserveFlags is set.
//
// X86 implementation note: must not blindly rely on regScratch or regResult in
// this function because we may be moving to one of them.
func (mach X86) OpMove(code gen.Coder, targetReg regs.R, x values.Operand, preserveFlags bool) (zeroExt bool) {
	switch x.Type.Category() {
	case types.Int:
		switch x.Storage {
		case values.Imm:
			if value := x.ImmValue(); value == 0 && !preserveFlags {
				Xor.opFromReg(code, types.I32, targetReg, targetReg)
			} else {
				MovImm64.op(code, x.Type, targetReg, value)
			}
			zeroExt = true

		case values.VarMem:
			Mov.opFromStack(code, x.Type, targetReg, x.VarMemOffset())
			zeroExt = true

		case values.VarReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				Mov.opFromReg(code, x.Type, targetReg, sourceReg)
				zeroExt = true
			}

		case values.TempReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				Mov.opFromReg(code, x.Type, targetReg, sourceReg)
				zeroExt = true
			} else if targetReg == regResult {
				zeroExt = x.RegZeroExt()
			} else {
				panic("moving temporary integer register to itself")
			}

		case values.Stack:
			Pop.op(code, targetReg)

		case values.ConditionFlags:
			if x.Type != types.I32 {
				panic(x)
			}

			var end links.L

			cond := x.Condition()
			setcc := conditionInsns[cond].setcc

			switch {
			case cond >= values.MinUnorderedOrCondition:
				MovImm.opImm(code, x.Type, targetReg, 1) // true
				Jp.rel8.opStub(code)                     // if unordered, else
				end.AddSite(code.Len())                  //
				setcc.opReg(code, targetReg)             // cond

			case cond >= values.MinOrderedAndCondition:
				MovImm.opImm(code, x.Type, targetReg, 0) // false
				Jp.rel8.opStub(code)                     // if unordered, else
				end.AddSite(code.Len())                  //
				setcc.opReg(code, targetReg)             // cond

			default:
				setcc.opReg(code, targetReg)
				Movzx8.opFromReg(code, x.Type, targetReg, targetReg)
			}

			end.Addr = code.Len()
			mach.updateBranches8(code, &end)

			zeroExt = true

		default:
			panic(x)
		}

	case types.Float:
		switch x.Storage {
		case values.Imm:
			if value := x.ImmValue(); value == 0 {
				PxorSSE.opFromReg(code, x.Type, targetReg, targetReg)
			} else {
				MovImm64.op(code, x.Type, regScratch, value) // integer scratch register
				MovSSE.opFromReg(code, x.Type, targetReg, regScratch)
			}

		case values.VarMem:
			MovsSSE.opFromStack(code, x.Type, targetReg, x.VarMemOffset())

		case values.VarReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				MovsSSE.opFromReg(code, x.Type, targetReg, sourceReg)
			}

		case values.TempReg:
			if sourceReg := x.Reg(); sourceReg != targetReg {
				MovsSSE.opFromReg(code, x.Type, targetReg, sourceReg)
			} else if targetReg != regResult {
				panic("moving temporary float register to itself")
			}

		case values.Stack:
			popFloatOp(code, x.Type, targetReg)

		default:
			panic(x)
		}

	default:
		panic(x)
	}

	code.Consumed(x)

	return
}
Example #11
0
File: x86.go Project: tsavola/wag
// OpCallIndirect using table index located in result register.
func (mach X86) OpCallIndirect(code gen.Coder, tableLen, sigIndex int32) int32 {
	var outOfBounds links.L
	var checksOut links.L

	mach.opCompareBounds(code, regResult, tableLen)
	Jle.rel8.opStub(code) // TODO: is this the correct comparison?
	outOfBounds.AddSite(code.Len())

	Mov.opFromAddr(code, types.I64, regResult, 3, regResult, code.RODataAddr()+gen.ROTableAddr)
	Mov.opFromReg(code, types.I32, regScratch, regResult) // zero-extended function address
	ShrImm.op(code, types.I64, regResult, 32)             // signature index
	Cmp.opImm(code, types.I32, regResult, sigIndex)
	Je.rel8.opStub(code)
	checksOut.AddSite(code.Len())

	code.OpTrapCall(traps.IndirectCallSignature)

	outOfBounds.Addr = code.Len()
	mach.updateBranches8(code, &outOfBounds)

	code.OpTrapCall(traps.IndirectCallIndex)

	checksOut.Addr = code.Len()
	mach.updateBranches8(code, &checksOut)

	Add.opFromReg(code, types.I64, regScratch, regTextBase)
	Call.opReg(code, regScratch)
	return code.Len()
}