diff --git a/src/analyze.cpp b/src/analyze.cpp index f20d155e4..e0d34be28 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -163,10 +163,6 @@ static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *so return entry; } -static uint8_t log2_u64(uint64_t x) { - return (63 - clzll(x)); -} - static uint8_t bits_needed_for_unsigned(uint64_t x) { if (x == 0) { return 0; diff --git a/src/parsec.cpp b/src/parsec.cpp index 5b2c860bf..d2f5731e2 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -347,9 +347,60 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr); } +static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { + const Type *ty = qt.getTypePtr(); + switch (ty->getTypeClass()) { + case Type::Builtin: + { + const BuiltinType *builtin_ty = static_cast(ty); + switch (builtin_ty->getKind()) { + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + case BuiltinType::SChar: + return 8; + case BuiltinType::UInt128: + case BuiltinType::Int128: + return 128; + default: + return 0; + } + zig_unreachable(); + } + case Type::Typedef: + { + const TypedefType *typedef_ty = static_cast(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + const char *type_name = decl_name(typedef_decl); + if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { + return 8; + } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { + return 16; + } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { + return 32; + } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { + return 64; + } else { + return 0; + } + } + default: + return 0; + } + zig_unreachable(); +} + + static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, const SourceLocation &source_loc) { + uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); + if (int_bit_width != 0) { + // we can perform the log2 now. + uint64_t cast_bit_width = log2_u64(int_bit_width); + return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); + } + AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); // @import("std").math.Log2Int(c_long); diff --git a/src/util.hpp b/src/util.hpp index b4f90bc79..bf997bb08 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -147,4 +147,8 @@ bool uint64_eq(uint64_t a, uint64_t b); uint32_t ptr_hash(const void *ptr); bool ptr_eq(const void *a, const void *b); +static inline uint8_t log2_u64(uint64_t x) { + return (63 - clzll(x)); +} + #endif diff --git a/test/parsec.zig b/test/parsec.zig index 16650d24a..f408066d2 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -315,12 +315,11 @@ pub fn addCases(cases: &tests.ParseCContext) { \\pub const LUA_GLOBALSINDEX = -10002; ); - cases.add("sift right assign", + cases.add("shift right assign", \\int log2(unsigned a) { \\ int i = 0; \\ while (a > 0) { \\ a >>= 1; - \\ //i++; \\ } \\ return i; \\} @@ -334,4 +333,24 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ return i; \\} ); + + cases.add("shift right assign with a fixed size type", + \\#include + \\int log2(uint32_t a) { + \\ int i = 0; + \\ while (a > 0) { + \\ a >>= 1; + \\ } + \\ return i; + \\} + , + \\export fn log2(_arg_a: u32) -> c_int { + \\ var a = _arg_a; + \\ var i: c_int = 0; + \\ while (a > c_uint(0)) { + \\ a >>= u5(1); + \\ }; + \\ return i; + \\} + ); }