Custom struct alignment

This commit is contained in:
Ginger Bill
2017-02-05 15:19:30 +00:00
parent 7944b7714f
commit 2a5b674d33
9 changed files with 485 additions and 350 deletions
+15
View File
@@ -7,8 +7,21 @@
#import "os.odin"; #import "os.odin";
#import "sync.odin"; #import "sync.odin";
#import "utf8.odin"; #import "utf8.odin";
#import ht "http_test.odin";
main :: proc() { main :: proc() {
T0 :: struct #align 8 {};
/*
{
sig: u32;
x := __cpuid(0, ^sig);
fmt.println(sig, x);
}
i: int; i: int;
fmt.println("Hellope!"); fmt.println("Hellope!");
@@ -38,4 +51,6 @@ main :: proc() {
fmt.println(i); fmt.println(i);
} }
} }
*/
} }
+86 -86
View File
@@ -1,10 +1,10 @@
#import "fmt.odin" #import "fmt.odin";
#foreign_system_library "Ws2_32" when ODIN_OS == "windows" #foreign_system_library ws2 "Ws2_32.lib" when ODIN_OS == "windows";
SOCKET :: type uint SOCKET :: type uint;
INVALID_SOCKET :: ~(0 as SOCKET) INVALID_SOCKET :: ~(cast(SOCKET)0);
AF :: enum i32 { AF :: enum i32 {
UNSPEC = 0, // unspecified UNSPEC = 0, // unspecified
@@ -35,111 +35,111 @@ AF :: enum i32 {
SIP = 24, // Simple Internet Protocol SIP = 24, // Simple Internet Protocol
PIP = 25, // Help Identify PIP packets PIP = 25, // Help Identify PIP packets
MAX = 26, MAX = 26,
} };
SOCK_STREAM :: 1 SOCK_STREAM :: 1;
SOCKET_ERROR :: -1 SOCKET_ERROR :: -1;
IPPROTO_TCP :: 6 IPPROTO_TCP :: 6;
AI_PASSIVE :: 0x0020 AI_PASSIVE :: 0x0020;
SOMAXCONN :: 128 SOMAXCONN :: 128;
SD_RECEIVE :: 0 SD_RECEIVE :: 0;
SD_SEND :: 1 SD_SEND :: 1;
SD_BOTH :: 2 SD_BOTH :: 2;
WSADESCRIPTION_LEN :: 256 WSADESCRIPTION_LEN :: 256;
WSASYS_STATUS_LEN :: 128 WSASYS_STATUS_LEN :: 128;
WSADATA :: struct #ordered { WSADATA :: struct #ordered {
version: i16 version: i16,
high_version: i16 high_version: i16,
// NOTE(bill): This is x64 ordering // NOTE(bill): This is x64 ordering
max_sockets: u16 max_sockets: u16,
max_udp_dg: u16 max_udp_dg: u16,
vendor_info: ^byte vendor_info: ^byte,
description: [WSADESCRIPTION_LEN+1]byte description: [WSADESCRIPTION_LEN+1]byte,
system_status: [WSASYS_STATUS_LEN+1]byte system_status: [WSASYS_STATUS_LEN+1]byte,
} }
addrinfo :: struct #ordered { addrinfo :: struct #ordered {
flags: i32 flags: i32,
family: i32 family: i32,
socktype: i32 socktype: i32,
protocol: i32 protocol: i32,
addrlen: uint addrlen: uint,
canonname: ^u8 canonname: ^u8,
addr: ^sockaddr addr: ^sockaddr,
next: ^addrinfo next: ^addrinfo,
} }
sockaddr :: struct #ordered { sockaddr :: struct #ordered {
family: u16 family: u16,
data: [14]byte data: [14]byte,
} }
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
WSACleanup :: proc() -> i32 #foreign #dll_import WSACleanup :: proc() -> i32 #foreign ws2;
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign ws2;
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
WSAGetLastError :: proc() -> i32 #foreign #dll_import WSAGetLastError :: proc() -> i32 #foreign ws2;
to_c_string :: proc(s: string) -> ^byte { to_c_string :: proc(s: string) -> ^byte {
c_str := new_slice(byte, s.count+1) c_str := new_slice(byte, s.count+1);
assert(c_str.data != nil) assert(c_str.data != nil);
copy(c_str, s as []byte) copy(c_str, cast([]byte)s);
c_str[s.count] = 0 c_str[s.count] = 0;
return c_str.data return c_str.data;
} }
run :: proc() { run :: proc() {
wsa: WSADATA wsa: WSADATA;
res: ^addrinfo = nil res: ^addrinfo = nil;
hints: addrinfo hints: addrinfo;
s, client: SOCKET s, client: SOCKET;
if WSAStartup(2 | (2 << 8), ^wsa) != 0 { if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
fmt.println("WSAStartup failed: ", WSAGetLastError()) fmt.println("WSAStartup failed: ", WSAGetLastError());
return return;
} }
defer WSACleanup() defer WSACleanup();
hints.family = AF.INET as i32 hints.family = cast(i32)AF.INET;
hints.socktype = SOCK_STREAM hints.socktype = SOCK_STREAM;
hints.protocol = IPPROTO_TCP hints.protocol = IPPROTO_TCP;
hints.flags = AI_PASSIVE hints.flags = AI_PASSIVE;
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 { if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
fmt.println("getaddrinfo failed: ", WSAGetLastError()) fmt.println("getaddrinfo failed: ", WSAGetLastError());
return return;
} }
defer freeaddrinfo(res) defer freeaddrinfo(res);
s = socket(res.family, res.socktype, res.protocol) s = socket(res.family, res.socktype, res.protocol);
if s == INVALID_SOCKET { if s == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError()) fmt.println("socket failed: ", WSAGetLastError());
return return;
} }
defer closesocket(s) defer closesocket(s);
bind(s, res.addr, res.addrlen as i32) bind(s, res.addr, cast(i32)res.addrlen);
listen(s, SOMAXCONN) listen(s, SOMAXCONN);
client = accept(s, nil, 0) client = accept(s, nil, 0);
if client == INVALID_SOCKET { if client == INVALID_SOCKET {
fmt.println("socket failed: ", WSAGetLastError()) fmt.println("socket failed: ", WSAGetLastError());
return return;
} }
defer closesocket(client) defer closesocket(client);
html := html :=
`HTTP/1.1 200 OK `HTTP/1.1 200 OK
@@ -154,27 +154,27 @@ Content-type: text/html
<h1 style="color: orange;">Odin Server Demo</h1> <h1 style="color: orange;">Odin Server Demo</h1>
</body> </body>
</html> </html>
` `;
buf: [1024]byte buf: [1024]byte;
for { for {
bytes := recv(client, ^buf[0], buf.count as i32, 0) bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
if bytes > 0 { if bytes > 0 {
// fmt.println(buf[:bytes] as string) // fmt.println(buf[:bytes] as string)
bytes_sent := send(client, html.data, (html.count-1) as i32, 0) bytes_sent := send(client, html.data, cast(i32)(html.count-1), 0);
if bytes_sent == SOCKET_ERROR { if bytes_sent == SOCKET_ERROR {
fmt.println("send failed: ", WSAGetLastError()) fmt.println("send failed: ", WSAGetLastError());
return return;
} }
break break;
} else if bytes == 0 { } else if bytes == 0 {
fmt.println("Connection closing...") fmt.println("Connection closing...");
break break;
} else { } else {
fmt.println("recv failed: ", WSAGetLastError()) fmt.println("recv failed: ", WSAGetLastError());
return return;
} }
} }
shutdown(client, SD_SEND) shutdown(client, SD_SEND);
} }
+3
View File
@@ -119,6 +119,9 @@ __debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
__trap :: proc() #foreign __llvm_core "llvm.trap"; __trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter"; read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
__cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid";
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it) // IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
Allocator_Mode :: enum u8 { Allocator_Mode :: enum u8 {
+39
View File
@@ -553,6 +553,45 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
} }
type_set_offsets(c->sizes, c->allocator, struct_type); type_set_offsets(c->sizes, c->allocator, struct_type);
if (st->align != NULL) {
if (st->is_packed) {
syntax_error_node(st->align, "`#align` cannot be applied with `#packed`");
return;
}
Operand o = {0};
check_expr(c, &o, st->align);
if (o.mode != Addressing_Constant) {
if (o.mode != Addressing_Invalid) {
error_node(st->align, "#align must be a constant");
}
return;
}
Type *type = base_type(o.type);
if (is_type_untyped(type) || is_type_integer(type)) {
if (o.value.kind == ExactValue_Integer) {
i64 align = o.value.value_integer;
if (align < 1 || !gb_is_power_of_two(align)) {
error_node(st->align, "#align must be a power of 2, got %lld", align);
return;
}
// NOTE(bill): Success!!!
i64 custom_align = gb_clamp(align, 1, c->sizes.max_align);
if (custom_align < align) {
warning_node(st->align, "Custom alignment has been clamped to %lld from %lld", align, custom_align);
}
struct_type->Record.custom_align = custom_align;
return;
}
}
error_node(st->align, "#align must be an integer");
return;
}
} }
void check_union_type(Checker *c, Type *union_type, AstNode *node) { void check_union_type(Checker *c, Type *union_type, AstNode *node) {
+1 -1
View File
@@ -799,7 +799,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Token token = {0}; Token token = {0};
token.pos = ast_node_token(ms->body).pos; token.pos = ast_node_token(ms->body).pos;
token.string = str_lit("true"); token.string = str_lit("true");
x.expr = make_ident(c->curr_ast_file, token); x.expr = ast_ident(c->curr_ast_file, token);
} }
// NOTE(bill): Check for multiple defaults // NOTE(bill): Check for multiple defaults
+23 -2
View File
@@ -215,6 +215,12 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_fprintf(f, "<"); ir_fprintf(f, "<");
} }
ir_fprintf(f, "{"); ir_fprintf(f, "{");
if (t->Record.custom_align > 0) {
ir_fprintf(f, "[0 x <%lld x i8>]", t->Record.custom_align);
if (t->Record.field_count > 0) {
ir_fprintf(f, ", ");
}
}
for (isize i = 0; i < t->Record.field_count; i++) { for (isize i = 0; i < t->Record.field_count; i++) {
if (i > 0) { if (i > 0) {
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
@@ -755,6 +761,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_StructElementPtr: { case irInstr_StructElementPtr: {
Type *et = ir_type(instr->StructElementPtr.address); Type *et = ir_type(instr->StructElementPtr.address);
ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index); ir_fprintf(f, "%%%d = getelementptr inbounds ", value->index);
i32 index = instr->StructElementPtr.elem_index;
Type *st = base_type(type_deref(et));
if (is_type_struct(st)) {
if (st->Record.custom_align > 0) {
index += 1;
}
}
ir_print_type(f, m, type_deref(et)); ir_print_type(f, m, type_deref(et));
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
@@ -765,7 +778,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_print_type(f, m, t_int); ir_print_type(f, m, t_int);
ir_fprintf(f, " 0, "); ir_fprintf(f, " 0, ");
ir_print_type(f, m, t_i32); ir_print_type(f, m, t_i32);
ir_fprintf(f, " %d", instr->StructElementPtr.elem_index); ir_fprintf(f, " %d", index);
ir_fprintf(f, "\n"); ir_fprintf(f, "\n");
} break; } break;
@@ -816,11 +829,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
case irInstr_StructExtractValue: { case irInstr_StructExtractValue: {
Type *et = ir_type(instr->StructExtractValue.address); Type *et = ir_type(instr->StructExtractValue.address);
ir_fprintf(f, "%%%d = extractvalue ", value->index); ir_fprintf(f, "%%%d = extractvalue ", value->index);
i32 index = instr->StructExtractValue.index;
Type *st = base_type(et);
if (is_type_struct(st)) {
if (st->Record.custom_align > 0) {
index += 1;
}
}
ir_print_type(f, m, et); ir_print_type(f, m, et);
ir_fprintf(f, " "); ir_fprintf(f, " ");
ir_print_value(f, m, instr->StructExtractValue.address, et); ir_print_value(f, m, instr->StructExtractValue.address, et);
ir_fprintf(f, ", %d\n", instr->StructExtractValue.index); ir_fprintf(f, ", %d\n", index);
} break; } break;
case irInstr_UnionTagPtr: { case irInstr_UnionTagPtr: {
+312 -261
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -103,6 +103,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \ TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_map, "map"), \
TOKEN_KIND(Token_static, "static"), \ TOKEN_KIND(Token_static, "static"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \ TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_using, "using"), \
+5
View File
@@ -87,6 +87,8 @@ typedef struct TypeRecord {
bool struct_is_ordered; bool struct_is_ordered;
Entity **fields_in_src_order; // Entity_Variable Entity **fields_in_src_order; // Entity_Variable
i64 custom_align; // NOTE(bill): Only used in structs at the moment
Type * enum_base_type; Type * enum_base_type;
Entity * enum_count; Entity * enum_count;
Entity * enum_min_value; Entity * enum_min_value;
@@ -1459,6 +1461,9 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
case Type_Record: { case Type_Record: {
switch (t->Record.kind) { switch (t->Record.kind) {
case TypeRecord_Struct: case TypeRecord_Struct:
if (t->Record.custom_align > 0) {
return gb_clamp(t->Record.custom_align, 1, s.max_align);
}
if (t->Record.field_count > 0) { if (t->Record.field_count > 0) {
// TODO(bill): What is this supposed to be? // TODO(bill): What is this supposed to be?
if (t->Record.struct_is_packed) { if (t->Record.struct_is_packed) {