惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Palo Alto Networks Blog
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
有赞技术团队
有赞技术团队
The GitHub Blog
The GitHub Blog
C
Cisco Blogs
B
Blog
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
Simon Willison's Weblog
Simon Willison's Weblog
T
Tenable Blog
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
WordPress大学
WordPress大学
月光博客
月光博客
Latest news
Latest news
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
I
InfoQ
D
Darknet – Hacking Tools, Hacker News & Cyber Security
W
WeLiveSecurity
Hacker News - Newest:
Hacker News - Newest: "LLM"
酷 壳 – CoolShell
酷 壳 – CoolShell
U
Unit 42
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
Apple Machine Learning Research
Apple Machine Learning Research
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
T
The Exploit Database - CXSecurity.com
I
Intezer
GbyAI
GbyAI
Jina AI
Jina AI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Google Online Security Blog
Google Online Security Blog
Engineering at Meta
Engineering at Meta
D
Docker
Recent Commits to openclaw:main
Recent Commits to openclaw:main
小众软件
小众软件
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
Project Zero
Project Zero

Mox的笔记库

2026PPoPP MLIR Tutorial学习 | Mox的笔记库 MacOS配置《明日方舟:终末地》 | Mox的笔记库 2025:向内生长 | Mox的笔记库 由mlir::ExecutionEngine引发的跨系统问题 | Mox的笔记库 WSL2配置Cuda-Tile环境记录(未完待续) | Mox的笔记库 Vibe Coding手搓项目记录 | Mox的笔记库 给Debian上包——以DuckDB为例 | Mox的笔记库 UCPD.sys事件存档 | Mox的笔记库 换新电脑之Mac mini M4从购买到配置 | Mox的笔记库 Mac配置MLX-C开发环境 | Mox的笔记库 RISC-V meets RDBMS——RISC-V架构上可运行数据库一览 | Mox的笔记库 DuckDB Sort实现调查 | Mox的笔记库 修复Redis在树莓派5上无法运行的问题 | Mox的笔记库 网站网络结构变更记录 | Mox的笔记库 EDBT25论文阅读:PhoebeDB——A Disk-Based RDBMS Kernel for High-Performance and Cost-Effective OLTP SIGMOD25论文阅读:BPF-DB:——A Kernel-Embedded Transactional Database Management System For eBPF Applications Apache Arrow Gandiva项目解析 | Mox的笔记库 VLDB24论文阅读:Cloud-Native Database Systems and Unikernels——Reimagining OS Abstractions for Modern Hardware NoisePage源码分析(未完待续) | Mox的笔记库 VLDB20论文阅读:Mainlining Databases——Supporting Fast Transactional Workloads on Universal Columnar Data File Formats VLDB17论文阅读:Relaxed Operator Fusion for In-Memory Databases:Making Compilation, Vectorization, and Prefetching Work Together At Last 论文阅读:How not to structure your database-backed web applications——a study of performance bugs in the wild SIGMOD24阅读:ROME——Robust Query Optimization via Parallel Multi-Plan Execution 文章阅读:First Past the Post-Evaluating Query Optimization in MongoDB SIGMOD文章阅读:Apache Calcite——A Foundational Framework for Optimized Query Processing Over Heterogeneous Data Sources VLDB23论文阅读:Analyzing the Impact of Cardinality Estimation on Execution Plans in Microsoft SQL Server SIGMOD22论文阅读:Efficient Massively Parallel Join Optimization for Large Queries VLDB论文阅读:Weaving Relations for Cache Performance VLDB22论文阅读:ConnectorX——Accelerating Data Loading From Databases to Dataframes 论文阅读:UniKraft-Fast, Specialized Unikernels the Easy Way 当DuckDB遇上RISC-V | Mox的笔记库 SIGMOD25论文阅读:An Elephant Under The Microscope——Analyzing The Interaction Of Optimizer Components In PostgreSQL 论文阅读:Compile-Time Analysis of Compiler Frameworks for Query Compilation VLDB23阅读:Bringing Compiling Databases to RISC Architectures SIGMOD24文章阅读:Query Compilation Without Regrets | Mox的笔记库 淦!MLIR输出Hello World不应该这么难! | Mox的笔记库 2024:拥挤年代的想象与创造 | Mox的笔记库 如何给自己的博客添加MLIR和LLVM IR语法高亮 | Mox的笔记库 博客重构:从Hexo到Astro | Mox的笔记库 VLDB19-Parsing Gigabytes of JSON per Second论文阅读 CIDR25:Runtime-Extensible Parsers阅读 | Mox的笔记库 SIGMOD24文章阅读:VeriTxn | Mox的笔记库 MLIR学习资料整理 | Mox的笔记库 VLDB23文章阅读——Exploiting Cloud Object Storage for High-Performance Analytics VLDB24——OLAP on Modern Chiplet-Based Processors走马观花阅读 如何让数据库中的Python跑的更快-VLDB22-YeSQL文章阅读 | Mox的笔记库 你好,世界! | Mox的笔记库 如何愉快的运行一个MLIR程序 | Mox的笔记库 让系统研究更有意义:HarmonyOS NEXT的教训和经验——讲座回顾 | Mox的笔记库 VLDB22:YeSQL文章阅读(已废弃) | Mox的笔记库 UNSW 24T3 COMP9336上课记录 | Mox的笔记库 Velox开发环境配置踩坑记录 | Mox的笔记库 LingoDB源码编译与分析 | Mox的笔记库 论文阅读:Declarative Sub-Operators for Universal Data Processing 论文阅读:Designing an Open Framework for Query Optimization and Compilation MLIR Toy Tutorial实践记录 | Mox的笔记库 2024年7月RSSHub开发体验 | Mox的笔记库 LLVM-Kaleidoscope实操踩坑记录 | Mox的笔记库 澳洲大学计算机硕士比较 | Mox的笔记库 论文阅读——CDUL:CLIP-Driven Unsupervised Learning for Multi-Label Image Classification CVPR2023-CLIP算法调研 | Mox的笔记库 论批量快速添加图片与视频水印的事 | Mox的笔记库 基于元信息写入的服务器压力测试 | Mox的笔记库 家庭组网IPv6+Mesh折腾 | Mox的笔记库 MjAyMw==,希望,前进与平庸之道 | Mox的笔记库 code-server初体验 | Mox的笔记库 从Nginx到Caddy | Mox的笔记库 RMM观察与初探 | Mox的笔记库 计算机网络课设——UDP/TCP/TLS Socket实验 | Mox的笔记库 JQuery的XSS初探 | Mox的笔记库 生产实习记录 | Mox的笔记库 Fedora-CoreOS配置与试用(2023年) | Mox的笔记库 Electron学习笔记 | Mox的笔记库 ServerSentEvent学习 | Mox的笔记库 报告翻译:容器云的安全挑战 | Mox的笔记库 Vagrant配置Metarget靶场环境 | Mox的笔记库 OpenAI-whisper折腾 | Mox的笔记库 202202,困惑,混乱与未曾设想之路 | Mox的笔记库 2022年Hack the box:Tier1免费区全解 | Mox的笔记库 Navidrome部署记录 | Mox的笔记库 长安杯2021-snake复现 | Mox的笔记库 报告概要翻译:OBFUSCATING C++ PROGRAMS VIA CONTROL FLOW FLATTENING 从零开始的Django CVE-2022-28346复现 | Mox的笔记库 2022CISCN(西北区赛)-The shinning | Mox的笔记库 Docker+QEMU+Arm64(Ubuntu)+环境配置(2022版) | Mox的笔记库 Arch Linux运行树莓派系统(2022年) | Mox的笔记库 2022CISCN初赛-ez_usb-复盘WriteUp | Mox的笔记库 Arch Linux迁移计划 | Mox的笔记库 Django事务使用 | Mox的笔记库 记录第一次EduSRC上报 | Mox的笔记库 Jetbrain问题应急处理 | Mox的笔记库 Celery5.2学习&配置 | Mox的笔记库 Waline部署记录 | Mox的笔记库 Frida hook初次实战 | Mox的笔记库 NodeMCU-MicroPython配置实录 | Mox的笔记库 Log4j2漏洞复现 | Mox的笔记库 2022长安“战疫”网络安全卫士守护赛回顾 | Mox的笔记库 2021年12月 Vivo千镜杯回顾 | Mox的笔记库 Windows的WSL2+Docker初探 | Mox的笔记库 Hexo部署安装全流程回顾 | Mox的笔记库
如何在MLIR中自定义类型并且输出运行 | Mox的笔记库
MocusEZ · 2025-07-25 · via Mox的笔记库

本文是淦!MLIR输出Hello World不应该这么难的续集,同时也是对MLIR官方Toy Tutorial的Chapter #7中一些困惑的自我解答尝试

本文的实现代码已放入Github仓库:

https://github.com/mocusez/mlir-hello-world

根据Github CI的脚本可了解运行流程

对于Toy Tutroial的困惑

文章中在Toy Dialect中定义一个composite type,名称为struct

# A struct is defined by using the `struct` keyword followed by a name.

struct MyStruct {

# Inside of the struct is a list of variable declarations without initializers

# or shapes, which may also be other previously defined structs.

var a;

var b;

}

文章只是告诉我们了定义一个Type的流程:

  1. 定义Type
  2. 定义TypeStorage
  3. 定义ODS,即TableGen
  4. 定义Type的解析和打印
  5. 定义Type的相关操作

但是很多细节语焉不详:

  1. 我们该如何处理Type和TypeStorage的下降(lowering)?
  2. 我明明已经用了MLIR,为什么需要处理Type的解析和打印?(以及这个解析和打印,是针对Toy这门语言,还是MLIR的Dialect)

第二个问题其实极具迷惑性,但实际答案是:用于MLIR文本源代码的解析,在这点上与Toy语言的解析大不相同

基于这两点,我们开启今天文章的内容:实现一个简易的HashTable,并且能打印(Print)看到结果

实现方案概述

在Hello Dialect中定义Dict这个Type,以及Type的操作方法(Put,Get,Delete),转化为LLVM IR进行执行实现

添加自定义类型Type

首先,在Dialect的TableGen里面声明类型

def DictType :

DialectType<Hello_Dialect, CPred<"::llvm::isa<DictType>($_self)">,

"Hello dict type">;

如果不确定这里面的CPred怎么写,那么参照这个进行修改即可

dialect.h中定义Type的C++方法,用于在转化中生成和访问Dialect,同时声明使用的TypeStorage

namespace hello {

struct DictTypeStorage;

}

class DictType : public mlir::Type::TypeBase<DictType, mlir::Type,

hello::DictTypeStorage> {

public:

/// Inherit some necessary constructors from 'TypeBase'.

using Base::Base;

/// Create an instance of a `DictType` with the given key and value types.

static DictType get(mlir::Type keyType, mlir::Type valueType);

/// Returns the key type of this dict type.

mlir::Type getKeyType();

/// Returns the value type of this dict type.

mlir::Type getValueType();

/// The name of this dict type.

static constexpr mlir::StringLiteral name = "hello.dict";

};

dialect.cpp中完成Type的方法补齐,下文中的getImpl()是指从TypeStorage访问相关MLIR Type

DictType DictType::get(mlir::Type keyType, mlir::Type valueType) {

return Base::get(keyType.getContext(), keyType, valueType);

}

mlir::Type DictType::getKeyType() {

return getImpl()->keyType;

}

/// Returns the value type of this dict type.

mlir::Type DictType::getValueType() {

return getImpl()->valueType;

}

以及在Dialect中的initialize()方法中添加对应的Type

void HelloDialect::initialize() {

addOperations<

#define GET_OP_LIST

#include "Hello/HelloOps.cpp.inc"

>();

addTypes<DictType>();

}

添加自定义的TypeStorage

MLIR存在Type和TypeStorage结构,关于TypeStorage,可以理解为Type当中数据和元数据的实际存储

由于在Dialect.h中已经声明了DictTypeStorage,那么在Dialect.cpp中直接继承mlir::TypeStorage实现就行

operator==确定了Type之间的比较关系

hashKey确定操作的Type是否为同一个

实现*construct方法,使用allocator告诉Dialect需要申请的空间(这一步操作并不会在lowering中体现)

struct DictTypeStorage : public mlir::TypeStorage {

/// The `KeyTy` defines what uniquely identifies this type.

/// For dict type, we unique on the key type and value type pair.

using KeyTy = std::pair<mlir::Type, mlir::Type>;

/// Constructor for the type storage instance.

DictTypeStorage(mlir::Type keyType, mlir::Type valueType)

: keyType(keyType), valueType(valueType) {}

/// Define the comparison function for the key type.

bool operator==(const KeyTy &key) const {

return key.first == keyType && key.second == valueType;

}

/// Define a hash function for the key type.

static llvm::hash_code hashKey(const KeyTy &key) {

return llvm::hash_combine(key.first, key.second);

}

/// Define a construction function for the key type.

static KeyTy getKey(mlir::Type keyType, mlir::Type valueType) {

return KeyTy(keyType, valueType);

}

/// Define a construction method for creating a new instance of this storage.

static DictTypeStorage *construct(mlir::TypeStorageAllocator &allocator,

const KeyTy &key) {

// Allocate the storage instance and construct it.

return new (allocator.allocate<DictTypeStorage>())

DictTypeStorage(key.first, key.second);

}

/// The key and value types of the dict.

mlir::Type keyType;

mlir::Type valueType;

};

Type类型转化

Hello Dialect中的Dict Type需要转化为一个指针,相关的操作实际发生与Operation的下降lowering,通过下降Op的入参和返回值实现

一个方案是创建一个继承LLVMTypeConverter的方法,添加addConversion——这个方案理论可行,但我没试过

class HelloTypeConverter : public mlir::LLVMTypeConverter {

public:

HelloTypeConverter(mlir::MLIRContext *ctx) : mlir::LLVMTypeConverter(ctx) {

addConversion([](hello::DictType type) {

return mlir::LLVM::LLVMPointerType::get(type.getContext());

});

}

};

另外一个方案是直接在typeconverter上加上addConversion

这里还分出两种写法可供大家参考(这两种方法测试均通过):

  1. 直接点名转换的Type的类型

typeConverter.addConversion([](DictType type) -> mlir::Type {

return mlir::LLVM::LLVMPointerType::get(type.getContext());

});

  1. 根据mlir::dyn_cast判断后确定返回

typeConverter.addConversion([](mlir::Type type) -> std::optional<mlir::Type> {

if (auto dictType = mlir::dyn_cast<DictType>(type))

return mlir::LLVM::LLVMPointerType::get(type.getContext());

return std::nullopt;

});

按照构造函数传入typeconverter后,就可以使用getTypeConverter根据类型决定传回什么参数

auto resultType = getTypeConverter()->convertType(op->getResult(0).getType());

if (!resultType) {

return mlir::failure();

}

所以这段代码就等价于

auto resultType = mlir::LLVM::LLVMPointerType::get(context);

这部分代码相等于就是生成不可变代码——resultType不会因为Operation传入的参数的不同而发生变化

Type类型操作方法转化

对于Dict(哈希表)而言,有putgetdelete这些操作,以及用于释放内存的createfree,这些都需要在Dialect中定义对应Op(Operation)才能实现

下面代码当中,定义AssemblyFormat确保能从文本的mlir文件中能正确解析类型

class Hello_Op<string mnemonic, list<Trait> traits = []> :

Op<Hello_Dialect, mnemonic, traits>;

def Dict_CreateOp : Hello_Op<"dict.create", [Pure]> {

let summary = "Create a new dict<string,i32>";

let results = (outs DictType:$dict);

let assemblyFormat = "attr-dict `:` type($dict)";

}

def Dict_FreeOp : Hello_Op<"dict.free", []> {

let summary = "Free the dict<string,i32> memory";

let arguments = (ins DictType:$dict);

let assemblyFormat = "$dict attr-dict `:` type($dict)";

}

def Dict_PutOp : Hello_Op<"dict.put", []> {

let summary = "Insert string->i32";

let arguments = (ins DictType:$dict, StrAttr:$key, I32Attr:$value);

let results = (outs DictType:$out);

let assemblyFormat = "$dict `,` $key `=` $value attr-dict `:` type($dict) `->` type($out)";

}

def Dict_GetOp : Hello_Op<"dict.get", []> {

let summary = "Lookup string->i32, returns i32";

let arguments = (ins DictType:$dict, StrAttr:$key);

let results = (outs I32:$value);

let assemblyFormat = "$dict `,` $key attr-dict `:` type($dict) `->` type($value)";

}

def Dict_DeleteOp : Hello_Op<"dict.delete", []> {

let summary = "Delete key string";

let arguments = (ins DictType:$dict, StrAttr:$key);

let results = (outs DictType:$out);

let assemblyFormat = "$dict `,` $key attr-dict `:` type($dict) `->` type($out)";

}

同时也需要写明各个Op的lowering,这里以Dict_CreateOp的实现为例

class DictCreateOpLowering : public mlir::ConversionPattern {

public:

explicit DictCreateOpLowering(mlir::TypeConverter &typeConverter,

mlir::MLIRContext *context)

: mlir::ConversionPattern(

typeConverter, hello::CreateOp::getOperationName(), 1, context) {}

mlir::LogicalResult

matchAndRewrite(mlir::Operation *op, mlir::ArrayRef<mlir::Value> operands,

mlir::ConversionPatternRewriter &rewriter) const override {

auto loc = op->getLoc();

auto resultType =

getTypeConverter()->convertType(op->getResult(0).getType());

if (!resultType) {

return mlir::failure();

}

mlir::ModuleOp module = op->getParentOfType<mlir::ModuleOp>();

auto createMapRef = getOrInsertCreateMap(rewriter, module);

auto callOp = rewriter.create<mlir::LLVM::CallOp>(

loc, resultType, createMapRef, mlir::ValueRange{});

rewriter.replaceOp(op, callOp.getResult());

return mlir::success();

}

private:

mlir::FlatSymbolRefAttr getOrInsertCreateMap(mlir::PatternRewriter &rewriter,

mlir::ModuleOp module) const {

auto *context = module.getContext();

if (module.lookupSymbol<mlir::LLVM::LLVMFuncOp>("create_map"))

return mlir::SymbolRefAttr::get(context, "create_map");

// Create function type: () -> !llvm.ptr

auto resultType = mlir::LLVM::LLVMPointerType::get(context);

auto fnType =

mlir::LLVM::LLVMFunctionType::get(resultType, std::nullopt, false);

// Insert function declaration

mlir::PatternRewriter::InsertionGuard insertGuard(rewriter);

rewriter.setInsertionPointToStart(module.getBody());

rewriter.create<mlir::LLVM::LLVMFuncOp>(module.getLoc(), "create_map",

fnType);

return mlir::SymbolRefAttr::get(context, "create_map");

}

};

这个Op在做的事情就是:Dict_CreateOp转化为对于create_map这个C/LLVM IR函数的调用,只要能实现,就能用C的printf()完成输出。

这是非常重要的一部分,需要在声明对于自定义Type的解析范式,即printTypeparseType

为了做这一步,需要将Dialect的useDefaultTypePrinterParser设为1

def Hello_Dialect : Dialect {

let name = "hello";

let summary = "A hello out-of-tree MLIR dialect.";

let description = [{

This dialect is minimal example to implement hello-world kind of sample code

for MLIR.

}];

let cppNamespace = "::hello";

let useDefaultTypePrinterParser = 1;

}

在对应的dialect.cpp中定义printTypeparseType

mlir::Type DictType::getValueType() {

return getImpl()->valueType;

}

mlir::Type HelloDialect::parseType(mlir::DialectAsmParser &parser) const {

llvm::StringRef typeTag;

if (parser.parseKeyword(&typeTag))

return mlir::Type();

if (typeTag == "dict") {

if (parser.parseLess())

return mlir::Type();

mlir::Type keyType;

if (parser.parseType(keyType))

return mlir::Type();

if (parser.parseComma())

return mlir::Type();

mlir::Type valueType;

if (parser.parseType(valueType))

return mlir::Type();

if (parser.parseGreater())

return mlir::Type();

return DictType::get(keyType, valueType);

}

parser.emitError(parser.getNameLoc(), "unknown hello type: ") << typeTag;

return mlir::Type();

}

void HelloDialect::printType(mlir::Type type, mlir::DialectAsmPrinter &printer) const {

if (auto dictType = mlir::dyn_cast<DictType>(type)) {

printer << "dict<";

printer.printType(dictType.getKeyType());

printer << ", ";

printer.printType(dictType.getValueType());

printer << ">";

return;

}

llvm_unreachable("unhandled hello type");

}

运行!

准备一份MLIR代码

module {

func.func @test_dict_operations() -> i32 {

%dict0 = hello.dict.create : !hello.dict<index, i32>

%dict1 = hello.dict.put %dict0, "first1" = 100 : !hello.dict<index, i32> -> !hello.dict<index, i32>

%dict2 = hello.dict.put %dict1, "second" = 200 : !hello.dict<index, i32> -> !hello.dict<index, i32>

%dict3 = hello.dict.put %dict2, "third" = 300 : !hello.dict<index, i32> -> !hello.dict<index, i32>

%val1 = hello.dict.get %dict3, "first1" : !hello.dict<index, i32> -> i32

%val2 = hello.dict.get %dict3, "second" : !hello.dict<index, i32> -> i32

%val3 = hello.dict.get %dict3, "third" : !hello.dict<index, i32> -> i32

%dict4 = hello.dict.delete %dict3, "second" : !hello.dict<index, i32> -> !hello.dict<index, i32>

hello.dict.free %dict4 : !hello.dict<index, i32>

func.return %val2 : i32

}

}

将MLIR下降到LLVM IR,我们看一看看打印出来的LLVM IR的样子

; ModuleID = 'LLVMDialectModule'

source_filename = "LLVMDialectModule"

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"

target triple = "x86_64-pc-linux-gnu"

@key_third = internal constant [6 x i8] c"third\00"

@key_second = internal constant [7 x i8] c"second\00"

@key_first1 = internal constant [7 x i8] c"first1\00"

declare void @free_map(ptr) local_unnamed_addr

declare void @delete(ptr, ptr) local_unnamed_addr

declare ptr @get(ptr, ptr) local_unnamed_addr

declare void @put(ptr, ptr, i32) local_unnamed_addr

declare ptr @create_map() local_unnamed_addr

define i32 @test_dict_operations() local_unnamed_addr {

%1 = tail call ptr @create_map()

tail call void @put(ptr %1, ptr nonnull @key_first1, i32 100)

tail call void @put(ptr %1, ptr nonnull @key_second, i32 200)

tail call void @put(ptr %1, ptr nonnull @key_third, i32 300)

%2 = tail call ptr @get(ptr %1, ptr nonnull @key_first1)

%3 = tail call ptr @get(ptr %1, ptr nonnull @key_second)

%4 = load i32, ptr %3, align 4

%5 = tail call ptr @get(ptr %1, ptr nonnull @key_third)

tail call void @delete(ptr %1, ptr nonnull @key_second)

tail call void @free_map(ptr %1)

ret i32 %4

}

!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}

大部分转化为了C/LLVM IR的函数调用,这样就变成了我们所熟悉的问题,和前文的printf()行为一样

在C/C++的实现相关接口函数,编译并调用运行

../../build/bin/hello-opt dict.mlir -emit=llvm > dict.ll

clang-20 dict.c dict.ll -o dict

extern int test_dict_operations();

int main() {

printf("Starting dictionary test...\n");

int result = test_dict_operations();

printf("Result from test_dict_operations: %d\n", result);

return 0;

}

预期结果为

Starting dictionary test...

Result from test_dict_operations: 200

image-20250724222358886

思考内容

可以看到这种实现方式的局限性:只能适配于<string,i32>结构的哈希表,不能适用于其他类型。这个问题可以通过动态生成LLVM IR解决,具体操作就是另外一个问题了😂

还是建议要自己上手尝试才加深理解


avatar

探索未曾设想的道路