[backend]引入浮点数支持,但目前寄存器分配存在问题
This commit is contained in:
@@ -10,7 +10,23 @@ namespace sysy {
|
||||
|
||||
// DAG节点定义 (内部实现)
|
||||
struct RISCv64ISel::DAGNode {
|
||||
enum NodeKind {ARGUMENT, CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY, MEMSET, GET_ELEMENT_PTR};
|
||||
enum NodeKind {
|
||||
ARGUMENT,
|
||||
CONSTANT, // 整数或地址常量
|
||||
LOAD,
|
||||
STORE,
|
||||
BINARY, // 整数二元运算
|
||||
CALL,
|
||||
RETURN,
|
||||
BRANCH,
|
||||
ALLOCA_ADDR,
|
||||
UNARY, // 整数一元运算
|
||||
MEMSET,
|
||||
GET_ELEMENT_PTR,
|
||||
FP_CONSTANT, // 浮点常量
|
||||
FBINARY, // 浮点二元运算 (如 FADD, FSUB, FCMP)
|
||||
FUNARY, // 浮点一元运算 (如 FCVT, FNEG)
|
||||
};
|
||||
NodeKind kind;
|
||||
Value* value = nullptr;
|
||||
std::vector<DAGNode*> operands;
|
||||
@@ -29,7 +45,9 @@ unsigned RISCv64ISel::getVReg(Value* val) {
|
||||
if (vreg_counter == 0) {
|
||||
vreg_counter = 1; // vreg 0 保留
|
||||
}
|
||||
vreg_map[val] = vreg_counter++;
|
||||
unsigned new_vreg = vreg_counter++;
|
||||
vreg_map[val] = new_vreg;
|
||||
vreg_to_value_map[new_vreg] = val;
|
||||
}
|
||||
return vreg_map.at(val);
|
||||
}
|
||||
@@ -161,18 +179,52 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
}
|
||||
break;
|
||||
|
||||
case DAGNode::FP_CONSTANT: {
|
||||
// RISC-V没有直接加载浮点立即数的指令
|
||||
// 标准做法是:1. 将浮点数的32位二进制表示加载到一个整数寄存器
|
||||
// 2. 使用 fmv.w.x 指令将位模式从整数寄存器移动到浮点寄存器
|
||||
auto const_val = dynamic_cast<ConstantValue*>(node->value);
|
||||
auto float_vreg = getVReg(const_val);
|
||||
auto temp_int_vreg = getNewVReg(); // 临时整数虚拟寄存器
|
||||
|
||||
float f_val = const_val->getFloat();
|
||||
// 使用 reinterpret_cast 获取浮点数的32位二进制表示
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
|
||||
// 1. li temp_int_vreg, float_bits
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
|
||||
// 2. fmv.w.x float_vreg, temp_int_vreg
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::LOAD: {
|
||||
auto dest_vreg = getVReg(node->value);
|
||||
Value* ptr_val = node->operands[0]->value;
|
||||
|
||||
// --- 修改点 ---
|
||||
// 1. 获取加载结果的类型 (即这个LOAD指令自身的类型)
|
||||
Type* loaded_type = node->value->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode = loaded_type->isPointer() ? RVOpcodes::FRAME_LOAD_D : RVOpcodes::FRAME_LOAD_W;
|
||||
RVOpcodes real_opcode = loaded_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
||||
|
||||
RVOpcodes frame_opcode;
|
||||
RVOpcodes real_opcode;
|
||||
if (loaded_type->isPointer()) {
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_D;
|
||||
real_opcode = RVOpcodes::LD;
|
||||
} else if (loaded_type->isFloat()) {
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_F;
|
||||
real_opcode = RVOpcodes::FLW;
|
||||
} else { // 默认为整数
|
||||
frame_opcode = RVOpcodes::FRAME_LOAD_W;
|
||||
real_opcode = RVOpcodes::LW;
|
||||
}
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
@@ -220,20 +272,51 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
|
||||
// 如果要存储的值是一个常量,就在这里生成 `li` 指令加载它
|
||||
if (auto val_const = dynamic_cast<ConstantValue*>(val_to_store)) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
// 区分整数常量和浮点常量
|
||||
if (val_const->isInt()) {
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(getVReg(val_const)));
|
||||
li->addOperand(std::make_unique<ImmOperand>(val_const->getInt()));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
} else if (val_const->isFloat()) {
|
||||
// 先将浮点数的位模式加载到整数vreg,再用fmv.w.x移到浮点vreg
|
||||
auto temp_int_vreg = getNewVReg();
|
||||
auto float_vreg = getVReg(val_const);
|
||||
|
||||
float f_val = val_const->getFloat();
|
||||
uint32_t float_bits = *reinterpret_cast<uint32_t*>(&f_val);
|
||||
|
||||
// 1. li temp_int_vreg, float_bits
|
||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||
li->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
li->addOperand(std::make_unique<ImmOperand>(float_bits));
|
||||
CurMBB->addInstruction(std::move(li));
|
||||
|
||||
// 2. fmv.w.x float_vreg, temp_int_vreg
|
||||
auto fmv = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
fmv->addOperand(std::make_unique<RegOperand>(float_vreg));
|
||||
fmv->addOperand(std::make_unique<RegOperand>(temp_int_vreg));
|
||||
CurMBB->addInstruction(std::move(fmv));
|
||||
}
|
||||
}
|
||||
auto val_vreg = getVReg(val_to_store);
|
||||
|
||||
// --- 修改点 ---
|
||||
// 1. 获取被存储的值的类型
|
||||
Type* stored_type = val_to_store->getType();
|
||||
|
||||
// 2. 根据类型选择正确的伪指令或真实指令操作码
|
||||
RVOpcodes frame_opcode = stored_type->isPointer() ? RVOpcodes::FRAME_STORE_D : RVOpcodes::FRAME_STORE_W;
|
||||
RVOpcodes real_opcode = stored_type->isPointer() ? RVOpcodes::SD : RVOpcodes::SW;
|
||||
RVOpcodes frame_opcode;
|
||||
RVOpcodes real_opcode;
|
||||
if (stored_type->isPointer()) {
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_D;
|
||||
real_opcode = RVOpcodes::SD;
|
||||
} else if (stored_type->isFloat()) {
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_F;
|
||||
real_opcode = RVOpcodes::FSW;
|
||||
} else { // 默认为整数
|
||||
frame_opcode = RVOpcodes::FRAME_STORE_W;
|
||||
real_opcode = RVOpcodes::SW;
|
||||
}
|
||||
|
||||
if (auto alloca = dynamic_cast<AllocaInst*>(ptr_val)) {
|
||||
// 3. 创建使用新的、区分宽度的伪指令
|
||||
@@ -497,6 +580,109 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::FBINARY: {
|
||||
auto bin = dynamic_cast<BinaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(bin);
|
||||
auto lhs_vreg = getVReg(bin->getLhs());
|
||||
auto rhs_vreg = getVReg(bin->getRhs());
|
||||
|
||||
switch (bin->getKind()) {
|
||||
case Instruction::kFAdd: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FADD_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFSub: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FSUB_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFMul: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMUL_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFDiv: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FDIV_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
|
||||
// --- 浮点比较指令 ---
|
||||
// 注意:比较结果(0或1)写入的是一个通用整数寄存器(dest_vreg)
|
||||
case Instruction::kFCmpEQ: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFCmpLT: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFCmpLE: {
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
// --- 通过交换操作数或组合指令实现其余比较 ---
|
||||
case Instruction::kFCmpGT: { // a > b 等价于 b < a
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLT_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg)); // 操作数交换
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFCmpGE: { // a >= b 等价于 b <= a
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FLE_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(rhs_vreg)); // 操作数交换
|
||||
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFCmpNE: { // a != b 等价于 !(a == b)
|
||||
// 1. 先用 feq.s 比较,结果存入 dest_vreg
|
||||
auto feq = std::make_unique<MachineInstr>(RVOpcodes::FEQ_S);
|
||||
feq->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
feq->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||
feq->addOperand(std::make_unique<RegOperand>(rhs_vreg));
|
||||
CurMBB->addInstruction(std::move(feq));
|
||||
// 2. 再用 seqz 对结果取反 (如果相等(1),则变0;如果不等(0),则变1)
|
||||
auto seqz = std::make_unique<MachineInstr>(RVOpcodes::SEQZ);
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
seqz->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
CurMBB->addInstruction(std::move(seqz));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported float binary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::UNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
@@ -524,6 +710,54 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::FUNARY: {
|
||||
auto unary = dynamic_cast<UnaryInst*>(node->value);
|
||||
auto dest_vreg = getVReg(unary);
|
||||
auto src_vreg = getVReg(unary->getOperand());
|
||||
|
||||
switch (unary->getKind()) {
|
||||
case Instruction::kItoF: { // 整数 to 浮点
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_S_W);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFtoI: { // 浮点 to 整数
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FCVT_W_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kFNeg: { // 浮点取负
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FNEG_S);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
// --- 处理位传送指令 ---
|
||||
case Instruction::kBitItoF: { // 整数位模式 -> 浮点寄存器
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_W_X);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是浮点vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是整数vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
case Instruction::kBitFtoI: { // 浮点位模式 -> 整数寄存器
|
||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::FMV_X_W);
|
||||
instr->addOperand(std::make_unique<RegOperand>(dest_vreg)); // 目标是整数vreg
|
||||
instr->addOperand(std::make_unique<RegOperand>(src_vreg)); // 源是浮点vreg
|
||||
CurMBB->addInstruction(std::move(instr));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unsupported float unary instruction in ISel");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DAGNode::CALL: {
|
||||
auto call = dynamic_cast<CallInst*>(node->value);
|
||||
// 处理函数参数,放入a0-a7物理寄存器
|
||||
@@ -870,7 +1104,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
||||
CurMBB->addInstruction(std::move(mv));
|
||||
}
|
||||
|
||||
// --- Step 2: [最终权威版] 遵循LLVM GEP语义迭代计算地址 ---
|
||||
// --- Step 2: 遵循LLVM GEP语义迭代计算地址 ---
|
||||
|
||||
// 初始被索引的类型,是基指针指向的那个类型 (例如, [2 x i32])
|
||||
Type* current_type = gep->getBasePointer()->getType()->as<PointerType>()->getBaseType();
|
||||
@@ -971,8 +1205,13 @@ RISCv64ISel::DAGNode* RISCv64ISel::get_operand_node(Value* val_ir, std::map<Valu
|
||||
// 规则1:如果这个Value已经有对应的节点,直接返回
|
||||
if (value_to_node.count(val_ir)) {
|
||||
return value_to_node[val_ir];
|
||||
} else if (dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else if (auto const_val = dynamic_cast<ConstantValue*>(val_ir)) {
|
||||
if (const_val->isInt()) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else {
|
||||
// 为浮点常量创建新的FP_CONSTANT节点
|
||||
return create_node(DAGNode::FP_CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
}
|
||||
} else if (dynamic_cast<GlobalValue*>(val_ir)) {
|
||||
return create_node(DAGNode::CONSTANT, val_ir, value_to_node, nodes_storage);
|
||||
} else if (dynamic_cast<AllocaInst*>(val_ir)) {
|
||||
@@ -1032,6 +1271,17 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
load_node->operands.push_back(get_operand_node(load->getPointer(), value_to_node, nodes_storage));
|
||||
} else if (auto bin = dynamic_cast<BinaryInst*>(inst)) {
|
||||
if(value_to_node.count(bin)) continue;
|
||||
if (bin->getKind() == Instruction::kFSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
// 使用isZero()来判断浮点数0.0,比直接比较更健壮
|
||||
if (const_lhs->isZero()) {
|
||||
// 这是一个浮点取负操作,创建 FUNARY 节点
|
||||
auto funary_node = create_node(DAGNode::FUNARY, bin, value_to_node, nodes_storage);
|
||||
funary_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
continue; // 处理完毕,跳到下一条指令
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bin->getKind() == BinaryInst::kSub) {
|
||||
if (auto const_lhs = dynamic_cast<ConstantValue*>(bin->getLhs())) {
|
||||
if (const_lhs->getInt() == 0) {
|
||||
@@ -1041,13 +1291,24 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
||||
}
|
||||
}
|
||||
}
|
||||
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
|
||||
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
if (bin->getKind() >= Instruction::kFAdd) { // 假设浮点指令枚举值更大
|
||||
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
|
||||
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
} else {
|
||||
auto bin_node = create_node(DAGNode::BINARY, bin, value_to_node, nodes_storage);
|
||||
bin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||
bin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto un = dynamic_cast<UnaryInst*>(inst)) {
|
||||
if(value_to_node.count(un)) continue;
|
||||
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
if (un->getKind() >= Instruction::kFNeg) {
|
||||
auto funary_node = create_node(DAGNode::FUNARY, un, value_to_node, nodes_storage);
|
||||
funary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
} else {
|
||||
auto unary_node = create_node(DAGNode::UNARY, un, value_to_node, nodes_storage);
|
||||
unary_node->operands.push_back(get_operand_node(un->getOperand(), value_to_node, nodes_storage));
|
||||
}
|
||||
} else if (auto call = dynamic_cast<CallInst*>(inst)) {
|
||||
if(value_to_node.count(call)) continue;
|
||||
auto call_node = create_node(DAGNode::CALL, call, value_to_node, nodes_storage);
|
||||
|
||||
Reference in New Issue
Block a user