static void check_cardinality(compile_t* c, LLVMValueRef desc, size_t size, LLVMBasicBlockRef next_block) { LLVMValueRef field_count = gendesc_fieldcount(c, desc); LLVMValueRef count = LLVMConstInt(c->i32, size, false); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntEQ, count, field_count, ""); LLVMBasicBlockRef continue_block = codegen_block(c, "pattern_continue"); LLVMBuildCondBr(c->builder, test, continue_block, next_block); LLVMPositionBuilderAtEnd(c->builder, continue_block); }
static void trace_dynamic_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef ptr, LLVMValueRef desc, ast_t* type, ast_t* orig, ast_t* tuple) { // Build a "don't care" type of our cardinality. size_t cardinality = ast_childcount(type); ast_t* dontcare = ast_from(type, TK_TUPLETYPE); for(size_t i = 0; i < cardinality; i++) ast_append(dontcare, ast_from(type, TK_DONTCARE)); // Replace our type in the tuple type with the "don't care" type. bool in_tuple = (tuple != NULL); if(in_tuple) ast_swap(type, dontcare); else tuple = dontcare; // If the original type is a subtype of the test type, then we are always // the correct cardinality. Otherwise, we need to dynamically check // cardinality. LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); if(!is_subtype(orig, tuple, NULL)) { LLVMValueRef dynamic_count = gendesc_fieldcount(c, desc); LLVMValueRef static_count = LLVMConstInt(c->i32, cardinality, false); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntEQ, static_count, dynamic_count, ""); // Skip if not the right cardinality. LLVMBuildCondBr(c->builder, test, is_true, is_false); } else { LLVMBuildBr(c->builder, is_true); } LLVMPositionBuilderAtEnd(c->builder, is_true); size_t index = 0; ast_t* child = ast_child(type); ast_t* dc_child = ast_child(dontcare); while(child != NULL) { switch(trace_type(child)) { case TRACE_PRIMITIVE: // Skip this element. break; case TRACE_ACTOR: case TRACE_KNOWN: case TRACE_UNKNOWN: case TRACE_KNOWN_VAL: case TRACE_UNKNOWN_VAL: case TRACE_TAG: case TRACE_TAG_OR_ACTOR: case TRACE_DYNAMIC: { // If we are (A, B), turn (_, _) into (A, _). ast_t* swap = ast_dup(child); ast_swap(dc_child, swap); // Create a next block. LLVMBasicBlockRef next_block = codegen_block(c, ""); // Load the object from the tuple field. LLVMValueRef field_info = gendesc_fieldinfo(c, desc, index); LLVMValueRef object = gendesc_fieldload(c, ptr, field_info); // Trace dynamic, even if the tuple thinks the field isn't dynamic. trace_dynamic(c, ctx, object, swap, orig, tuple, next_block); // Continue into the next block. LLVMBuildBr(c->builder, next_block); LLVMPositionBuilderAtEnd(c->builder, next_block); // Restore (A, _) to (_, _). ast_swap(swap, dc_child); ast_free_unattached(swap); break; } case TRACE_TUPLE: { // If we are (A, B), turn (_, _) into (A, _). ast_t* swap = ast_dup(child); ast_swap(dc_child, swap); // Get a pointer to the unboxed tuple and it's descriptor. LLVMValueRef field_info = gendesc_fieldinfo(c, desc, index); LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info); LLVMValueRef field_desc = gendesc_fielddesc(c, field_info); // Trace the tuple dynamically. trace_dynamic_tuple(c, ctx, field_ptr, field_desc, swap, orig, tuple); // Restore (A, _) to (_, _). ast_swap(swap, dc_child); ast_free_unattached(swap); break; } default: {} } index++; child = ast_sibling(child); dc_child = ast_sibling(dc_child); } // Restore the tuple type. if(in_tuple) ast_swap(dontcare, type); ast_free_unattached(dontcare); // Continue with other possible tracings. LLVMBuildBr(c->builder, is_false); LLVMPositionBuilderAtEnd(c->builder, is_false); }