浏览代码

Custom struct alignment

Ginger Bill 8 年之前
父节点
当前提交
2a5b674d33
共有 9 个文件被更改,包括 370 次插入267 次删除
  1. 15 0
      code/demo.odin
  2. 86 86
      code/http_test.odin
  3. 3 0
      core/_preload.odin
  4. 39 0
      src/check_expr.c
  5. 1 1
      src/check_stmt.c
  6. 23 2
      src/ir_print.c
  7. 197 178
      src/parser.c
  8. 1 0
      src/tokenizer.c
  9. 5 0
      src/types.c

+ 15 - 0
code/demo.odin

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

+ 86 - 86
code/http_test.odin

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

+ 3 - 0
core/_preload.odin

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

+ 39 - 0
src/check_expr.c

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

+ 1 - 1
src/check_stmt.c

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

+ 23 - 2
src/ir_print.c

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

文件差异内容过多而无法显示
+ 197 - 178
src/parser.c


+ 1 - 0
src/tokenizer.c

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

+ 5 - 0
src/types.c

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

部分文件因为文件数量过多而无法显示