#pragma once

#include "IR.h" // 假设IR.h包含了Module, Function, BasicBlock, Instruction, Value, IRBuilder, Type等定义
#include "IRBuilder.h" // 需要IRBuilder来创建新指令
#include "SysYIRPrinter.h" // 新增: 用于调试输出
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <list> // 用于迭代和修改指令列表
#include <algorithm> // for std::reverse (if needed, although not used in final version)
#include <iostream> // MODIFICATION: 用于警告输出

namespace sysy {

/**
 * @brief AddressCalculationExpansion Pass
 *
 * 这是一个IR优化Pass，用于将LoadInst和StoreInst中包含的多维数组索引
 * 显式地转换为IR中的BinaryInst（乘法和加法）序列，并生成带有线性偏移量的
 * LoadInst/StoreInst。
 *
 * 目的：确保在寄存器分配之前，所有中间地址计算的结果都有明确的IR指令和对应的虚拟寄存器，
 * 从而避免在后端DAG构建时临时创建值而导致寄存器分配缺失的问题。
 *
 * SysY语言特性：
 * - 无指针类型（所有数组访问的基地址是alloca或global的AllocaType/ArrayType）
 * - 数据类型只有int和float，且都占用4字节。
 * - LoadInst和StoreInst直接接受多个索引作为额外操作数。
 */
class AddressCalculationExpansion {
private:
    Module* pModule;
    IRBuilder* pBuilder; // 用于在IR中插入新指令

    // 数组元素的固定大小，根据SysY特性，int和float都是4字节
    static const int ELEMENT_SIZE = 4;

    // 辅助函数：根据数组的维度信息和当前索引的维度，计算该索引的步长（字节数）
    // dims: 包含所有维度大小的vector，例如 {2, 3, 4}
    // currentDimIndex: 当前正在处理的索引在 dims 中的位置 (0, 1, 2...)
    int calculateStride(const std::vector<int>& dims, size_t currentDimIndex) {
        int stride = ELEMENT_SIZE; // 最内层元素大小 (4字节)
        // 乘以当前维度之后的所有维度的大小
        for (size_t i = currentDimIndex + 1; i < dims.size(); ++i) {
            stride *= dims[i];
        }
        return stride;
    }

public:
    AddressCalculationExpansion(Module* module, IRBuilder* builder)
        : pModule(module), pBuilder(builder) {}

    // 运行此Pass
    bool run();
};

} // namespace sysy