Add "float" and "double" local variables and casts

This commit is contained in:
Rui Ueyama 2020-09-12 14:47:47 +09:00
parent 1e57f72d8a
commit 29de46aed4
6 changed files with 148 additions and 17 deletions

View File

@ -71,7 +71,10 @@ static void gen_addr(Node *node) {
// Load a value from where %rax is pointing to.
static void load(Type *ty) {
if (ty->kind == TY_ARRAY || ty->kind == TY_STRUCT || ty->kind == TY_UNION) {
switch (ty->kind) {
case TY_ARRAY:
case TY_STRUCT:
case TY_UNION:
// If it is an array, do not attempt to load a value to the
// register because in general we can't load an entire array to a
// register. As a result, the result of an evaluation of an array
@ -79,6 +82,12 @@ static void load(Type *ty) {
// This is where "array is automatically converted to a pointer to
// the first element of the array in C" occurs.
return;
case TY_FLOAT:
println(" movss (%%rax), %%xmm0");
return;
case TY_DOUBLE:
println(" movsd (%%rax), %%xmm0");
return;
}
char *insn = ty->is_unsigned ? "movz" : "movs";
@ -102,12 +111,20 @@ static void load(Type *ty) {
static void store(Type *ty) {
pop("%rdi");
if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) {
switch (ty->kind) {
case TY_STRUCT:
case TY_UNION:
for (int i = 0; i < ty->size; i++) {
println(" mov %d(%%rax), %%r8b", i);
println(" mov %%r8b, %d(%%rdi)", i);
}
return;
case TY_FLOAT:
println(" movss %%xmm0, (%%rdi)");
return;
case TY_DOUBLE:
println(" movsd %%xmm0, (%%rdi)");
return;
}
if (ty->size == 1)
@ -127,7 +144,7 @@ static void cmp_zero(Type *ty) {
println(" cmp $0, %%rax");
}
enum { I8, I16, I32, I64, U8, U16, U32, U64 };
enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64 };
static int getTypeId(Type *ty) {
switch (ty->kind) {
@ -139,6 +156,10 @@ static int getTypeId(Type *ty) {
return ty->is_unsigned ? U32 : I32;
case TY_LONG:
return ty->is_unsigned ? U64 : I64;
case TY_FLOAT:
return F32;
case TY_DOUBLE:
return F64;
}
return U64;
}
@ -148,19 +169,57 @@ static char i32i8[] = "movsbl %al, %eax";
static char i32u8[] = "movzbl %al, %eax";
static char i32i16[] = "movswl %ax, %eax";
static char i32u16[] = "movzwl %ax, %eax";
static char i32f32[] = "cvtsi2ssl %eax, %xmm0";
static char i32i64[] = "movsxd %eax, %rax";
static char i32f64[] = "cvtsi2sdl %eax, %xmm0";
static char u32f32[] = "mov %eax, %eax; cvtsi2ssq %rax, %xmm0";
static char u32i64[] = "mov %eax, %eax";
static char u32f64[] = "mov %eax, %eax; cvtsi2sdq %rax, %xmm0";
static char i64f32[] = "cvtsi2ssq %rax, %xmm0";
static char i64f64[] = "cvtsi2sdq %rax, %xmm0";
static char u64f32[] = "cvtsi2ssq %rax, %xmm0";
static char u64f64[] =
"test %rax,%rax; js 1f; pxor %xmm0,%xmm0; cvtsi2sd %rax,%xmm0; jmp 2f; "
"1: mov %rax,%rdi; and $1,%eax; pxor %xmm0,%xmm0; shr %rdi; "
"or %rax,%rdi; cvtsi2sd %rdi,%xmm0; addsd %xmm0,%xmm0; 2:";
static char f32i8[] = "cvttss2sil %xmm0, %eax; movsbl %al, %eax";
static char f32u8[] = "cvttss2sil %xmm0, %eax; movzbl %al, %eax";
static char f32i16[] = "cvttss2sil %xmm0, %eax; movswl %ax, %eax";
static char f32u16[] = "cvttss2sil %xmm0, %eax; movzwl %ax, %eax";
static char f32i32[] = "cvttss2sil %xmm0, %eax";
static char f32u32[] = "cvttss2siq %xmm0, %rax";
static char f32i64[] = "cvttss2siq %xmm0, %rax";
static char f32u64[] = "cvttss2siq %xmm0, %rax";
static char f32f64[] = "cvtss2sd %xmm0, %xmm0";
static char f64i8[] = "cvttsd2sil %xmm0, %eax; movsbl %al, %eax";
static char f64u8[] = "cvttsd2sil %xmm0, %eax; movzbl %al, %eax";
static char f64i16[] = "cvttsd2sil %xmm0, %eax; movswl %ax, %eax";
static char f64u16[] = "cvttsd2sil %xmm0, %eax; movzwl %ax, %eax";
static char f64i32[] = "cvttsd2sil %xmm0, %eax";
static char f64u32[] = "cvttsd2siq %xmm0, %rax";
static char f64f32[] = "cvtsd2ss %xmm0, %xmm0";
static char f64i64[] = "cvttsd2siq %xmm0, %rax";
static char f64u64[] = "cvttsd2siq %xmm0, %rax";
static char *cast_table[][10] = {
// i8 i16 i32 i64 u8 u16 u32 u64
{NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64}, // i8
{i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64}, // i16
{i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64}, // i32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL}, // i64
{i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64}, // u8
{i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64}, // u16
{i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64}, // u32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL}, // u64
// i8 i16 i32 i64 u8 u16 u32 u64 f32 f64
{NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64}, // i8
{i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64}, // i16
{i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64}, // i32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64}, // i64
{i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64}, // u8
{i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64}, // u16
{i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64}, // u32
{i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64}, // u64
{f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64}, // f32
{f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL}, // f64
};
static void cast(Type *from, Type *to) {

20
parse.c
View File

@ -380,9 +380,11 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
SHORT = 1 << 6,
INT = 1 << 8,
LONG = 1 << 10,
OTHER = 1 << 12,
SIGNED = 1 << 13,
UNSIGNED = 1 << 14,
FLOAT = 1 << 12,
DOUBLE = 1 << 14,
OTHER = 1 << 16,
SIGNED = 1 << 17,
UNSIGNED = 1 << 18,
};
Type *ty = ty_int;
@ -461,6 +463,10 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
counter += INT;
else if (equal(tok, "long"))
counter += LONG;
else if (equal(tok, "float"))
counter += FLOAT;
else if (equal(tok, "double"))
counter += DOUBLE;
else if (equal(tok, "signed"))
counter |= SIGNED;
else if (equal(tok, "unsigned"))
@ -517,6 +523,12 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
case UNSIGNED + LONG + LONG + INT:
ty = ty_ulong;
break;
case FLOAT:
ty = ty_float;
break;
case DOUBLE:
ty = ty_double;
break;
default:
error_tok(tok, "invalid type");
}
@ -1125,7 +1137,7 @@ static bool is_typename(Token *tok) {
"void", "_Bool", "char", "short", "int", "long", "struct", "union",
"typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned",
"const", "volatile", "auto", "register", "restrict", "__restrict",
"__restrict__", "_Noreturn",
"__restrict__", "_Noreturn", "float", "double",
};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)

View File

@ -41,6 +41,19 @@ int main() {
ASSERT(-1, ({ typedef short T; T x = 65535; (int)x; }));
ASSERT(65535, ({ typedef unsigned short T; T x = 65535; (int)x; }));
ASSERT(0, (_Bool)0.0);
ASSERT(1, (_Bool)0.1);
ASSERT(3, (char)3.0);
ASSERT(1000, (short)1000.3);
ASSERT(3, (int)3.99);
ASSERT(2000000000000000, (long)2e15);
ASSERT(3, (float)3.5);
ASSERT(5, (double)(float)5.5);
ASSERT(3, (float)3);
ASSERT(3, (double)3);
ASSERT(3, (float)3L);
ASSERT(3, (double)3L);
printf("OK\n");
return 0;
}

44
test/float.c Normal file
View File

@ -0,0 +1,44 @@
#include "test.h"
int main() {
ASSERT(35, (float)(char)35);
ASSERT(35, (float)(short)35);
ASSERT(35, (float)(int)35);
ASSERT(35, (float)(long)35);
ASSERT(35, (float)(unsigned char)35);
ASSERT(35, (float)(unsigned short)35);
ASSERT(35, (float)(unsigned int)35);
ASSERT(35, (float)(unsigned long)35);
ASSERT(35, (double)(char)35);
ASSERT(35, (double)(short)35);
ASSERT(35, (double)(int)35);
ASSERT(35, (double)(long)35);
ASSERT(35, (double)(unsigned char)35);
ASSERT(35, (double)(unsigned short)35);
ASSERT(35, (double)(unsigned int)35);
ASSERT(35, (double)(unsigned long)35);
ASSERT(35, (char)(float)35);
ASSERT(35, (short)(float)35);
ASSERT(35, (int)(float)35);
ASSERT(35, (long)(float)35);
ASSERT(35, (unsigned char)(float)35);
ASSERT(35, (unsigned short)(float)35);
ASSERT(35, (unsigned int)(float)35);
ASSERT(35, (unsigned long)(float)35);
ASSERT(35, (char)(double)35);
ASSERT(35, (short)(double)35);
ASSERT(35, (int)(double)35);
ASSERT(35, (long)(double)35);
ASSERT(35, (unsigned char)(double)35);
ASSERT(35, (unsigned short)(double)35);
ASSERT(35, (unsigned int)(double)35);
ASSERT(35, (unsigned long)(double)35);
ASSERT(-2147483648, (double)(unsigned long)(long)-1);
printf("OK\n");
return 0;
}

View File

@ -84,6 +84,9 @@ int main() {
ASSERT(1, sizeof(char) << 31 >> 31);
ASSERT(1, sizeof(char) << 63 >> 63);
ASSERT(4, sizeof(float));
ASSERT(8, sizeof(double));
printf("OK\n");
return 0;
}

View File

@ -135,7 +135,7 @@ static bool is_keyword(Token *tok) {
"enum", "static", "goto", "break", "continue", "switch", "case",
"default", "extern", "_Alignof", "_Alignas", "do", "signed",
"unsigned", "const", "volatile", "auto", "register", "restrict",
"__restrict", "__restrict__", "_Noreturn",
"__restrict", "__restrict__", "_Noreturn", "float", "double",
};
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)