bool destruct_(Context *ctx, ParseResult *pr, ParseResult *ret_pr, llvm::IRBuilder<> *builder, bool value_is_ptr) { pr->copyTo(ret_pr); if (pr->do_not_destruct) { return true; } if (pr->type->is_array && pr->type->array_size) { return destructArray(ctx, pr, ret_pr, builder, value_is_ptr); } Function *fn = getDestructor(ctx, pr->type); if (!fn) { if (pr->type->struct_name.size()) { destructStruct(ctx, pr, ret_pr, builder, value_is_ptr); } return true; } std::vector<llvm::Value *> call_args; llvm::Value *value_ptr; if (value_is_ptr) { value_ptr = pr->value; } else { value_ptr = llvm::cast<llvm::Value>( builder->CreateAlloca(ctx->toLLVMType(pr->type, NULL, false)) ); builder->CreateStore(pr->value, value_ptr); } call_args.push_back(value_ptr); builder->CreateCall( fn->llvm_function, llvm::ArrayRef<llvm::Value*>(call_args) ); return true; }
/// TODO: add trivial marker for tagtypes bool isTrivial(const TypePtr& type) { auto ttype = type.isa<TagTypePtr>(); if(!ttype) { if (core::lang::isArray(type)) { // in case of an array, check the enclosed type for triviality return isTrivial(core::lang::ArrayType(type).getElementType()); } // non-tag-type & non-array types are always trivial return true; } auto record = ttype->getRecord(); IRBuilder builder(type->getNodeManager()); auto containsCtor = [&](const LambdaExprPtr& ctor)->bool { return any(record->getConstructors(), [&](const ExpressionPtr& cur) { return *builder.normalize(cur) == *builder.normalize(ctor); }); }; auto containsMemberFunction = [&](const MemberFunctionPtr& member)->bool { return any(record->getMemberFunctions(), [&](const MemberFunctionPtr& cur) { return *builder.normalize(cur) == *builder.normalize(member); }); }; auto thisType = builder.refType(builder.tagTypeReference(record->getName())); ParentsPtr parents = (record.isa<StructPtr>()) ? record.as<StructPtr>()->getParents() : builder.parents(); // check for trivial constructors bool trivialDefaultConstructor = containsCtor(builder.getDefaultConstructor(thisType, parents, record->getFields())); if (!trivialDefaultConstructor) return false; bool trivialCopyConstructor = containsCtor(builder.getDefaultCopyConstructor(thisType, parents, record->getFields())); if (!trivialCopyConstructor) return false; bool trivialMoveConstructor = containsCtor(builder.getDefaultMoveConstructor(thisType, parents, record->getFields())); if (!trivialMoveConstructor) return false; // check for trivial copy and move assignments bool trivialCopyAssignment = containsMemberFunction(builder.getDefaultCopyAssignOperator(thisType, parents, record->getFields())); if (!trivialCopyAssignment) return false; bool trivialMoveAssignment = containsMemberFunction(builder.getDefaultMoveAssignOperator(thisType, parents, record->getFields())); if (!trivialMoveAssignment) return false; // check for trivial, non-virtual destructor if(record->getDestructor().as<LambdaExprPtr>()->getBody().size() != 0 || record->getDestructorVirtual().getValue()) return false; // check for virtual member functions for(auto memFun : record->getMemberFunctions()) { if(memFun->getVirtualFlag().getValue()) return false; } if(!record->getPureVirtualMemberFunctions().empty()) return false; // check for virtual & non-trivial base classes if(ttype->isStruct()) { auto stype = ttype->getStruct(); for(auto par : stype->getParents()) { if(par->getVirtual().getValue()) return false; // if our direct base class is non-trivial, we cannot be trivial per-se if(!isTrivial(par->getType())) return false; } } // check that all non-static members are trivial for(auto field : record->getFields()) { auto fieldType = field->getType(); if(!isTrivial(fieldType)) return false; //check cpp_ref field types if(analysis::isRefType(fieldType) && lang::isCppReference(fieldType)) { //TODO this is an over approximation which has to be refined return false; } } return true; }
bool destructArray(Context *ctx, ParseResult *pr, ParseResult *ret_pr, llvm::IRBuilder<> *builder, bool value_is_ptr) { Type *array_type = pr->type->array_type; llvm::BasicBlock *block = pr->block; llvm::Value *array_value = pr->value; if (!array_value) { return true; } if (!array_value->getType()) { return true; } if (!array_type->is_array) { Function *fn = getDestructor(ctx, array_type); if (!fn) { return true; } } llvm::Type *llvm_array_type = ctx->toLLVMType(pr->type, NULL, false); /* Array literals are stored in the variable table as actual * arrays, rather than pointers to arrays. This should be fixed at * some point, but for now, if this value is not a pointer, then * store it in a temporary location. */ if (!pr->value->getType()->isPointerTy()) { array_value = llvm::cast<llvm::Value>( builder->CreateAlloca(llvm_array_type) ); builder->CreateStore(pr->value, array_value); } for (int i = (pr->type->array_size - 1); i >= 0; i--) { ParseResult element; element.type = array_type; element.block = block; std::vector<llvm::Value *> indices; STL::push_back2( &indices, ctx->nt->getLLVMZero(), llvm::cast<llvm::Value>(ctx->nt->getNativeInt(i)) ); llvm::Value *res = builder->Insert( llvm::GetElementPtrInst::Create( array_value, llvm::ArrayRef<llvm::Value*>(indices) ), "ap" ); if (!array_type->is_array) { element.value = builder->CreateLoad(res); } else { element.value = res; } element.do_not_destruct = false; Destruct(ctx, &element, &element, builder); block = element.block; } ret_pr->block = block; return true; }