mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-07 13:33:13 +00:00
Custom struct alignment
This commit is contained in:
@@ -7,8 +7,21 @@
|
||||
#import "os.odin";
|
||||
#import "sync.odin";
|
||||
#import "utf8.odin";
|
||||
#import ht "http_test.odin";
|
||||
|
||||
|
||||
main :: proc() {
|
||||
T0 :: struct #align 8 {};
|
||||
|
||||
/*
|
||||
{
|
||||
sig: u32;
|
||||
x := __cpuid(0, ^sig);
|
||||
fmt.println(sig, x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
i: int;
|
||||
|
||||
fmt.println("Hellope!");
|
||||
@@ -38,4 +51,6 @@ main :: proc() {
|
||||
fmt.println(i);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
INVALID_SOCKET :: ~(0 as SOCKET)
|
||||
SOCKET :: type uint;
|
||||
INVALID_SOCKET :: ~(cast(SOCKET)0);
|
||||
|
||||
AF :: enum i32 {
|
||||
UNSPEC = 0, // unspecified
|
||||
@@ -35,111 +35,111 @@ AF :: enum i32 {
|
||||
SIP = 24, // Simple Internet Protocol
|
||||
PIP = 25, // Help Identify PIP packets
|
||||
MAX = 26,
|
||||
}
|
||||
};
|
||||
|
||||
SOCK_STREAM :: 1
|
||||
SOCKET_ERROR :: -1
|
||||
IPPROTO_TCP :: 6
|
||||
AI_PASSIVE :: 0x0020
|
||||
SOMAXCONN :: 128
|
||||
SOCK_STREAM :: 1;
|
||||
SOCKET_ERROR :: -1;
|
||||
IPPROTO_TCP :: 6;
|
||||
AI_PASSIVE :: 0x0020;
|
||||
SOMAXCONN :: 128;
|
||||
|
||||
SD_RECEIVE :: 0
|
||||
SD_SEND :: 1
|
||||
SD_BOTH :: 2
|
||||
SD_RECEIVE :: 0;
|
||||
SD_SEND :: 1;
|
||||
SD_BOTH :: 2;
|
||||
|
||||
WSADESCRIPTION_LEN :: 256
|
||||
WSASYS_STATUS_LEN :: 128
|
||||
WSADESCRIPTION_LEN :: 256;
|
||||
WSASYS_STATUS_LEN :: 128;
|
||||
WSADATA :: struct #ordered {
|
||||
version: i16
|
||||
high_version: i16
|
||||
version: i16,
|
||||
high_version: i16,
|
||||
|
||||
|
||||
// NOTE(bill): This is x64 ordering
|
||||
max_sockets: u16
|
||||
max_udp_dg: u16
|
||||
vendor_info: ^byte
|
||||
description: [WSADESCRIPTION_LEN+1]byte
|
||||
system_status: [WSASYS_STATUS_LEN+1]byte
|
||||
max_sockets: u16,
|
||||
max_udp_dg: u16,
|
||||
vendor_info: ^byte,
|
||||
description: [WSADESCRIPTION_LEN+1]byte,
|
||||
system_status: [WSASYS_STATUS_LEN+1]byte,
|
||||
}
|
||||
|
||||
addrinfo :: struct #ordered {
|
||||
flags: i32
|
||||
family: i32
|
||||
socktype: i32
|
||||
protocol: i32
|
||||
addrlen: uint
|
||||
canonname: ^u8
|
||||
addr: ^sockaddr
|
||||
next: ^addrinfo
|
||||
flags: i32,
|
||||
family: i32,
|
||||
socktype: i32,
|
||||
protocol: i32,
|
||||
addrlen: uint,
|
||||
canonname: ^u8,
|
||||
addr: ^sockaddr,
|
||||
next: ^addrinfo,
|
||||
}
|
||||
|
||||
sockaddr :: struct #ordered {
|
||||
family: u16
|
||||
data: [14]byte
|
||||
family: u16,
|
||||
data: [14]byte,
|
||||
}
|
||||
|
||||
|
||||
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import
|
||||
WSACleanup :: proc() -> i32 #foreign #dll_import
|
||||
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import
|
||||
freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import
|
||||
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import
|
||||
closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import
|
||||
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import
|
||||
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import
|
||||
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import
|
||||
recv :: 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 #dll_import
|
||||
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import
|
||||
WSAGetLastError :: proc() -> i32 #foreign #dll_import
|
||||
WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign ws2;
|
||||
WSACleanup :: proc() -> i32 #foreign ws2;
|
||||
getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign ws2;
|
||||
freeaddrinfo :: proc(ai: ^addrinfo) #foreign ws2;
|
||||
socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign ws2;
|
||||
closesocket :: proc(s: SOCKET) -> i32 #foreign ws2;
|
||||
bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign ws2;
|
||||
listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign ws2;
|
||||
accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign ws2;
|
||||
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 ws2;
|
||||
shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign ws2;
|
||||
WSAGetLastError :: proc() -> i32 #foreign ws2;
|
||||
|
||||
to_c_string :: proc(s: string) -> ^byte {
|
||||
c_str := new_slice(byte, s.count+1)
|
||||
assert(c_str.data != nil)
|
||||
copy(c_str, s as []byte)
|
||||
c_str[s.count] = 0
|
||||
return c_str.data
|
||||
c_str := new_slice(byte, s.count+1);
|
||||
assert(c_str.data != nil);
|
||||
copy(c_str, cast([]byte)s);
|
||||
c_str[s.count] = 0;
|
||||
return c_str.data;
|
||||
}
|
||||
|
||||
run :: proc() {
|
||||
wsa: WSADATA
|
||||
res: ^addrinfo = nil
|
||||
hints: addrinfo
|
||||
s, client: SOCKET
|
||||
wsa: WSADATA;
|
||||
res: ^addrinfo = nil;
|
||||
hints: addrinfo;
|
||||
s, client: SOCKET;
|
||||
|
||||
if WSAStartup(2 | (2 << 8), ^wsa) != 0 {
|
||||
fmt.println("WSAStartup failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("WSAStartup failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
defer WSACleanup()
|
||||
defer WSACleanup();
|
||||
|
||||
hints.family = AF.INET as i32
|
||||
hints.socktype = SOCK_STREAM
|
||||
hints.protocol = IPPROTO_TCP
|
||||
hints.flags = AI_PASSIVE
|
||||
hints.family = cast(i32)AF.INET;
|
||||
hints.socktype = SOCK_STREAM;
|
||||
hints.protocol = IPPROTO_TCP;
|
||||
hints.flags = AI_PASSIVE;
|
||||
|
||||
if getaddrinfo(nil, to_c_string("8080"), ^hints, ^res) != 0 {
|
||||
fmt.println("getaddrinfo failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("getaddrinfo failed: ", WSAGetLastError());
|
||||
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 {
|
||||
fmt.println("socket failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("socket failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
defer closesocket(s)
|
||||
defer closesocket(s);
|
||||
|
||||
bind(s, res.addr, res.addrlen as i32)
|
||||
listen(s, SOMAXCONN)
|
||||
bind(s, res.addr, cast(i32)res.addrlen);
|
||||
listen(s, SOMAXCONN);
|
||||
|
||||
client = accept(s, nil, 0)
|
||||
client = accept(s, nil, 0);
|
||||
if client == INVALID_SOCKET {
|
||||
fmt.println("socket failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("socket failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
defer closesocket(client)
|
||||
defer closesocket(client);
|
||||
|
||||
html :=
|
||||
`HTTP/1.1 200 OK
|
||||
@@ -154,27 +154,27 @@ Content-type: text/html
|
||||
<h1 style="color: orange;">Odin Server Demo</h1>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
`;
|
||||
|
||||
buf: [1024]byte
|
||||
buf: [1024]byte;
|
||||
for {
|
||||
bytes := recv(client, ^buf[0], buf.count as i32, 0)
|
||||
bytes := recv(client, ^buf[0], cast(i32)buf.count, 0);
|
||||
if bytes > 0 {
|
||||
// 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 {
|
||||
fmt.println("send failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("send failed: ", WSAGetLastError());
|
||||
return;
|
||||
}
|
||||
break
|
||||
break;
|
||||
} else if bytes == 0 {
|
||||
fmt.println("Connection closing...")
|
||||
break
|
||||
fmt.println("Connection closing...");
|
||||
break;
|
||||
} else {
|
||||
fmt.println("recv failed: ", WSAGetLastError())
|
||||
return
|
||||
fmt.println("recv failed: ", WSAGetLastError());
|
||||
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";
|
||||
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)
|
||||
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);
|
||||
|
||||
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) {
|
||||
|
||||
@@ -799,7 +799,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
Token token = {0};
|
||||
token.pos = ast_node_token(ms->body).pos;
|
||||
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
|
||||
|
||||
@@ -215,6 +215,12 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
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++) {
|
||||
if (i > 0) {
|
||||
ir_fprintf(f, ", ");
|
||||
@@ -755,6 +761,13 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
case irInstr_StructElementPtr: {
|
||||
Type *et = ir_type(instr->StructElementPtr.address);
|
||||
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_fprintf(f, ", ");
|
||||
@@ -765,7 +778,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
ir_print_type(f, m, t_int);
|
||||
ir_fprintf(f, " 0, ");
|
||||
ir_print_type(f, m, t_i32);
|
||||
ir_fprintf(f, " %d", instr->StructElementPtr.elem_index);
|
||||
ir_fprintf(f, " %d", index);
|
||||
ir_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
@@ -816,11 +829,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
||||
case irInstr_StructExtractValue: {
|
||||
Type *et = ir_type(instr->StructExtractValue.address);
|
||||
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_fprintf(f, " ");
|
||||
ir_print_value(f, m, instr->StructExtractValue.address, et);
|
||||
ir_fprintf(f, ", %d\n", instr->StructExtractValue.index);
|
||||
ir_fprintf(f, ", %d\n", index);
|
||||
} break;
|
||||
|
||||
case irInstr_UnionTagPtr: {
|
||||
|
||||
573
src/parser.c
573
src/parser.c
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_enum, "enum"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_map, "map"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
TOKEN_KIND(Token_using, "using"), \
|
||||
|
||||
@@ -87,6 +87,8 @@ typedef struct TypeRecord {
|
||||
bool struct_is_ordered;
|
||||
Entity **fields_in_src_order; // Entity_Variable
|
||||
|
||||
i64 custom_align; // NOTE(bill): Only used in structs at the moment
|
||||
|
||||
Type * enum_base_type;
|
||||
Entity * enum_count;
|
||||
Entity * enum_min_value;
|
||||
@@ -1459,6 +1461,9 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
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) {
|
||||
// TODO(bill): What is this supposed to be?
|
||||
if (t->Record.struct_is_packed) {
|
||||
|
||||
Reference in New Issue
Block a user