|
|
@@ -68,6 +68,10 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
|
|
|
functions_[id.index] = BuildFunctionDecl(id);
|
|
|
}
|
|
|
|
|
|
+ for (const auto& class_info : sem_ir_->classes().array_ref()) {
|
|
|
+ BuildVtable(class_info);
|
|
|
+ }
|
|
|
+
|
|
|
// Specific functions are lowered when we emit a reference to them.
|
|
|
specific_functions_.resize(sem_ir_->specifics().size());
|
|
|
|
|
|
@@ -703,4 +707,62 @@ auto FileContext::GetLocForDI(SemIR::InstId inst_id) -> LocForDI {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+auto FileContext::BuildVtable(const SemIR::Class& class_info) -> void {
|
|
|
+ // Bail out if this class is not dynamic (this will account for classes that
|
|
|
+ // are declared-and-not-defined (including extern declarations) as well).
|
|
|
+ if (!class_info.is_dynamic) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto first_owning_decl_loc =
|
|
|
+ sem_ir().insts().GetLocId(class_info.first_owning_decl_id);
|
|
|
+ if (first_owning_decl_loc.is_import_ir_inst_id()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ auto canonical_vtable_id =
|
|
|
+ sem_ir().constant_values().GetConstantInstId(class_info.vtable_id);
|
|
|
+ if (canonical_vtable_id == SemIR::ErrorInst::SingletonInstId) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ auto vtable_inst_block =
|
|
|
+ sem_ir().inst_blocks().Get(sem_ir()
|
|
|
+ .insts()
|
|
|
+ .GetAs<SemIR::Vtable>(canonical_vtable_id)
|
|
|
+ .virtual_functions_id);
|
|
|
+
|
|
|
+ auto* entry_type = llvm::IntegerType::getInt32Ty(llvm_context());
|
|
|
+ auto* table_type = llvm::ArrayType::get(entry_type, vtable_inst_block.size());
|
|
|
+
|
|
|
+ Mangler m(*this);
|
|
|
+ std::string mangled_name = m.MangleVTable(class_info);
|
|
|
+
|
|
|
+ auto* llvm_vtable = new llvm::GlobalVariable(
|
|
|
+ llvm_module(), table_type, /*isConstant=*/true,
|
|
|
+ llvm::GlobalValue::ExternalLinkage, nullptr, mangled_name);
|
|
|
+
|
|
|
+ auto* i32_type = llvm::IntegerType::getInt32Ty(llvm_context());
|
|
|
+ auto* i64_type = llvm::IntegerType::getInt64Ty(llvm_context());
|
|
|
+ auto* vtable_const_int =
|
|
|
+ llvm::ConstantExpr::getPtrToInt(llvm_vtable, i64_type);
|
|
|
+
|
|
|
+ llvm::SmallVector<llvm::Constant*> vfuncs;
|
|
|
+ vfuncs.reserve(vtable_inst_block.size());
|
|
|
+
|
|
|
+ for (auto fn_decl_id : vtable_inst_block) {
|
|
|
+ auto fn_decl = GetCalleeFunction(sem_ir(), fn_decl_id);
|
|
|
+ vfuncs.push_back(llvm::ConstantExpr::getTrunc(
|
|
|
+ llvm::ConstantExpr::getSub(
|
|
|
+ llvm::ConstantExpr::getPtrToInt(
|
|
|
+ GetOrCreateFunction(fn_decl.function_id,
|
|
|
+ SemIR::SpecificId::None),
|
|
|
+ i64_type),
|
|
|
+ vtable_const_int),
|
|
|
+ i32_type));
|
|
|
+ }
|
|
|
+
|
|
|
+ llvm_vtable->setInitializer(llvm::ConstantArray::get(table_type, vfuncs));
|
|
|
+ llvm_vtable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
|
|
+}
|
|
|
+
|
|
|
} // namespace Carbon::Lower
|