diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 7d9eefe19..cad2be85b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -217,7 +217,7 @@ bool check_is_terminating(Ast *node, String const &label) { } case_end; - case_ast_node(rs, InlineRangeStmt, node); + case_ast_node(rs, UnrollRangeStmt, node); return false; case_end; @@ -675,7 +675,7 @@ void add_constant_switch_case(CheckerContext *ctx, Map *seen, Oper } void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { - ast_node(irs, InlineRangeStmt, node); + ast_node(irs, UnrollRangeStmt, node); check_open_scope(ctx, node); Type *val0 = nullptr; @@ -1303,7 +1303,7 @@ void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { case Ast_IfStmt: case Ast_ForStmt: case Ast_RangeStmt: - case Ast_InlineRangeStmt: + case Ast_UnrollRangeStmt: case Ast_SwitchStmt: case Ast_TypeSwitchStmt: // TODO(bill): Is this a correct checking system? @@ -1903,7 +1903,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_close_scope(ctx); case_end; - case_ast_node(irs, InlineRangeStmt, node); + case_ast_node(irs, UnrollRangeStmt, node); check_inline_range_stmt(ctx, node, mod_flags); case_end; diff --git a/src/ir.cpp b/src/ir.cpp index 1c81f08ed..bd3c0409c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10892,8 +10892,8 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { ir_start_block(proc, done); case_end; - case_ast_node(rs, InlineRangeStmt, node); - ir_emit_comment(proc, str_lit("InlineRangeStmt")); + case_ast_node(rs, UnrollRangeStmt, node); + ir_emit_comment(proc, str_lit("UnrollRangeStmt")); ir_open_scope(proc); // Open scope here irBlock *done = ir_new_block(proc, node, "inline.for.done"); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index d3bc3d0f8..6ed94661e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -4295,7 +4295,7 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) { lb_start_block(p, done); } -void lb_build_inline_range_stmt(lbProcedure *p, AstInlineRangeStmt *rs, Scope *scope) { +void lb_build_inline_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) { lbModule *m = p->module; lb_open_scope(p, scope); // Open scope here @@ -5288,7 +5288,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { lb_build_range_stmt(p, rs, node->scope); case_end; - case_ast_node(rs, InlineRangeStmt, node); + case_ast_node(rs, UnrollRangeStmt, node); lb_build_inline_range_stmt(p, rs, node->scope); case_end; @@ -9103,50 +9103,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_trailing_zeros: - { - lbValue x = lb_build_expr(p, ce->args[0]); - x = lb_emit_conv(p, x, tv.type); - - char const *name = "llvm.cttz"; - LLVMTypeRef types[1] = {lb_type(p->module, tv.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = tv.type; - return res; - } + return lb_emit_trailing_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); case BuiltinProc_count_ones: + return lb_emit_count_ones(p, lb_build_expr(p, ce->args[0]), tv.type); + case BuiltinProc_reverse_bits: - { - lbValue x = lb_build_expr(p, ce->args[0]); - x = lb_emit_conv(p, x, tv.type); - - char const *name = nullptr; - switch (id) { - case BuiltinProc_count_ones: name = "llvm.ctpop"; break; - case BuiltinProc_reverse_bits: name = "llvm.bitreverse"; break; - } - LLVMTypeRef types[1] = {lb_type(p->module, tv.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = x.value; - - lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); - res.type = tv.type; - return res; - } + return lb_emit_reverse_bits(p, lb_build_expr(p, ce->args[0]), tv.type); case BuiltinProc_byte_swap: { @@ -9985,6 +9948,72 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) { } +lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) { + x = lb_emit_conv(p, x, type); + + char const *name = "llvm.ctpop"; + LLVMTypeRef types[1] = {lb_type(p->module, type)}; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[1] = {}; + args[0] = x.value; + + lbValue res = {}; + res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.type = type; + return res; +} + + +lbValue lb_emit_trailing_zeros(lbProcedure *p, lbValue x, Type *type) { + x = lb_emit_conv(p, x, type); + + char const *name = "llvm.cttz"; + LLVMTypeRef types[1] = {lb_type(p->module, type)}; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[2] = {}; + args[0] = x.value; + args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); + + lbValue res = {}; + res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.type = type; + return res; +} + + +lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) { + x = lb_emit_conv(p, x, type); + + char const *name = "llvm.bitreverse"; + LLVMTypeRef types[1] = {lb_type(p->module, type)}; + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + LLVMValueRef args[1] = {}; + args[0] = x.value; + + lbValue res = {}; + res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.type = type; + return res; +} + + +lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x) { + GB_ASSERT(is_type_bit_set(x.type)); + Type *underlying = bit_set_to_int(x.type); + lbValue card = lb_emit_count_ones(p, x, underlying); + return lb_emit_conv(p, card, t_int); +} + + lbLoopData lb_loop_start(lbProcedure *p, isize count, Type *index_type) { lbLoopData data = {}; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 004d6b905..9c8c357f0 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -396,6 +396,12 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); LLVMMetadataRef lb_debug_type(lbModule *m, Type *type); +lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type); +lbValue lb_emit_trailing_zeros(lbProcedure *p, lbValue x, Type *type); +lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type); + +lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x); + #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" diff --git a/src/parser.cpp b/src/parser.cpp index 18a4ba9d2..c3bfc4dab 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -58,7 +58,7 @@ Token ast_token(Ast *node) { case Ast_ReturnStmt: return node->ReturnStmt.token; case Ast_ForStmt: return node->ForStmt.token; case Ast_RangeStmt: return node->RangeStmt.token; - case Ast_InlineRangeStmt: return node->InlineRangeStmt.inline_token; + case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token; case Ast_CaseClause: return node->CaseClause.token; case Ast_SwitchStmt: return node->SwitchStmt.token; case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; @@ -319,11 +319,11 @@ Ast *clone_ast(Ast *node) { n->RangeStmt.expr = clone_ast(n->RangeStmt.expr); n->RangeStmt.body = clone_ast(n->RangeStmt.body); break; - case Ast_InlineRangeStmt: - n->InlineRangeStmt.val0 = clone_ast(n->InlineRangeStmt.val0); - n->InlineRangeStmt.val1 = clone_ast(n->InlineRangeStmt.val1); - n->InlineRangeStmt.expr = clone_ast(n->InlineRangeStmt.expr); - n->InlineRangeStmt.body = clone_ast(n->InlineRangeStmt.body); + case Ast_UnrollRangeStmt: + n->UnrollRangeStmt.val0 = clone_ast(n->UnrollRangeStmt.val0); + n->UnrollRangeStmt.val1 = clone_ast(n->UnrollRangeStmt.val1); + n->UnrollRangeStmt.expr = clone_ast(n->UnrollRangeStmt.expr); + n->UnrollRangeStmt.body = clone_ast(n->UnrollRangeStmt.body); break; case Ast_CaseClause: n->CaseClause.list = clone_ast_array(n->CaseClause.list); @@ -851,15 +851,15 @@ Ast *ast_range_stmt(AstFile *f, Token token, Slice vals, Token in_token, return result; } -Ast *ast_inline_range_stmt(AstFile *f, Token inline_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { - Ast *result = alloc_ast_node(f, Ast_InlineRangeStmt); - result->InlineRangeStmt.inline_token = inline_token; - result->InlineRangeStmt.for_token = for_token; - result->InlineRangeStmt.val0 = val0; - result->InlineRangeStmt.val1 = val1; - result->InlineRangeStmt.in_token = in_token; - result->InlineRangeStmt.expr = expr; - result->InlineRangeStmt.body = body; +Ast *ast_unroll_range_stmt(AstFile *f, Token unroll_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { + Ast *result = alloc_ast_node(f, Ast_UnrollRangeStmt); + result->UnrollRangeStmt.unroll_token = unroll_token; + result->UnrollRangeStmt.for_token = for_token; + result->UnrollRangeStmt.val0 = val0; + result->UnrollRangeStmt.val1 = val1; + result->UnrollRangeStmt.in_token = in_token; + result->UnrollRangeStmt.expr = expr; + result->UnrollRangeStmt.body = body; return result; } @@ -4258,9 +4258,9 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo } -Ast *parse_unrolled_for_loop(AstFile *f, Token inline_token) { - if (inline_token.kind == Token_inline) { - syntax_warning(inline_token, "'inline for' is deprecated in favour of `#unroll for'"); +Ast *parse_unrolled_for_loop(AstFile *f, Token unroll_token) { + if (unroll_token.kind == Token_inline) { + syntax_warning(unroll_token, "'inline for' is deprecated in favour of `#unroll for'"); } Token for_token = expect_token(f, Token_for); Ast *val0 = nullptr; @@ -4308,9 +4308,9 @@ Ast *parse_unrolled_for_loop(AstFile *f, Token inline_token) { body = parse_block_stmt(f, false); } if (bad_stmt) { - return ast_bad_stmt(f, inline_token, f->curr_token); + return ast_bad_stmt(f, unroll_token, f->curr_token); } - return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body); + return ast_unroll_range_stmt(f, unroll_token, for_token, val0, val1, in_token, expr, body); } Ast *parse_stmt(AstFile *f) { @@ -4320,8 +4320,8 @@ Ast *parse_stmt(AstFile *f) { // Operands case Token_inline: if (peek_token_kind(f, Token_for)) { - Token inline_token = expect_token(f, Token_inline); - return parse_unrolled_for_loop(f, inline_token); + Token unroll_token = expect_token(f, Token_inline); + return parse_unrolled_for_loop(f, unroll_token); } /* fallthrough */ case Token_no_inline: diff --git a/src/parser.hpp b/src/parser.hpp index 1ff073f91..8c2eadb46 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -415,8 +415,8 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *expr; \ Ast *body; \ }) \ - AST_KIND(InlineRangeStmt, "inline range statement", struct { \ - Token inline_token; \ + AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \ + Token unroll_token; \ Token for_token; \ Ast *val0; \ Ast *val1; \