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

View File

@@ -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);
}
}
*/
}

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
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);
}

View File

@@ -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 {

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);
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) {

View File

@@ -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

View File

@@ -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: {

File diff suppressed because it is too large Load Diff

View File

@@ -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"), \

View File

@@ -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) {