181 lines
7.4 KiB
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--;
|
|
}
|
|
}
|
|
}
|