From 3964574a8325ab802f98856195b8214dcce3124c Mon Sep 17 00:00:00 2001 From: Bor Grošelj Simić Date: Fri, 28 Jan 2022 02:06:18 +0100 Subject: implement float -> unsigned casts amd64 lacks instruction for this so it has to be implemented with float -> signed casts. The approach is borrowed from llvm. --- amd64/isel.c | 26 ++++++++++++++++++++++++++ arm64/emit.c | 2 ++ doc/il.txt | 16 ++++++++++------ fold.c | 2 ++ ops.h | 2 ++ test/fpcnv.ssa | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 6 deletions(-) diff --git a/amd64/isel.c b/amd64/isel.c index 17ab86d..570bff6 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -307,6 +307,32 @@ sel(Ins i, ANum *an, Fn *fn) emit(Oand, Kl, tmp[0], i.arg[0], getcon(1, fn)); fixarg(&curi->arg[0], Kl, curi, fn); break; + case Ostoui: + i.op = Ostosi; + r0 = newtmp("ftou", Ks, fn); + goto Oftoui; + case Odtoui: + i.op = Odtosi; + r0 = newtmp("ftou", Kd, fn); + Oftoui: + if (k == Kw) { + goto Emit; + } + for (j=0; j<4; j++) + tmp[j] = newtmp("ftou", Kl, fn); + emit(Oor, Kl, i.to, tmp[0], tmp[3]); + emit(Oand, Kl, tmp[3], tmp[2], tmp[1]); + emit(i.op, Kl, tmp[2], r0, R); + if (i.op == Ostosi) + emit(Oadd, Ks, r0, getcon(0xdf000000, fn), i.arg[0]); + else + emit(Oadd, Kd, r0, getcon(0xc3e0000000000000, fn), i.arg[0]); + i1 = curi; + fixarg(&i1->arg[0], i.op == Ostosi ? Ks : Kd, i1, fn); + fixarg(&i1->arg[1], i.op == Ostosi ? Ks : Kd, i1, fn); + emit(Osar, Kl, tmp[1], tmp[0], getcon(63, fn)); + emit(i.op, Kl, tmp[0], i.arg[0], R); + fixarg(&curi->arg[0], Kl, curi, fn); case Onop: break; case Ostored: diff --git a/arm64/emit.c b/arm64/emit.c index 7cebcab..70384c0 100644 --- a/arm64/emit.c +++ b/arm64/emit.c @@ -89,7 +89,9 @@ static struct { { Ocast, Ks, "fmov %=, %W0" }, { Ocast, Kd, "fmov %=, %L0" }, { Ostosi, Ka, "fcvtzs %=, %S0" }, + { Ostoui, Ka, "fcvtzu %=, %S0" }, { Odtosi, Ka, "fcvtzs %=, %D0" }, + { Odtoui, Ka, "fcvtzu %=, %D0" }, { Oswtof, Ka, "scvtf %=, %W0" }, { Ouwtof, Ka, "ucvtf %=, %W0" }, { Osltof, Ka, "scvtf %=, %L0" }, diff --git a/doc/il.txt b/doc/il.txt index 818f0a4..2236340 100644 --- a/doc/il.txt +++ b/doc/il.txt @@ -696,7 +696,9 @@ or convert a floating point into an integer and vice versa. * `exts` -- `d(s)` * `truncd` -- `s(d)` * `stosi` -- `I(ss)` + * `stoui` -- `I(ss)` * `dtosi` -- `I(dd)` + * `dtoui` -- `I(dd)` * `swtof` -- `F(ww)` * `uwtof` -- `F(ww)` * `sltof` -- `F(ll)` @@ -716,12 +718,12 @@ argument of `truncd` cannot be represented as a single-precision floating point, it is truncated towards zero. -Converting between signed integers and floating points is -done using `stosi` (single to signed integer), `dtosi` -(double to signed integer), `swtof` (signed word to float), -`uwtof` (unsigned word to float), `sltof` (signed long -to float) and `ultof` (unsigned long to float). Conversion -from unsigned types is not yet supported. +Converting between signed integers and floating points is done +using `stosi` (single to signed integer), `stoui` (single to +unsigned integer`, `dtosi` (double to signed integer), `dtoui` +(double to unsigned integer), `swtof` (signed word to float), +`uwtof` (unsigned word to float), `sltof` (signed long to +float) and `ultof` (unsigned long to float). Because of <@ Subtyping >, there is no need to have an instruction to lower the precision of an integer temporary. @@ -984,6 +986,7 @@ instructions unless you know exactly what you are doing. * <@ Conversions >: * `dtosi` + * `dtoui` * `exts` * `extsb` * `extsh` @@ -994,6 +997,7 @@ instructions unless you know exactly what you are doing. * `sltof` * `ultof` * `stosi` + * `stoui` * `swtof` * `uwtof` * `truncd` diff --git a/fold.c b/fold.c index 30e21d2..5d3c83c 100644 --- a/fold.c +++ b/fold.c @@ -387,7 +387,9 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr) case Oextsw: x = (int32_t)l.u; break; case Oextuw: x = (uint32_t)l.u; break; case Ostosi: x = w ? (int64_t)cl->bits.s : (int32_t)cl->bits.s; break; + case Ostoui: x = w ? (uint64_t)cl->bits.s : (uint32_t)cl->bits.s; break; case Odtosi: x = w ? (int64_t)cl->bits.d : (int32_t)cl->bits.d; break; + case Odtoui: x = w ? (uint64_t)cl->bits.d : (uint32_t)cl->bits.d; break; case Ocast: x = l.u; if (cl->type == CAddr) { diff --git a/ops.h b/ops.h index 04b0cf8..9f02262 100644 --- a/ops.h +++ b/ops.h @@ -96,7 +96,9 @@ O(extuw, T(e,w,e,e, e,x,e,e), 1) X(0, 0, 1) O(exts, T(e,e,e,s, e,e,e,x), 1) X(0, 0, 1) O(truncd, T(e,e,d,e, e,e,x,e), 1) X(0, 0, 1) O(stosi, T(s,s,e,e, x,x,e,e), 1) X(0, 0, 1) +O(stoui, T(s,s,e,e, x,x,e,e), 1) X(0, 0, 1) O(dtosi, T(d,d,e,e, x,x,e,e), 1) X(0, 0, 1) +O(dtoui, T(d,d,e,e, x,x,e,e), 1) X(0, 0, 1) O(swtof, T(e,e,w,w, e,e,x,x), 1) X(0, 0, 1) O(uwtof, T(e,e,w,w, e,e,x,x), 1) X(0, 0, 1) O(sltof, T(e,e,l,l, e,e,x,x), 1) X(0, 0, 1) diff --git a/test/fpcnv.ssa b/test/fpcnv.ssa index 4dac489..3036168 100644 --- a/test/fpcnv.ssa +++ b/test/fpcnv.ssa @@ -43,7 +43,37 @@ function d $ltod(l %l) { ret %rt } +export +function w $stow(s %f) { +@start + %rt =w stoui %f + ret %rt +} +export +function w $dtow(d %f) { +@start + %rt =w dtoui %f + ret %rt +} + +export +function l $stol(s %f) { +@start + %rt =l stoui %f + ret %rt +} +export +function l $dtol(d %f) { +@start + %rt =l dtoui %f + ret %rt +} + + + # >>> driver +# #include +# # extern float fneg(float); # extern double ftrunc(double); # @@ -52,10 +82,19 @@ function d $ltod(l %l) { # extern float ltos(long long unsigned int); # extern double ltod(long long unsigned int); # +# extern unsigned int stow(float); +# extern unsigned int dtow(double); +# extern unsigned long long stol(float); +# extern unsigned long long dtol(double); +# # unsigned long long iin[] = { 0, 1, 16, 234987, 427386245, 0x7fff0000, # 0xffff0000, 23602938196141, 72259248152500195, 9589010795705032704ull, # 0xdcf5fbe299d0148aull, 0xffffffff00000000ull, -1 }; # +# double fin[] = { 0.17346516197824458, 442.0760005466251, 4342856.879893436, +# 98547543006.49626, 236003043787688.3, 9.499222733527032e+18, +# 1.1936266170755652e+19 }; +# # int main() { # int i; # @@ -72,6 +111,18 @@ function d $ltod(l %l) { # return 6; # if (ltod(iin[i]) != (double)iin[i]) # return 7; +# } +# for (i=0; i UINT_MAX) +# continue; +# if (stow((float)fin[i]) != (unsigned int)(float)fin[i]) +# return 10; +# if (dtow(fin[i]) != (unsigned int)fin[i]) +# return 11; # } # return 0; # } -- cgit 1.4.1