mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 14:48:47 +00:00
Custom struct alignment
This commit is contained in:
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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"), \
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user