Merge pull request #9496 from cooldome/vm_float_casts
VM: add int <-> float casts of the same size
This commit is contained in:
commit
2fa13040b9
5 changed files with 94 additions and 5 deletions
|
|
@ -44,6 +44,8 @@
|
||||||
|
|
||||||
### Language additions
|
### Language additions
|
||||||
|
|
||||||
|
- Vm suport for float32<->int32 and float64<->int64 casts was added.
|
||||||
|
|
||||||
|
|
||||||
### Language changes
|
### Language changes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -488,6 +488,22 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcAsgnFloat:
|
of opcAsgnFloat:
|
||||||
decodeB(rkFloat)
|
decodeB(rkFloat)
|
||||||
regs[ra].floatVal = regs[rb].floatVal
|
regs[ra].floatVal = regs[rb].floatVal
|
||||||
|
of opcAsgnIntFromFloat32:
|
||||||
|
let rb = instr.regB
|
||||||
|
ensureKind(rkInt)
|
||||||
|
regs[ra].intVal = cast[int32](float32(regs[rb].floatVal))
|
||||||
|
of opcAsgnIntFromFloat64:
|
||||||
|
let rb = instr.regB
|
||||||
|
ensureKind(rkInt)
|
||||||
|
regs[ra].intVal = cast[int64](regs[rb].floatVal)
|
||||||
|
of opcAsgnFloat32FromInt:
|
||||||
|
let rb = instr.regB
|
||||||
|
ensureKind(rkFloat)
|
||||||
|
regs[ra].floatVal = cast[float32](int32(regs[rb].intVal))
|
||||||
|
of opcAsgnFloat64FromInt:
|
||||||
|
let rb = instr.regB
|
||||||
|
ensureKind(rkFloat)
|
||||||
|
regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))
|
||||||
of opcAsgnComplex:
|
of opcAsgnComplex:
|
||||||
asgnComplex(regs[ra], regs[instr.regB])
|
asgnComplex(regs[ra], regs[instr.regB])
|
||||||
of opcAsgnRef:
|
of opcAsgnRef:
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@ type
|
||||||
opcAsgnStr,
|
opcAsgnStr,
|
||||||
opcAsgnFloat,
|
opcAsgnFloat,
|
||||||
opcAsgnRef,
|
opcAsgnRef,
|
||||||
|
opcAsgnIntFromFloat32, # int and float must be of the same byte size
|
||||||
|
opcAsgnIntFromFloat64, # int and float must be of the same byte size
|
||||||
|
opcAsgnFloat32FromInt, # int and float must be of the same byte size
|
||||||
|
opcAsgnFloat64FromInt, # int and float must be of the same byte size
|
||||||
opcAsgnComplex,
|
opcAsgnComplex,
|
||||||
opcNodeToReg,
|
opcNodeToReg,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -769,18 +769,18 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.gABC(n, opcCard, dest, tmp)
|
c.gABC(n, opcCard, dest, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
|
proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
|
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
|
||||||
var signedIntegers = {tyInt8..tyInt32}
|
var signedIntegers = {tyInt8..tyInt32}
|
||||||
var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
|
var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
|
||||||
let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
|
let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
|
||||||
let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
|
let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
|
||||||
let src_size = getSize(c.config, src)
|
let src_size = getSize(c.config, src)
|
||||||
|
let dst_size = getSize(c.config, dst)
|
||||||
if c.config.target.intSize < 8:
|
if c.config.target.intSize < 8:
|
||||||
signedIntegers.incl(tyInt)
|
signedIntegers.incl(tyInt)
|
||||||
unsignedIntegers.incl(tyUInt)
|
unsignedIntegers.incl(tyUInt)
|
||||||
if src_size == getSize(c.config, dst) and src.kind in allowedIntegers and
|
if src_size == dst_size and src.kind in allowedIntegers and
|
||||||
dst.kind in allowedIntegers:
|
dst.kind in allowedIntegers:
|
||||||
let tmp = c.genx(n.sons[1])
|
let tmp = c.genx(n.sons[1])
|
||||||
var tmp2 = c.getTemp(n.sons[1].typ)
|
var tmp2 = c.getTemp(n.sons[1].typ)
|
||||||
|
|
@ -809,8 +809,28 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
c.freeTemp(tmp3)
|
c.freeTemp(tmp3)
|
||||||
|
elif src_size == dst_size and src.kind in allowedIntegers and
|
||||||
|
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
||||||
|
let tmp = c.genx(n[1])
|
||||||
|
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||||
|
if dst.kind == tyFloat32:
|
||||||
|
c.gABC(n, opcAsgnFloat32FromInt, dest, tmp)
|
||||||
|
else:
|
||||||
|
c.gABC(n, opcAsgnFloat64FromInt, dest, tmp)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
|
elif src_size == dst_size and src.kind in {tyFloat, tyFloat32, tyFloat64} and
|
||||||
|
dst.kind in allowedIntegers:
|
||||||
|
let tmp = c.genx(n[1])
|
||||||
|
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||||
|
if src.kind == tyFloat32:
|
||||||
|
c.gABC(n, opcAsgnIntFromFloat32, dest, tmp)
|
||||||
|
else:
|
||||||
|
c.gABC(n, opcAsgnIntFromFloat64, dest, tmp)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size")
|
globalError(c.config, n.info, "VM is only allowed to 'cast' between integers and/or floats of same size")
|
||||||
|
|
||||||
proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
|
proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
|
||||||
unused(c, n, dest)
|
unused(c, n, dest)
|
||||||
|
|
@ -2008,7 +2028,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||||
if allowCast in c.features:
|
if allowCast in c.features:
|
||||||
genConv(c, n, n.sons[1], dest, opcCast)
|
genConv(c, n, n.sons[1], dest, opcCast)
|
||||||
else:
|
else:
|
||||||
genIntCast(c, n, dest)
|
genCastIntFloat(c, n, dest)
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr:
|
||||||
genTypeLit(c, n.typ, dest)
|
genTypeLit(c, n.typ, dest)
|
||||||
of nkComesFrom:
|
of nkComesFrom:
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,55 @@ proc test() =
|
||||||
doAssert(not compiles(cast[uint32](I8)))
|
doAssert(not compiles(cast[uint32](I8)))
|
||||||
doAssert(not compiles(cast[uint64](I8)))
|
doAssert(not compiles(cast[uint64](I8)))
|
||||||
|
|
||||||
|
|
||||||
|
proc test_float_cast =
|
||||||
|
|
||||||
|
const
|
||||||
|
exp_bias = 1023'i64
|
||||||
|
exp_shift = 52
|
||||||
|
exp_mask = 0x7ff'i64 shl exp_shift
|
||||||
|
mantissa_mask = 0xfffffffffffff'i64
|
||||||
|
|
||||||
|
let f = 8.0
|
||||||
|
let fx = cast[int64](f)
|
||||||
|
let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
|
||||||
|
let mantissa = fx and mantissa_mask
|
||||||
|
doAssert(exponent == 3, $exponent)
|
||||||
|
doAssert(mantissa == 0, $mantissa)
|
||||||
|
|
||||||
|
# construct 2^N float, where N is integer
|
||||||
|
let x = -2'i64
|
||||||
|
let xx = (x + exp_bias) shl exp_shift
|
||||||
|
let xf = cast[float](xx)
|
||||||
|
doAssert(xf == 0.25, $xf)
|
||||||
|
|
||||||
|
proc test_float32_cast =
|
||||||
|
|
||||||
|
const
|
||||||
|
exp_bias = 127'i32
|
||||||
|
exp_shift = 23
|
||||||
|
exp_mask = 0x7f800000'i32
|
||||||
|
mantissa_mask = 0x007ffff'i32
|
||||||
|
|
||||||
|
let f = -0.5'f32
|
||||||
|
let fx = cast[int32](f)
|
||||||
|
let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
|
||||||
|
let mantissa = fx and mantissa_mask
|
||||||
|
doAssert(exponent == -1, $exponent)
|
||||||
|
doAssert(mantissa == 0, $mantissa)
|
||||||
|
|
||||||
|
# construct 2^N float32 where N is integer
|
||||||
|
let x = 4'i32
|
||||||
|
let xx = (x + exp_bias) shl exp_shift
|
||||||
|
let xf = cast[float32](xx)
|
||||||
|
doAssert(xf == 16.0'f32, $xf)
|
||||||
|
|
||||||
test()
|
test()
|
||||||
|
test_float_cast()
|
||||||
|
test_float32_cast()
|
||||||
static:
|
static:
|
||||||
test()
|
test()
|
||||||
|
test_float_cast()
|
||||||
|
test_float32_cast()
|
||||||
|
|
||||||
echo "OK"
|
echo "OK"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue