static void createPushHeapFunction() { // Saving last BasicBlock; LLVMBasicBlockRef OldBB = LLVMGetInsertBlock(Builder); LLVMTypeRef ParamType = LLVMPointerType(RAType, 0); LLVMTypeRef FunctionType = LLVMFunctionType(LLVMVoidType(), &ParamType, 1, 0); LLVMValueRef Function = LLVMAddFunction(Module, "push.heap", FunctionType); LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); LLVMPositionBuilderAtEnd(Builder, Entry); // Function Body LLVMValueRef HeapMalloc = LLVMBuildMalloc(Builder, HeapType, "heap.malloc"); LLVMValueRef ExPtrIdx[] = { getSConstInt(0), getSConstInt(0) }; LLVMValueRef LastPtrIdx[] = { getSConstInt(0), getSConstInt(1) }; LLVMValueRef ExPtr = LLVMBuildInBoundsGEP(Builder, HeapMalloc, ExPtrIdx, 2, "heap.exec"); LLVMValueRef LastPtr = LLVMBuildInBoundsGEP(Builder, HeapMalloc, LastPtrIdx, 2, "heap.last"); LLVMBuildStore(Builder, LLVMGetParam(Function, 0), ExPtr); LLVMBuildStore(Builder, LLVMBuildLoad(Builder, HeapHead, "ld.heap.head"), LastPtr); LLVMBuildStore(Builder, HeapMalloc, HeapHead); LLVMBuildRetVoid(Builder); // Restoring last BasicBlock LLVMPositionBuilderAtEnd(Builder, OldBB); }
static LLVMValueRef translateRecordExpr(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { PtrVector *V = &(Node->Child); ASTNode *FieldNode = (ASTNode*) ptrVectorGet(V, 0); Type *ThisType = createType(IdTy, Node->Value); LLVMTypeRef RecordType = getLLVMTypeFromType(TyTable, ThisType); LLVMValueRef RecordVal = LLVMBuildMalloc(Builder, RecordType, ""); unsigned FieldNumber = LLVMCountStructElementTypes(RecordType), I; for (I = 0; I < FieldNumber; ++I) { LLVMValueRef ElemIdx[] = { getSConstInt(0), getSConstInt(I) }; LLVMValueRef ElemI = LLVMBuildInBoundsGEP(Builder, RecordVal, ElemIdx, 2, ""); LLVMValueRef FieldPtr = translateExpr(TyTable, ValTable, ptrVectorGet(&(FieldNode->Child), I)); LLVMValueRef ValueFrom = NULL; switch (LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(FieldPtr)))) { case LLVMIntegerTypeKind: case LLVMFloatTypeKind: ValueFrom = LLVMBuildLoad(Builder, FieldPtr, ""); break; case LLVMPointerTypeKind: ValueFrom = toDynamicMemory(FieldPtr); break; default: ValueFrom = FieldPtr; } LLVMBuildStore(Builder, ValueFrom, ElemI); } return RecordVal; }
LLVMValueRef gendesc_fieldptr(compile_t* c, LLVMValueRef ptr, LLVMValueRef field_info) { LLVMValueRef offset = LLVMBuildExtractValue(c->builder, field_info, 0, ""); offset = LLVMBuildZExt(c->builder, offset, c->intptr, ""); return LLVMBuildInBoundsGEP(c->builder, ptr, &offset, 1, ""); }
static void make_serialise(compile_t* c, reach_type_t* t) { // Use the trace function as the serialise_trace function. t->serialise_trace_fn = t->trace_fn; // Generate the serialise function. t->serialise_fn = codegen_addfun(c, genname_serialise(t->name), c->serialise_type); codegen_startfun(c, t->serialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_fn, LLVMCCallConv); LLVMSetLinkage(t->serialise_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->serialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_fn, 1); LLVMValueRef addr = LLVMGetParam(t->serialise_fn, 2); LLVMValueRef offset = LLVMGetParam(t->serialise_fn, 3); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); LLVMValueRef offset_addr = LLVMBuildInBoundsGEP(c->builder, addr, &offset, 1, ""); serialise(c, t, ctx, object, offset_addr); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
LLVMValueRef gendesc_ptr_to_fields(compile_t* c, LLVMValueRef object, LLVMValueRef desc) { // Skip the descriptor. LLVMValueRef offset = desc_field(c, desc, DESC_FIELD_OFFSET); offset = LLVMBuildZExt(c->builder, offset, c->intptr, ""); LLVMValueRef base = LLVMBuildBitCast(c->builder, object, c->void_ptr, ""); return LLVMBuildInBoundsGEP(c->builder, base, &offset, 1, ""); }
static LLVMValueRef translateArrAccessLval(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { ASTNode *Lval = (ASTNode*) ptrVectorGet(&(Node->Child), 0), *Index = (ASTNode*) ptrVectorGet(&(Node->Child), 1); LLVMValueRef Array = translateExpr(TyTable, ValTable, Lval); LLVMValueRef IndVal = translateExpr(TyTable, ValTable, Index); LLVMValueRef Idx[] = { getSConstInt(0), IndVal }; return LLVMBuildInBoundsGEP(Builder, Array, Idx, 2, ""); }
LLVMValueRef gendesc_istrait(compile_t* c, LLVMValueRef desc, ast_t* type) { // Get the trait identifier. reach_type_t* t = reach_type(c->reach, type); assert(t != NULL); LLVMValueRef trait_id = LLVMConstInt(c->i32, t->type_id, false); // Read the count and the trait list from the descriptor. LLVMValueRef count = desc_field(c, desc, DESC_TRAIT_COUNT); LLVMValueRef list = desc_field(c, desc, DESC_TRAITS); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMBuildBr(c->builder, cond_block); // While the index is less than the count, check an ID. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i32, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, count, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get ID and compare it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef gep[2]; gep[0] = LLVMConstInt(c->i32, 0, false); gep[1] = phi; LLVMValueRef id_ptr = LLVMBuildInBoundsGEP(c->builder, list, gep, 2, ""); LLVMValueRef id = LLVMBuildLoad(c->builder, id_ptr, ""); LLVMValueRef test_id = LLVMBuildICmp(c->builder, LLVMIntEQ, id, trait_id, ""); // Add one to the phi node. LLVMValueRef one = LLVMConstInt(c->i32, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); LLVMAddIncoming(phi, &inc, &body_block, 1); // Either to the post block or back to the condition. LLVMBuildCondBr(c->builder, test_id, post_block, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef result = LLVMBuildPhi(c->builder, c->i1, ""); LLVMAddIncoming(result, &test, &cond_block, 1); LLVMAddIncoming(result, &test_id, &body_block, 1); return result; }
LLVMValueRef gendesc_fieldinfo(compile_t* c, LLVMValueRef desc, size_t index) { LLVMValueRef fields = desc_field(c, desc, DESC_FIELDS); LLVMValueRef gep[2]; gep[0] = LLVMConstInt(c->i32, 0, false); gep[1] = LLVMConstInt(c->i32, index, false); LLVMValueRef field_desc = LLVMBuildInBoundsGEP(c->builder, fields, gep, 2, ""); return LLVMBuildLoad(c->builder, field_desc, ""); }
LLVMValueRef gendesc_vtable(compile_t* c, LLVMValueRef object, size_t colour) { LLVMValueRef desc = gendesc_fetch(c, object); LLVMValueRef vtable = LLVMBuildStructGEP(c->builder, desc, DESC_VTABLE, ""); LLVMValueRef gep[2]; gep[0] = LLVMConstInt(c->i32, 0, false); gep[1] = LLVMConstInt(c->i32, colour, false); LLVMValueRef func_ptr = LLVMBuildInBoundsGEP(c->builder, vtable, gep, 2, ""); return LLVMBuildLoad(c->builder, func_ptr, ""); }
static LLVMValueRef translateArrayExpr(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { PtrVector *V = &(Node->Child); ASTNode *SizeNode = (ASTNode*) ptrVectorGet(V, 0), *InitNode = (ASTNode*) ptrVectorGet(V, 1); Type *ThisType = createType(IdTy, Node->Value); LLVMTypeRef ArrayType = getLLVMTypeFromType(TyTable, ThisType); LLVMValueRef SizeVal = translateExpr(TyTable, ValTable, SizeNode), InitVal = translateExpr(TyTable, ValTable, InitNode); LLVMValueRef ArrayVal = LLVMBuildArrayMalloc(Builder, ArrayType, SizeVal, ""); // This BasicBlock and ThisFunction LLVMBasicBlockRef ThisBB = LLVMGetInsertBlock(Builder); LLVMValueRef ThisFn = LLVMGetBasicBlockParent(ThisBB); LLVMValueRef Counter = LLVMBuildAlloca(Builder, LLVMInt32Type(), ""); LLVMBuildStore(Builder, LLVMConstInt(LLVMInt32Type(), 0, 1), Counter); LLVMTargetDataRef DataRef = LLVMCreateTargetData(LLVMGetDataLayout(Module)); unsigned long long Size = LLVMStoreSizeOfType(DataRef, ArrayType); LLVMBasicBlockRef InitBB, MidBB, EndBB; InitBB = LLVMAppendBasicBlock(ThisFn, "for.init"); EndBB = LLVMAppendBasicBlock(ThisFn, "for.end"); MidBB = LLVMAppendBasicBlock(ThisFn, "for.mid"); LLVMBuildBr(Builder, InitBB); LLVMPositionBuilderAtEnd(Builder, InitBB); LLVMValueRef CurrentCounter = LLVMBuildLoad(Builder, Counter, ""); LLVMValueRef Comparation = LLVMBuildICmp(Builder, LLVMIntSLT, CurrentCounter, SizeVal, ""); LLVMBuildCondBr(Builder, Comparation, MidBB, EndBB); LLVMPositionBuilderAtEnd(Builder, MidBB); CurrentCounter = LLVMBuildLoad(Builder, Counter, ""); LLVMValueRef TheValue = LLVMBuildLoad(Builder, InitVal, ""); LLVMValueRef ElemIdx[] = { LLVMConstInt(LLVMInt32Type(), 0, 1), CurrentCounter }; LLVMValueRef Elem = LLVMBuildInBoundsGEP(Builder, ArrayVal, ElemIdx, 2, ""); copyMemory(Elem, TheValue, getSConstInt(Size)); LLVMBuildBr(Builder, InitBB); LLVMPositionBuilderAtEnd(Builder, EndBB); return ArrayVal; }
static void createPopHeapFunction() { // Saving last BasicBlock; LLVMBasicBlockRef OldBB = LLVMGetInsertBlock(Builder); LLVMTypeRef FunctionType = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); LLVMValueRef Function = LLVMAddFunction(Module, "pop.heap", FunctionType); LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); LLVMPositionBuilderAtEnd(Builder, Entry); // Function Body LLVMValueRef HeapHdPtr = LLVMBuildLoad(Builder, HeapHead, ""); LLVMValueRef LastPtrIdx[] = { getSConstInt(0), getSConstInt(1) }; LLVMValueRef LastPtr = LLVMBuildInBoundsGEP(Builder, HeapHdPtr, LastPtrIdx, 2, "heap.last"); LLVMValueRef LastPtrLd = LLVMBuildLoad(Builder, LastPtr, "ld.heap.last"); LLVMBuildStore(Builder, LastPtrLd, HeapHead); LLVMBuildRetVoid(Builder); // Restoring last BasicBlock LLVMPositionBuilderAtEnd(Builder, OldBB); }
static LLVMValueRef translateRecAccessLval(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { ASTNode *Lval = (ASTNode*) ptrVectorGet(&(Node->Child), 0); LLVMValueRef Record = translateExpr(TyTable, ValTable, Lval); LLVMTypeRef RecTypeRef = LLVMGetElementType(LLVMTypeOf(Record)); if (LLVMGetTypeKind(RecTypeRef) == LLVMPointerTypeKind) RecTypeRef = LLVMGetElementType(RecTypeRef); /* Get struct's name. */ const char *AliasName = LLVMGetStructName(RecTypeRef); char TypeName[NAME_MAX]; toRawName(TypeName, AliasName); /* Get struct's field. */ Type *RecType = (Type*) symTableFind(TyTable, TypeName); Hash *Fields = (Hash*) RecType->Val; PtrVector *V = &(Fields->Pairs); /* Get the right struct's field. */ unsigned Count = 0; for (Count = 0; Count < V->Size; ++Count) { Pair *P = (Pair*) ptrVectorGet(V, Count); if (!strcmp(P->first, Node->Value)) break; } LLVMValueRef Idx[] = { getSConstInt(0), getSConstInt(Count) }; LLVMValueRef Field = LLVMBuildInBoundsGEP(Builder, Record, Idx, 2, ""); LLVMTypeRef FieldElType = LLVMGetElementType(LLVMTypeOf(Field)); if (LLVMGetTypeKind(FieldElType) == LLVMPointerTypeKind && LLVMGetTypeKind(LLVMGetElementType(FieldElType)) == LLVMStructTypeKind) Field = LLVMBuildLoad(Builder, Field, "get.struct"); return Field; }
LLVMValueRef getHeadRA() { LLVMValueRef HeadLd = LLVMBuildLoad(Builder, HeapHead, ""); LLVMValueRef RAIdx[] = { getSConstInt(0), getSConstInt(0) }; return LLVMBuildInBoundsGEP(Builder, HeadLd, RAIdx, 2, ""); }
static LLVMValueRef box_is_box(compile_t* c, ast_t* left_type, LLVMValueRef l_value, LLVMValueRef r_value, int possible_boxes) { pony_assert(LLVMGetTypeKind(LLVMTypeOf(l_value)) == LLVMPointerTypeKind); pony_assert(LLVMGetTypeKind(LLVMTypeOf(r_value)) == LLVMPointerTypeKind); LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef checkbox_block = codegen_block(c, "is_checkbox"); LLVMBasicBlockRef box_block = codegen_block(c, "is_box"); LLVMBasicBlockRef num_block = NULL; if((possible_boxes & BOXED_SUBTYPES_NUMERIC) != 0) num_block = codegen_block(c, "is_num"); LLVMBasicBlockRef tuple_block = NULL; if((possible_boxes & BOXED_SUBTYPES_TUPLE) != 0) tuple_block = codegen_block(c, "is_tuple"); LLVMBasicBlockRef post_block = codegen_block(c, "is_post"); LLVMValueRef eq_addr = LLVMBuildICmp(c->builder, LLVMIntEQ, l_value, r_value, ""); LLVMBuildCondBr(c->builder, eq_addr, post_block, checkbox_block); // Check whether we have two boxed objects of the same type. LLVMPositionBuilderAtEnd(c->builder, checkbox_block); LLVMValueRef l_desc = gendesc_fetch(c, l_value); LLVMValueRef r_desc = gendesc_fetch(c, r_value); LLVMValueRef same_type = LLVMBuildICmp(c->builder, LLVMIntEQ, l_desc, r_desc, ""); LLVMValueRef l_typeid = NULL; if((possible_boxes & BOXED_SUBTYPES_UNBOXED) != 0) { l_typeid = gendesc_typeid(c, l_value); LLVMValueRef boxed_mask = LLVMConstInt(c->i32, 1, false); LLVMValueRef left_boxed = LLVMBuildAnd(c->builder, l_typeid, boxed_mask, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); left_boxed = LLVMBuildICmp(c->builder, LLVMIntEQ, left_boxed, zero, ""); LLVMValueRef both_boxed = LLVMBuildAnd(c->builder, same_type, left_boxed, ""); LLVMBuildCondBr(c->builder, both_boxed, box_block, post_block); } else { LLVMBuildCondBr(c->builder, same_type, box_block, post_block); } // Check whether it's a numeric primitive or a tuple. LLVMPositionBuilderAtEnd(c->builder, box_block); if((possible_boxes & BOXED_SUBTYPES_BOXED) == BOXED_SUBTYPES_BOXED) { if(l_typeid == NULL) l_typeid = gendesc_typeid(c, l_value); LLVMValueRef num_mask = LLVMConstInt(c->i32, 2, false); LLVMValueRef boxed_num = LLVMBuildAnd(c->builder, l_typeid, num_mask, ""); LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); boxed_num = LLVMBuildICmp(c->builder, LLVMIntEQ, boxed_num, zero, ""); LLVMBuildCondBr(c->builder, boxed_num, num_block, tuple_block); } else if((possible_boxes & BOXED_SUBTYPES_NUMERIC) != 0) { LLVMBuildBr(c->builder, num_block); } else { pony_assert((possible_boxes & BOXED_SUBTYPES_TUPLE) != 0); LLVMBuildBr(c->builder, tuple_block); } LLVMValueRef args[3]; LLVMValueRef is_num = NULL; if(num_block != NULL) { // Get the machine word size and memcmp without unboxing. LLVMPositionBuilderAtEnd(c->builder, num_block); if(l_typeid == NULL) l_typeid = gendesc_typeid(c, l_value); LLVMValueRef num_sizes = LLVMBuildBitCast(c->builder, c->numeric_sizes, c->void_ptr, ""); args[0] = LLVMBuildZExt(c->builder, l_typeid, c->intptr, ""); LLVMValueRef size = LLVMBuildInBoundsGEP(c->builder, num_sizes, args, 1, ""); size = LLVMBuildBitCast(c->builder, size, LLVMPointerType(c->i32, 0), ""); size = LLVMBuildLoad(c->builder, size, ""); LLVMSetAlignment(size, 4); LLVMValueRef one = LLVMConstInt(c->i32, 1, false); args[0] = LLVMBuildInBoundsGEP(c->builder, l_value, &one, 1, ""); args[0] = LLVMBuildBitCast(c->builder, args[0], c->void_ptr, ""); args[1] = LLVMBuildInBoundsGEP(c->builder, r_value, &one, 1, ""); args[1] = LLVMBuildBitCast(c->builder, args[1], c->void_ptr, ""); args[2] = LLVMBuildZExt(c->builder, size, c->intptr, ""); is_num = gencall_runtime(c, "memcmp", args, 3, ""); is_num = LLVMBuildICmp(c->builder, LLVMIntEQ, is_num, LLVMConstInt(c->i32, 0, false), ""); LLVMBuildBr(c->builder, post_block); } LLVMValueRef is_tuple = NULL; if(tuple_block != NULL) { // Call the type-specific __is function, which will unbox the tuples. LLVMPositionBuilderAtEnd(c->builder, tuple_block); reach_type_t* r_left = reach_type(c->reach, left_type); reach_method_t* is_fn = reach_method(r_left, TK_BOX, stringtab("__is"), NULL); pony_assert(is_fn != NULL); LLVMValueRef func = gendesc_vtable(c, l_value, is_fn->vtable_index); LLVMTypeRef params[2]; params[0] = c->object_ptr; params[1] = c->object_ptr; LLVMTypeRef type = LLVMFunctionType(c->i1, params, 2, false); func = LLVMBuildBitCast(c->builder, func, LLVMPointerType(type, 0), ""); args[0] = l_value; args[1] = r_value; is_tuple = codegen_call(c, func, args, 2); LLVMBuildBr(c->builder, post_block); } LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, ""); LLVMValueRef one = LLVMConstInt(c->i1, 1, false); LLVMValueRef zero = LLVMConstInt(c->i1, 0, false); LLVMAddIncoming(phi, &one, &this_block, 1); if(is_num != NULL) LLVMAddIncoming(phi, &is_num, &num_block, 1); if(is_tuple != NULL) LLVMAddIncoming(phi, &is_tuple, &tuple_block, 1); LLVMAddIncoming(phi, &zero, &checkbox_block, 1); return phi; }
static void serialise(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object, LLVMValueRef offset) { LLVMTypeRef structure = t->structure; int extra = 0; switch(t->underlying) { case TK_PRIMITIVE: { genserialise_typeid(c, t, offset); if(t->primitive != NULL) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef f_size = LLVMConstInt(c->intptr, LLVMOffsetOfElement(c->target_data, structure, 1), false); LLVMValueRef f_offset = LLVMBuildInBoundsGEP(c->builder, offset, &f_size, 1, ""); genserialise_element(c, t, false, ctx, field, f_offset); } return; } case TK_CLASS: { genserialise_typeid(c, t, offset); extra++; break; } case TK_ACTOR: { // Skip the actor pad. genserialise_typeid(c, t, offset); extra += 2; break; } case TK_TUPLETYPE: { // Get the tuple primitive type. if(LLVMTypeOf(object) == t->structure_ptr) { genserialise_typeid(c, t, offset); object = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef size = LLVMConstInt(c->intptr, LLVMOffsetOfElement(c->target_data, structure, 1), false); offset = LLVMBuildInBoundsGEP(c->builder, offset, &size, 1, ""); } structure = t->primitive; break; } default: {} } for(uint32_t i = 0; i < t->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); LLVMValueRef f_size = LLVMConstInt(c->intptr, LLVMOffsetOfElement(c->target_data, structure, i + extra), false); LLVMValueRef f_offset = LLVMBuildInBoundsGEP(c->builder, offset, &f_size, 1, ""); genserialise_element(c, t->fields[i].type, t->fields[i].embed, ctx, field, f_offset); } }