From baf5b9edc31eda5fe79dd1fee4b9a4378b10bd8b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 Apr 2020 19:26:16 +0100 Subject: [PATCH] Add `runtime.bswap_*` required for -llvm-api --- core/math/bits/bits.odin | 67 ++++++++++++++++++++++++-------------- core/mem/mem.odin | 9 ----- core/runtime/internal.odin | 16 +++++++++ src/checker.cpp | 5 +++ src/llvm_backend.cpp | 67 ++++++++++++++++++++++++-------------- 5 files changed, 106 insertions(+), 58 deletions(-) diff --git a/core/math/bits/bits.odin b/core/math/bits/bits.odin index 4075d1ac0..558eb05ab 100644 --- a/core/math/bits/bits.odin +++ b/core/math/bits/bits.odin @@ -1,6 +1,6 @@ package math_bits -import "core:os" +import "core:runtime" U8_MIN :: 0; U16_MIN :: 0; @@ -43,15 +43,32 @@ foreign { @(link_name="llvm.bitreverse.i16") reverse_bits16 :: proc(i: u16) -> u16 --- @(link_name="llvm.bitreverse.i32") reverse_bits32 :: proc(i: u32) -> u32 --- @(link_name="llvm.bitreverse.i64") reverse_bits64 :: proc(i: u64) -> u64 --- +} - @(link_name="llvm.bswap.i16") byte_swap_u16 :: proc(u16) -> u16 --- - @(link_name="llvm.bswap.i32") byte_swap_u32 :: proc(u32) -> u32 --- - @(link_name="llvm.bswap.i64") byte_swap_u64 :: proc(u64) -> u64 --- - @(link_name="llvm.bswap.i16") byte_swap_i16 :: proc(i16) -> i16 --- - @(link_name="llvm.bswap.i32") byte_swap_i32 :: proc(i32) -> i32 --- - @(link_name="llvm.bswap.i64") byte_swap_i64 :: proc(i64) -> i64 --- - @(link_name="llvm.bswap.i128") byte_swap_u128 :: proc(u128) -> u128 --- - @(link_name="llvm.bswap.i128") byte_swap_i128 :: proc(i128) -> i128 --- + +byte_swap_u16 :: proc(x: u16) -> u16 { + return u16(runtime.bswap_16(u16(x))); +} +byte_swap_u32 :: proc(x: u32) -> u32 { + return u32(runtime.bswap_32(u32(x))); +} +byte_swap_u64 :: proc(x: u64) -> u64 { + return u64(runtime.bswap_64(u64(x))); +} +byte_swap_i16 :: proc(x: i16) -> i16 { + return i16(runtime.bswap_16(u16(x))); +} +byte_swap_i32 :: proc(x: i32) -> i32 { + return i32(runtime.bswap_32(u32(x))); +} +byte_swap_i64 :: proc(x: i64) -> i64 { + return i64(runtime.bswap_64(u64(x))); +} +byte_swap_u128 :: proc(x: u128) -> u128 { + return u128(runtime.bswap_128(u128(x))); +} +byte_swap_i128 :: proc(x: i128) -> i128 { + return i128(runtime.bswap_128(u128(x))); } byte_swap_uint :: proc(i: uint) -> uint { @@ -100,29 +117,29 @@ rotate_right32 :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*siz rotate_right64 :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); } from_be_u8 :: proc(i: u8) -> u8 { return i; } -from_be_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } -from_be_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } -from_be_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } -from_be_uint :: proc(i: uint) -> uint { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } +from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } +from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } +from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } +from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } from_le_u8 :: proc(i: u8) -> u8 { return i; } -from_le_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } -from_le_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } -from_le_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } -from_le_uint :: proc(i: uint) -> uint { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } +from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } +from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } +from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } +from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } to_be_u8 :: proc(i: u8) -> u8 { return i; } -to_be_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } -to_be_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } -to_be_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } -to_be_uint :: proc(i: uint) -> uint { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } } +to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } +to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } +to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } +to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } } to_le_u8 :: proc(i: u8) -> u8 { return i; } -to_le_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } -to_le_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } -to_le_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } -to_le_uint :: proc(i: uint) -> uint { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } } +to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } +to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } +to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } +to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } } @(default_calling_convention="none") diff --git a/core/mem/mem.odin b/core/mem/mem.odin index f753a579d..99a16a6c9 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -2,15 +2,6 @@ package mem import "core:runtime" -foreign _ { - @(link_name = "llvm.bswap.i16") swap16 :: proc(b: u16) -> u16 ---; - @(link_name = "llvm.bswap.i32") swap32 :: proc(b: u32) -> u32 ---; - @(link_name = "llvm.bswap.i64") swap64 :: proc(b: u64) -> u64 ---; -} -swap :: proc{swap16, swap32, swap64}; - - - set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr { foreign _ { when ODIN_USE_LLVM_API { diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 2d4388bb2..4b3039802 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -2,6 +2,22 @@ package runtime import "core:os" +bswap_16 :: proc "none" (x: u16) -> u16 { + return x>>8 | x<<16; +} + +bswap_32 :: proc "none" (x: u32) -> u32 { + return x>>24 | (x>>8)&0xff00 | (x<<8)&0xff0000 | x<<24; +} + +bswap_64 :: proc "none" (x: u64) -> u64 { + return u64(bswap_32(u32(x))) | u64(bswap_32(u32(x>>32))); +} + +bswap_128 :: proc "none" (x: u128) -> u128 { + return u128(bswap_64(u64(x))) | u128(bswap_64(u64(x>>64))); +} + ptr_offset :: inline proc "contextless" (ptr: $P/^$T, n: int) -> P { new := int(uintptr(ptr)) + size_of(T)*n; return P(uintptr(new)); diff --git a/src/checker.cpp b/src/checker.cpp index a6cb80b7d..678339362 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1703,6 +1703,11 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("memory_compare"), str_lit("memory_compare_zero"), + + str_lit("bswap_16"), + str_lit("bswap_32"), + str_lit("bswap_64"), + str_lit("bswap_128"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 50f6bde73..938d09a38 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -7783,6 +7783,23 @@ void lb_emit_increment(lbProcedure *p, lbValue addr) { } +LLVMValueRef lb_lookup_runtime_procedure(lbModule *m, String const &name) { + AstPackage *pkg = m->info->runtime_package; + Entity *e = scope_lookup_current(pkg->scope, name); + + lbValue *found = nullptr; + if (m != e->code_gen_module) { + gb_mutex_lock(&m->mutex); + } + found = map_get(&e->code_gen_module->values, hash_entity(e)); + if (m != e->code_gen_module) { + gb_mutex_unlock(&m->mutex); + } + GB_ASSERT(found != nullptr); + + return found->value; +} + lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) { Type *vt = core_type(value.type); GB_ASSERT(type_size_of(vt) == type_size_of(platform_type)); @@ -7793,21 +7810,20 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) { res.type = platform_type; res.value = value.value; - // int sz = cast(int)type_size_of(vt); - // if (sz > 1) { - // char buf[32] = {}; - // gb_snprintf(buf, gb_count_of(buf), "llvm.bswap.i%d", sz*8); - // unsigned id = LLVMLookupIntrinsicID(buf, gb_strlen(buf)); - // gb_printf(">>> %s %u\n", buf, id); + int sz = cast(int)type_size_of(vt); + if (sz > 1) { + String name = {}; + switch (sz) { + case 2: name = str_lit("bswap_16"); break; + case 4: name = str_lit("bswap_32"); break; + case 8: name = str_lit("bswap_64"); break; + case 16: name = str_lit("bswap_128"); break; + default: GB_PANIC("unhandled byteswap size"); break; + } + LLVMValueRef fn = lb_lookup_runtime_procedure(p->module, name); - // LLVMTypeRef types[2] = {}; - // types[0] = lb_type(p->module, value.type); - // types[1] = lb_type(p->module, value.type); - - // LLVMValueRef fn = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - // res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, ""); - // } + res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, ""); + } return res; } @@ -7972,8 +7988,8 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { - Type *a = base_type(left.type); - Type *b = base_type(right.type); + Type *a = core_type(left.type); + Type *b = core_type(right.type); GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); @@ -8235,14 +8251,17 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } } + a = core_type(left.type); + b = core_type(right.type); + lbValue res = {}; res.type = t_llvm_bool; - if (is_type_integer(left.type) || - is_type_boolean(left.type) || - is_type_pointer(left.type) || - is_type_proc(left.type) || - is_type_enum(left.type)) { + if (is_type_integer(a) || + is_type_boolean(a) || + is_type_pointer(a) || + is_type_proc(a) || + is_type_enum(a)) { LLVMIntPredicate pred = {}; if (is_type_unsigned(left.type)) { switch (op_kind) { @@ -8264,7 +8283,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri case Token_NotEq: pred = LLVMIntNE; break; } res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); - } else if (is_type_float(left.type)) { + } else if (is_type_float(a)) { LLVMRealPredicate pred = {}; switch (op_kind) { case Token_CmpEq: pred = LLVMRealOEQ; break; @@ -8275,7 +8294,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri case Token_NotEq: pred = LLVMRealONE; break; } res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); - } else if (is_type_typeid(left.type)) { + } else if (is_type_typeid(a)) { LLVMIntPredicate pred = {}; switch (op_kind) { case Token_Gt: pred = LLVMIntUGT; break; @@ -8287,7 +8306,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); } else { - GB_PANIC("Unhandled comparison kind %s %.*s %s", type_to_string(left.type), LIT(token_strings[op_kind]), type_to_string(right.type)); + GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); } return res;