Handle a function returning bool, char or short

x86-64 psABI says that only the least significant 8 bits are
significant if RAX has a return value of a function returning bool.
Likewise, it looks like only the least significant 1 or 2 bytes
are guaranteed to have a correct value for char and short return
values, respectively.
This commit is contained in:
Rui Ueyama 2020-09-13 16:25:46 +09:00
parent 6a0ed71107
commit dcd4579226
5 changed files with 33 additions and 1 deletions

View File

@ -291,6 +291,21 @@ static void gen_expr(Node *node) {
println(" call %s", node->funcname);
println(" add $8, %%rsp");
}
// It looks like the most significant 48 or 56 bits in RAX may
// contain garbage if a function return type is short or bool/char,
// respectively. We clear the upper bits here.
switch (node->ty->kind) {
case TY_BOOL:
println(" movzx %%al, %%eax");
return;
case TY_CHAR:
println(" movsbl %%al, %%eax");
return;
case TY_SHORT:
println(" movswl %%ax, %%eax");
return;
}
return;
}
}

View File

@ -479,7 +479,7 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
return ty;
}
// func-params = ("void" | param ("," param)*)? ")"
// func-params = ("void" | param ("," param)*?)? ")"
// param = declspec declarator
static Type *func_params(Token **rest, Token *tok, Type *ty) {
if (equal(tok, "void") && equal(tok->next, ")")) {

View File

@ -1,3 +1,4 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -16,3 +17,8 @@ int *ext2 = &ext1;
int ext3 = 7;
int ext_fn1(int x) { return x; }
int ext_fn2(int x) { return x; }
int false_fn() { return 512; }
int true_fn() { return 513; }
int char_fn() { return (2<<8)+3; }
int short_fn() { return (2<<16)+5; }

View File

@ -65,6 +65,11 @@ void ret_none() {
return;
}
_Bool true_fn();
_Bool false_fn();
char char_fn();
short short_fn();
int main() {
ASSERT(3, ret3());
ASSERT(8, add2(3, 5));
@ -106,6 +111,11 @@ int main() {
ret_none();
ASSERT(1, true_fn());
ASSERT(0, false_fn());
ASSERT(3, char_fn());
ASSERT(5, short_fn());
printf("OK\n");
return 0;
}

View File

@ -2,5 +2,6 @@
void assert(int expected, int actual, char *code);
int printf();
int sprintf();
int strcmp(char *p, char *q);
int memcmp(char *p, char *q, long n);