LLVM:如何在运行时跟踪非类型语言的 Value* 的数据类型?
LLVM: How to keep track of data types of the Value* at runtime for untyped language?
我正在使用LLVM实现一种非类型编程语言来生成后端代码。为了跟踪特定变量的当前类型,我使用了一个结构StructTy_struct_datatype_t
定义为:
PointerTy_8 = PointerType::get(IntegerType::get(TheContext, 8), 0);
StructTy_struct_datatype_t = StructType::create(TheContext, "struct.datatype_t");
std::vector<Type *> StructTy_struct_datatype_t_fields;
StructTy_struct_datatype_t_fields.push_back(IntegerType::get(TheContext, 32));
StructTy_struct_datatype_t_fields.push_back(PointerTy_8);
// which represents the struct
typedef struct datatype_t {
int type; // holds an integer that tells me the type (1 = int, 2 = float, ...)
void* v; // holds a pointer to the actual value
} datatype_t;
然后,假设我有一个这样的函数
def function_add(a, b) {
return a + b;
}
我希望这个函数能够接受
function_add(1, 1); // returns 2; (int)
function_add(1.0, 1.0); // returns 2.0 (float)
function_add("str1", "str2"); // returns "str1str2" (string)
处理二进制操作的代码,即。a + b
如下
Value* L = lhs_codegen_elements.back();
Value* R = rhs_codegen_elements.back();
if (!L || !R) {
logError("L or R are undefined");
return codegen;
}
AllocaInst* lptr_datatype = (AllocaInst*)((LoadInst*)L)->getPointerOperand();
AllocaInst* rptr_datatype = (AllocaInst*)((LoadInst*)R)->getPointerOperand();
ConstantInt* const_int32_0 = ConstantInt::get(TheContext, APInt(32, StringRef("0"), 10));
ConstantInt* const_int32_1 = ConstantInt::get(TheContext, APInt(32, StringRef("1"), 10));
GetElementPtrInst* lptr_type =
GetElementPtrInst::Create(StructTy_struct_datatype_t, lptr_datatype, {const_int32_0, const_int32_0}, "type");
GetElementPtrInst* rptr_type =
GetElementPtrInst::Create(StructTy_struct_datatype_t, rptr_datatype, {const_int32_0, const_int32_0}, "type");
GetElementPtrInst* lptr_v =
GetElementPtrInst::Create(StructTy_struct_datatype_t, lptr_datatype, {const_int32_0, const_int32_1}, "v");
GetElementPtrInst* rptr_v =
GetElementPtrInst::Create(StructTy_struct_datatype_t, rptr_datatype, {const_int32_0, const_int32_1}, "v");
LoadInst* lload_inst_type = load_inst_codegen(TYPE_INT, lptr_type);
LoadInst* rload_inst_type = load_inst_codegen(TYPE_INT, rptr_type);
LoadInst* lload_inst_v = load_inst_codegen(TYPE_VOID_POINTER, lptr_v);
LoadInst* rload_inst_v = load_inst_codegen(TYPE_VOID_POINTER, rptr_v);
CmpInst* cond1 =
new ICmpInst(ICmpInst::ICMP_EQ, lload_inst_type, ConstantInt::get(TheContext, APInt(32, TYPE_DOUBLE)));
Function* function_bb = dyn_cast<Function>(bb);
BasicBlock* label_if_then_double = BasicBlock::Create(TheContext, "if.then.double", function_bb);
BasicBlock* label_if_then_long = BasicBlock::Create(TheContext, "if.then.long", function_bb);
BranchInst* branch_inst = BranchInst::Create(label_if_then_double, label_if_else, cond1, bb);
L->dump(); // %load_inst = load %struct.datatype_t, %struct.datatype_t* %alloca_datatype_v, align 8
R->dump(); // %load_inst = load %struct.datatype_t, %struct.datatype_t* %alloca_datatype_v1, align 8
L->getType()->dump(); // %struct.datatype_t = type { i32, i8* }
R->getType()->dump(); // %struct.datatype_t = type { i32, i8* }
lload_inst_type->dump(); // %load_inst = load i32, i32* %type, align 4
rload_inst_type->dump(); // %load_inst = load i32, i32* %type, align 4
lload_inst_v->dump(); // %load_inst = load i8*, i8** %v, align 8
rload_inst_v->dump(); // %load_inst = load i8*, i8** %v, align 8
if (op == '+') {
// issue: how to take the decision without knowing the type lload_inst_v holds
BinaryOperator::Create(Instruction::FAdd, lload_inst_v, rload_inst_v, "add", label_if_then_double);
// or
BinaryOperator::Create(Instruction::Add, lload_inst_v, rload_inst_v, "add", label_if_then_long);
}
所以问题是我需要知道哪个是lload_inst_type
和rload_inst_type
持有的类型,以便我可以将方法从 LLVM APIBinaryOperator::Create(Instruction::FAdd, ...)
切换为floats
,BinaryOperator::Create(Instruction::Add, ...)
用于ints
,例如。
但是,我刚刚意识到我无法弄清楚AllocaInst
的价值,LoadInst
生成后端时(至少我不知道该怎么做)。
- 如何在运行时跟踪
Value*
的数据类型? - 我是否选择了错误的策略来实现非类型语言?
如果您的源语言类型系统是非类型化的,则必须对 LLVM 隐藏,因为它是 IR 类型的。您必须设计一种方法来在运行时跟踪类型,也许是某种枚举的标记对象系统。函数调用必须检查在运行时传入的类型,并选择要调用的相应函数。
LLVM不提供任何此功能,这必须由语言运行时的类型系统负责。
相关文章:
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 瓦尔格林德:数学函数"Conditional jump or move depends on uninitialised value(s)"
- 错误处理.将系统错误代码映射到泛型
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 不同语言中相同代码的不同行为
- 链表的泛型函数remove()与成员函数remove)
- 为什么static_assert错误:即使我传递常量"expression must have a constant value"?
- 为什么C++对链表中的下一个节点使用指针,而像 C# 或 Java 这样的语言只使用类 Node 的名称?
- r语言 - C++ 类型为"const std ::?
- 如何为 C 型字符串数组编写 getter 和 setter?
- 通用C++/Python 多语言的存在
- C 字符串返回字符串的整数/双精度/长整型值
- 是什么导致了这种使用三进制而不是短整型的有符号int到无符号int转换
- 为什么我会" void value not ignored as it ought to be"?
- 为什么我的 EnumWindowProc 不能用 C 语言编译?
- 无法在 Arduino 中uint8_t数组转换为无符号长整型数组
- 给定一个类型,如何派生一个泛型更广泛的类型(例如,用于溢出安全求和)?
- 了解算法的性能差异(如果以不同的编程语言实现)
- LLVM:如何在运行时跟踪非类型语言的 Value* 的数据类型?
- 用C语言打印时,如何圆型浮点变量