cosmopolitan/third_party/chibicc/cast.c

181 lines
7.4 KiB
C

#include "third_party/chibicc/chibicc.h"
#define REDZONE(X) \
"sub\t$16,%rsp\n" \
"\t" X "\n" \
"\tadd\t$16,%rsp"
#define PUSHPOPRAX(X) \
"push\t%rax\n" \
"\t" X "\n" \
"\tpop\t%rax"
#ifdef __SSE3__
#define FIST(X) REDZONE("fistt" X)
#else
#define FIST(X) \
REDZONE("fnstcw\t8(%rsp)\n" \
"\tmovzwl\t8(%rsp),%eax\n" \
"\tor\t$12,%ah\n" \
"\tmov\t%ax,10(%rsp)\n" \
"\tfldcw\t10(%rsp)\n" \
"\tfist" X "\n" \
"\tfldcw\t8(%rsp)")
#endif
#define u64f64 \
"test\t%rax,%rax\n" \
"\tjs\t1f\n" \
"\tpxor\t%xmm0,%xmm0\n" \
"\tcvtsi2sd %rax,%xmm0\n" \
"\tjmp\t2f\n" \
"1:\n" \
"\tmov\t%rax,%rdi\n" \
"\tand\t$1,%eax\n" \
"\tpxor\t%xmm0,%xmm0\n" \
"\tshr\t%rdi\n" \
"\tor\t%rax,%rdi\n" \
"\tcvtsi2sd %rdi,%xmm0\n" \
"\taddsd\t%xmm0,%xmm0\n" \
"2:"
#define u64f80 \
PUSHPOPRAX("fildq\t(%rsp)\n" \
"\ttest\t%rax,%rax\n" \
"\tjns\t1f\n" \
"\tmov\t$0x5f800000,(%rsp)\n" \
"\tfadds\t(%rsp)\n" \
"1:")
#define i32i8 "movsbl\t%al,%eax"
#define i32u8 "movzbl\t%al,%eax"
#define i32i16 "cwtl"
#define i32u16 "movzwl\t%ax,%eax"
#define i32f32 "cvtsi2ssl %eax,%xmm0"
#define i32i64 "cltq"
#define i32f64 "cvtsi2sdl %eax,%xmm0"
#define u32i64 "mov\t%eax,%eax"
#define i64f32 "cvtsi2ssq %rax,%xmm0"
#define i64f64 "cvtsi2sdq %rax,%xmm0"
#define f32i32 "cvttss2sil %xmm0,%eax"
#define f32u32 "cvttss2siq %xmm0,%rax"
#define f32i64 "cvttss2siq %xmm0,%rax"
#define f32u64 "cvttss2siq %xmm0,%rax"
#define f32f64 "cvtss2sd %xmm0,%xmm0"
#define f64i32 "cvttsd2sil %xmm0,%eax"
#define f64u32 "cvttsd2siq %xmm0,%rax"
#define f64i64 "cvttsd2siq %xmm0,%rax"
#define f64u64 "cvttsd2siq %xmm0,%rax"
#define f64f32 "cvtsd2ss %xmm0,%xmm0"
#define u64f32 "cvtsi2ssq %rax,%xmm0"
#define f32i8 "cvttss2sil %xmm0,%eax\n\tmovsbl\t%al,%eax"
#define f32u8 "cvttss2sil %xmm0,%eax\n\tmovzbl\t%al,%eax"
#define f32i16 "cvttss2sil %xmm0,%eax\n\tmovswl\t%ax,%eax"
#define f32u16 "cvttss2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax"
#define f64i8 "cvttsd2sil %xmm0,%eax\n\tmovsbl\t%al,%eax"
#define f64u8 "cvttsd2sil %xmm0,%eax\n\tmovzbl\t%al,%eax"
#define f64i16 "cvttsd2sil %xmm0,%eax\n\tmovswl\t%ax,%eax"
#define f64u16 "cvttsd2sil %xmm0,%eax\n\tmovzwl\t%ax,%eax"
#define f64f80 REDZONE("movsd\t%xmm0,(%rsp)\n\tfldl\t(%rsp)")
#define f80i8 FIST("ps\t(%rsp)\n\tmovsbl\t(%rsp),%eax")
#define f80u8 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax")
#define f80i16 FIST("ps\t(%rsp)\n\tmovzbl\t(%rsp),%eax")
#define f80u16 FIST("pl\t(%rsp)\n\tmovswl\t(%rsp),%eax")
#define f80i32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax")
#define f80u32 FIST("pl\t(%rsp)\n\tmov\t(%rsp),%eax")
#define f80i64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax")
#define f80u64 FIST("pq\t(%rsp)\n\tmov\t(%rsp),%rax")
#define f80f32 REDZONE("fstps\t(%rsp)\n\tmovss\t(%rsp),%xmm0")
#define f80f64 REDZONE("fstpl\t(%rsp)\n\tmovsd\t(%rsp),%xmm0")
#define i32f80 PUSHPOPRAX("fildl\t(%rsp)")
#define u32f32 "mov\t%eax,%eax\n\tcvtsi2ssq %rax,%xmm0"
#define u32f64 "mov\t%eax,%eax\n\tcvtsi2sdq %rax,%xmm0"
#define u32f80 "mov\t%eax,%eax\n\tpush %rax\n\tfildll\t(%rsp)\n\tpop\t%rax"
#define i64f80 PUSHPOPRAX("fildll\t(%rsp)")
#define f32f80 REDZONE("movss\t%xmm0,(%rsp)\n\tflds\t(%rsp)")
#define i8i128 "movsbq\t%al,%rax\n\tcqto"
#define i16i128 "movswq\t%ax,%rax\n\tcqto"
#define i32i128 "cltq\n\tcqto"
#define i64i128 "cqto"
#define u8i128 "movzbq\t%al,%rax\n\txor\t%edx,%edx"
#define u16i128 "movzwq\t%ax,%rax\n\txor\t%edx,%edx"
#define u32i128 "cltq\n\txor\t%edx,%edx"
#define u64i128 "xor\t%edx,%edx"
#define i128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattisf"
#define i128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattidf"
#define i128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floattixf"
#define u128f32 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntisf"
#define u128f64 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntidf"
#define u128f80 "mov\t%rax,%rdi\n\tmov\t%rdx,%rsi\n\tcall\t__floatuntixf"
#define f32i128 "call\t__fixsfti"
#define f64i128 "call\t__fixdfti"
#define f80i128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixxfti")
#define f32u128 "call\t__fixunssfti"
#define f64u128 "call\t__fixunsdfti"
#define f80u128 REDZONE("fstpt\t(%rsp)\n\tcall\t__fixunsxfti")
enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80, I128, U128 };
static const char *const cast_table[13][13] = /* clang-format off */ {
// i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 f80 i128 u128
{NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i8
{i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i16
{i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // i32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64, i64f80, i64i128, i64i128}, // i64
{i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u8
{i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64, i32f80, i32i128, i32i128}, // u16
{i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64, u32f80, u32i128, i32i128}, // u32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64, u64f80, u64i128, u64i128}, // u64
{f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64, f32f80, f32i128, f32u128}, // f32
{f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL, f64f80, f64i128, f64u128}, // f64
{f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL, f80i128, f80u128}, // f80
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i128f32, i128f64, i128f80, NULL, NULL }, // i128
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u128f32, u128f64, u128f80, NULL, NULL }, // u128
} /* clang-format on */;
static int getTypeId(Type *ty) {
switch (ty->kind) {
case TY_CHAR:
return ty->is_unsigned ? U8 : I8;
case TY_SHORT:
return ty->is_unsigned ? U16 : I16;
case TY_INT:
return ty->is_unsigned ? U32 : I32;
case TY_LONG:
return ty->is_unsigned ? U64 : I64;
case TY_INT128:
return ty->is_unsigned ? U128 : I128;
case TY_FLOAT:
return F32;
case TY_DOUBLE:
return F64;
case TY_LDOUBLE:
return F80;
default:
return U64;
}
}
void gen_cast(Type *from, Type *to) {
bool skew;
if (to->kind == TY_VOID) return;
if (to->kind == TY_BOOL) {
cmp_zero(from);
println("\tsetne\t%%al");
println("\tmovzbl\t%%al,%%eax");
return;
}
int t1 = getTypeId(from);
int t2 = getTypeId(to);
if (cast_table[t1][t2]) {
if ((skew = (depth & 1) && strstr(cast_table[t1][t2], "call"))) {
println("\tsub\t$8,%%rsp");
depth++;
}
println("\t%s", cast_table[t1][t2]);
if (skew) {
println("\tadd\t$8,%%rsp");
depth--;
}
}
}