summaryrefslogtreecommitdiff
path: root/src/trans/codegen_c.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/trans/codegen_c.cpp')
-rw-r--r--src/trans/codegen_c.cpp49
1 files changed, 47 insertions, 2 deletions
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 7d38f7a6..4eb3509c 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -409,7 +409,11 @@ namespace {
m_of
<< "typedef struct { uint64_t lo, hi; } uint128_t;\n"
<< "typedef struct { uint64_t lo, hi; } int128_t;\n"
+ << "static inline float make_float(int is_neg, int exp, uint32_t mantissa_bits) { float rv; uint32_t vi=(mantissa_bits&((1<<23)-1))|((exp+127)<<23);if(is_neg)vi|=1<<31; memcpy(&rv, &vi, 4); return rv; }\n"
+ << "static inline double make_double(int is_neg, int exp, uint32_t mantissa_bits) { double rv; uint64_t vi=(mantissa_bits&((1ull<<52)-1))|((uint64_t)(exp+1023)<<52);if(is_neg)vi|=1ull<<63; memcpy(&rv, &vi, 4); return rv; }\n"
<< "static inline uint128_t make128(uint64_t v) { uint128_t rv = { v, 0 }; return rv; }\n"
+ << "static inline float cast128_float(uint128_t v) { if(v.hi == 0) return v.lo; int exp = 0; uint32_t mant = 0; return make_float(0, exp, mant); }\n"
+ << "static inline double cast128_double(uint128_t v) { if(v.hi == 0) return v.lo; int exp = 0; uint64_t mant = 0; return make_double(0, exp, mant); }\n"
<< "static inline int cmp128(uint128_t a, uint128_t b) { if(a.hi != b.hi) return a.hi < b.hi ? -1 : 1; if(a.lo != b.lo) return a.lo < b.lo ? -1 : 1; return 0; }\n"
<< "static inline bool add128_o(uint128_t a, uint128_t b, uint128_t* o) { o->lo = a.lo + b.lo; o->hi = a.hi + b.hi + (o->lo < a.lo ? 1 : 0); return (o->hi >= a.hi); }\n"
<< "static inline bool sub128_o(uint128_t a, uint128_t b, uint128_t* o) { o->lo = a.lo - b.lo; o->hi = a.hi - b.hi - (o->lo < a.lo ? 1 : 0); return (o->hi <= a.hi); }\n"
@@ -436,6 +440,8 @@ namespace {
<< "\treturn rv;\n"
<< "}\n"
<< "static inline int128_t make128s(int64_t v) { int128_t rv = { v, (v < 0 ? -1 : 0) }; return rv; }\n"
+ << "static inline float cast128s_float(int128_t v) { if(v.hi == 0) return v.lo; int exp = 0; uint32_t mant = 0; return make_float(0, exp, mant); }\n"
+ << "static inline double cast128s_double(int128_t v) { if(v.hi == 0) return v.lo; int exp = 0; uint64_t mant = 0; return make_double(0, exp, mant); }\n"
<< "static inline int cmp128s(int128_t a, int128_t b) { if(a.hi != b.hi) return (int64_t)a.hi < (int64_t)b.hi ? -1 : 1; if(a.lo != b.lo) return a.lo < b.lo ? -1 : 1; return 0; }\n"
<< "static inline bool add128s_o(int128_t a, int128_t b, int128_t* o) { o->lo = a.lo + b.lo; o->hi = a.hi + b.hi + (o->lo < a.lo ? 1 : 0); return (o->hi >= a.hi); }\n"
<< "static inline bool sub128s_o(int128_t a, int128_t b, int128_t* o) { o->lo = a.lo - b.lo; o->hi = a.hi - b.hi - (o->lo < a.lo ? 1 : 0); return (o->hi <= a.hi); }\n"
@@ -3151,8 +3157,38 @@ namespace {
MIR_BUG(mir_res, "Unreachable");
}
break;
+ case ::HIR::CoreType::F32:
+ emit_lvalue(dst);
+ m_of << " = ";
+ switch (ty.m_data.as_Primitive())
+ {
+ case ::HIR::CoreType::U128:
+ m_of << "cast128_float("; emit_lvalue(ve.val); m_of << ")";
+ break;
+ case ::HIR::CoreType::I128:
+ m_of << "cast128s_float("; emit_lvalue(ve.val); m_of << ")";
+ break;
+ default:
+ MIR_BUG(mir_res, "Unreachable");
+ }
+ break;
+ case ::HIR::CoreType::F64:
+ emit_lvalue(dst);
+ m_of << " = ";
+ switch (ty.m_data.as_Primitive())
+ {
+ case ::HIR::CoreType::U128:
+ m_of << "cast128_double("; emit_lvalue(ve.val); m_of << ")";
+ break;
+ case ::HIR::CoreType::I128:
+ m_of << "cast128s_double("; emit_lvalue(ve.val); m_of << ")";
+ break;
+ default:
+ MIR_BUG(mir_res, "Unreachable");
+ }
+ break;
default:
- MIR_BUG(mir_res, "Bad i128/u128 cast");
+ MIR_BUG(mir_res, "Bad i128/u128 cast - " << ty << " to " << ve.type);
}
return;
}
@@ -5178,7 +5214,16 @@ namespace {
TU_MATCHA( (ve), (c),
(Int,
if( c.v == INT64_MIN )
- m_of << "INT64_MIN";
+ {
+ if( m_options.emulated_i128 && c.t == ::HIR::CoreType::I128 )
+ {
+ m_of << "make128s(INT64_MIN)";
+ }
+ else
+ {
+ m_of << "INT64_MIN";
+ }
+ }
else
{
switch(c.t)