From 6b6de49fcfc0f8deef9a0979354ceac4c082f2b5 Mon Sep 17 00:00:00 2001 From: cy <766079883@qq.com> Date: Thu, 7 May 2026 20:15:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(mir):=E4=BF=AE=E5=A4=8D=E6=B5=AE=E7=82=B9?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ir.txt | 272 +++++++++++++++++++++++++++++++++++++++++ src/irgen/IRGenExp.cpp | 64 +++++++++- src/mir/AsmPrinter.cpp | 151 ++++++++++++++--------- src/mir/Lowering.cpp | 201 +++++++++++++++++------------- src/sem/func.cpp | 59 ++++++++- 5 files changed, 600 insertions(+), 147 deletions(-) create mode 100644 ir.txt diff --git a/ir.txt b/ir.txt new file mode 100644 index 0000000..da044f3 --- /dev/null +++ b/ir.txt @@ -0,0 +1,272 @@ +@MAX = global i32 1000000000 +@TWO = global i32 2 +@THREE = global i32 3 +@FIVE = global i32 5 + +declare void @putch(i32) +declare void @memset(i32*, i32, i32) +declare i32 @getfarray(float*) +declare float @getfloat() +declare void @putfloat(float) +declare void @putint(i32) +declare void @putfarray(i32, float*) + +define float @float_abs(float %x) { +entry: + %0 = alloca float + store float %x, float* %0 + %2 = load float, float* %0 + %3 = sitofp i32 0 to float + %4 = fcmp olt float %2, %3 + br i1 %4, label %L0.if.then, label %L1.if.end +L0.if.then: + %6 = load float, float* %0 + %7 = fsub float 0x0, %6 + ret float %7 +L1.if.end: + %9 = load float, float* %0 + ret float %9 +} + +define float @circle_area(i32 %radius) { +entry: + %0 = alloca i32 + store i32 %radius, i32* %0 + %2 = load i32, i32* %0 + %3 = sitofp i32 %2 to float + %4 = fmul float 0x400921FB60000000, %3 + %5 = load i32, i32* %0 + %6 = sitofp i32 %5 to float + %7 = fmul float %4, %6 + %8 = load i32, i32* %0 + %9 = load i32, i32* %0 + %10 = mul i32 %8, %9 + %11 = sitofp i32 %10 to float + %12 = fmul float %11, 0x400921FB60000000 + %13 = fadd float %7, %12 + %14 = sitofp i32 2 to float + %15 = fdiv float %13, %14 + ret float %15 +} + +define i32 @float_eq(float %a, float %b) { +entry: + %0 = alloca float + %1 = alloca float + store float %a, float* %0 + store float %b, float* %1 + %4 = load float, float* %0 + %5 = load float, float* %1 + %6 = fsub float %4, %5 + %7 = call float @float_abs(float %6) + %8 = fcmp olt float %7, 0x3EB0C6F7A0000000 + br i1 %8, label %L2.if.then, label %L3.if.else +L2.if.then: + %10 = sitofp i32 1 to float + %11 = fmul float %10, 0x4000000000000000 + %12 = sitofp i32 2 to float + %13 = fdiv float %11, %12 + %14 = fptosi float %13 to i32 + ret i32 %14 +L3.if.else: + ret i32 0 +L4.if.end: + ret i32 0 +} + +define void @error() { +entry: + call void @putch(i32 101) + call void @putch(i32 114) + call void @putch(i32 114) + call void @putch(i32 111) + call void @putch(i32 114) + call void @putch(i32 10) + ret void +} + +define void @ok() { +entry: + call void @putch(i32 111) + call void @putch(i32 107) + call void @putch(i32 10) + ret void +} + +define void @assert(i32 %cond) { +entry: + %0 = alloca i32 + store i32 %cond, i32* %0 + %2 = load i32, i32* %0 + %3 = icmp eq i32 %2, 0 + %4 = zext i1 %3 to i32 + %5 = icmp ne i32 %4, 0 + br i1 %5, label %L5.if.then, label %L6.if.else +L5.if.then: + call void @error() + br label %L7.if.end +L6.if.else: + call void @ok() + br label %L7.if.end +L7.if.end: + ret void +} + +define void @assert_not(i32 %cond) { +entry: + %0 = alloca i32 + store i32 %cond, i32* %0 + %2 = load i32, i32* %0 + %3 = icmp ne i32 %2, 0 + br i1 %3, label %L8.if.then, label %L9.if.else +L8.if.then: + call void @error() + br label %L10.if.end +L9.if.else: + call void @ok() + br label %L10.if.end +L10.if.end: + ret void +} + +define i32 @main() { +entry: + %0 = alloca i32 + %1 = alloca i32 + %2 = alloca i32 + %3 = alloca i32 + %4 = alloca float, i32 10 + %5 = alloca i32 + %6 = alloca float + %7 = alloca float + %8 = alloca float + %9 = call i32 @float_eq(float 0x3FB4000000000000, float 0xC0E01D0000000000) + call void @assert_not(i32 %9) + %11 = call i32 @float_eq(float 0x4057C21FC0000000, float 0x4041475CE0000000) + call void @assert_not(i32 %11) + %13 = call i32 @float_eq(float 0x4041475CE0000000, float 0x4041475CE0000000) + call void @assert(i32 %13) + %15 = fptosi float 0x4016000000000000 to i32 + %16 = call float @circle_area(i32 %15) + %17 = load i32, i32* @FIVE + %18 = call float @circle_area(i32 %17) + %19 = call i32 @float_eq(float %16, float %18) + call void @assert(i32 %19) + %21 = call i32 @float_eq(float 0x406D200000000000, float 0x40AFFE0000000000) + call void @assert_not(i32 %21) + %23 = fcmp one float 0x3FF8000000000000, 0x0 + br i1 %23, label %L11.if.then, label %L12.if.end +L11.if.then: + call void @ok() + br label %L12.if.end +L12.if.end: + %27 = fcmp oeq float 0x400A666660000000, 0x0 + %28 = zext i1 %27 to i32 + %29 = icmp eq i32 %28, 0 + %30 = zext i1 %29 to i32 + %31 = icmp ne i32 %30, 0 + br i1 %31, label %L13.if.then, label %L14.if.end +L13.if.then: + call void @ok() + br label %L14.if.end +L14.if.end: + %35 = fcmp one float 0x0, 0x0 + %36 = zext i1 %35 to i32 + store i32 %36, i32* %0 + br i1 %35, label %L15.and.rhs, label %L16.and.end +L15.and.rhs: + %39 = icmp ne i32 3, 0 + %40 = zext i1 %39 to i32 + store i32 %40, i32* %0 + br label %L16.and.end +L16.and.end: + %43 = load i32, i32* %0 + %44 = icmp ne i32 %43, 0 + br i1 %44, label %L17.if.then, label %L18.if.end +L17.if.then: + call void @error() + br label %L18.if.end +L18.if.end: + %48 = icmp ne i32 0, 0 + %49 = zext i1 %48 to i32 + store i32 %49, i32* %1 + br i1 %48, label %L20.or.end, label %L19.or.rhs +L19.or.rhs: + %52 = fcmp one float 0x3FD3333340000000, 0x0 + %53 = zext i1 %52 to i32 + store i32 %53, i32* %1 + br label %L20.or.end +L20.or.end: + %56 = load i32, i32* %1 + %57 = icmp ne i32 %56, 0 + br i1 %57, label %L21.if.then, label %L22.if.end +L21.if.then: + call void @ok() + br label %L22.if.end +L22.if.end: + store i32 1, i32* %2 + store i32 0, i32* %3 + call void @memset(float* %4, i32 0, i32 40) + %64 = getelementptr float, float* %4, i32 0 + store float 0x3FF0000000000000, float* %64 + %66 = getelementptr float, float* %4, i32 1 + store i32 2, float* %66 + %68 = getelementptr float, float* %4, i32 0 + %69 = call i32 @getfarray(float* %68) + store i32 %69, i32* %5 + br label %L23.while.cond +L23.while.cond: + %72 = load i32, i32* %2 + %73 = load i32, i32* @MAX + %74 = icmp slt i32 %72, %73 + br i1 %74, label %L24.while.body, label %L25.while.end +L24.while.body: + %76 = call float @getfloat() + store float %76, float* %6 + %78 = load float, float* %6 + %79 = fmul float 0x400921FB60000000, %78 + %80 = load float, float* %6 + %81 = fmul float %79, %80 + store float %81, float* %7 + %83 = load float, float* %6 + %84 = fptosi float %83 to i32 + %85 = call float @circle_area(i32 %84) + store float %85, float* %8 + %87 = load i32, i32* %3 + %88 = getelementptr float, float* %4, i32 %87 + %89 = load float, float* %88 + %90 = load float, float* %6 + %91 = fadd float %89, %90 + %92 = load i32, i32* %3 + %93 = getelementptr float, float* %4, i32 %92 + store float %91, float* %93 + %95 = load float, float* %7 + call void @putfloat(float %95) + call void @putch(i32 32) + %98 = load float, float* %8 + %99 = fptosi float %98 to i32 + call void @putint(i32 %99) + call void @putch(i32 10) + %102 = load i32, i32* %2 + %103 = fsub float 0x0, 0x4024000000000000 + %104 = fsub float 0x0, %103 + %105 = sitofp i32 %102 to float + %106 = fmul float %105, %104 + %107 = fptosi float %106 to i32 + store i32 %107, i32* %2 + %109 = load i32, i32* %3 + %110 = add i32 %109, 1 + store i32 %110, i32* %3 + br label %L23.while.cond +L25.while.end: + %113 = load i32, i32* %5 + %114 = getelementptr float, float* %4, i32 0 + call void @putfarray(i32 %113, float* %114) + %116 = srem i32 0, 256 + %117 = add i32 %116, 256 + %118 = srem i32 %117, 256 + call void @putint(i32 %118) + call void @putch(i32 10) + ret i32 0 +} + diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index 224e606..d1b88bb 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -7,9 +7,57 @@ #include "ir/IR.h" #include "sem/func.h" #include "utils/Log.h" - +#include // 用于 ldexp // ─── 辅助 ───────────────────────────────────────────────────────────────────── + +// 静态辅助函数:解析十六进制浮点字面量 +static float ParseHexFloat(const std::string& str) { + const char* s = str.c_str(); + // 跳过 "0x" 或 "0X" + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2; + + double significand = 0.0; + bool have_dot = false; + double dot_scale = 1.0 / 16.0; + + while (*s && *s != 'p' && *s != 'P') { + if (*s == '.') { + have_dot = true; + ++s; + continue; + } + int digit = -1; + if (*s >= '0' && *s <= '9') digit = *s - '0'; + else if (*s >= 'a' && *s <= 'f') digit = *s - 'a' + 10; + else if (*s >= 'A' && *s <= 'F') digit = *s - 'A' + 10; + if (digit >= 0) { + if (have_dot) { + significand += digit * dot_scale; + dot_scale /= 16.0; + } else { + significand = significand * 16 + digit; + } + } + ++s; + } + + int exponent = 0; + if (*s == 'p' || *s == 'P') { + ++s; + int sign = 1; + if (*s == '-') { sign = -1; ++s; } + else if (*s == '+') { ++s; } + exponent = 0; + while (*s >= '0' && *s <= '9') { + exponent = exponent * 10 + (*s - '0'); + ++s; + } + exponent *= sign; + } + + return static_cast(ldexp(significand, exponent)); +} // 把 i32/float 值转成 i1 ir::Value* IRGenImpl::ToI1(ir::Value* v) { if (!v) throw std::runtime_error(FormatError("irgen", "ToI1: null value")); @@ -571,11 +619,15 @@ std::any IRGenImpl::visitNumber(SysYParser::NumberContext* ctx) { if (ctx->FloatConst()) { std::string text = ctx->FloatConst()->getText(); float val = 0.0f; - try { - val = std::stof(text); - } catch (...) { - throw std::runtime_error( - FormatError("irgen", "浮点字面量解析失败: " + text)); + if (text.size() >= 2 && (text[1] == 'x' || text[1] == 'X')) { + val = ParseHexFloat(text); + } else { + try { + val = std::stof(text); + } catch (...) { + throw std::runtime_error( + FormatError("irgen", "浮点字面量解析失败: " + text)); + } } return static_cast(builder_.CreateConstFloat(val)); } diff --git a/src/mir/AsmPrinter.cpp b/src/mir/AsmPrinter.cpp index 5944a24..f92471e 100644 --- a/src/mir/AsmPrinter.cpp +++ b/src/mir/AsmPrinter.cpp @@ -158,11 +158,11 @@ void PrintAsmFunction(const MachineFunction& function, std::ostream& os) { case Opcode::Load: { if (ops.size() == 2 && ops[1].GetKind() == Operand::Kind::Reg) { os << " ld " << PhysRegName(ops[0].GetReg()) << ", 0(" << PhysRegName(ops[1].GetReg()) << ")\n"; - } else if (ops.size() == 2 && ops[1].GetKind() == Operand::Kind::Imm) { + } /*else if (ops.size() == 2 && ops[1].GetKind() == Operand::Kind::Imm) { // 用于调用者 outgoing 存储的占位偏移(将在 Outgoing 中修正) int offset = ops[1].GetImm(); // 实际偏移 = local_vars + 16 + offset - os << " ld " << PhysRegName(ops[0].GetReg()) << ", " << offset << "(sp)\n"; - } else { + os << " ld " << PhysRegName(ops[0].GetReg()) << ", " << offset << "(sp)\n";*/ + else { int frame_idx = ops[1].GetFrameIndex(); const auto& slot = function.GetFrameSlot(frame_idx); if (slot.size == 8) EmitStackLoad64(os, ops[0].GetReg(), slot.offset); @@ -174,16 +174,15 @@ void PrintAsmFunction(const MachineFunction& function, std::ostream& os) { case Opcode::Store: { if (ops.size() == 2 && ops[1].GetKind() == Operand::Kind::Reg) { os << " sd " << PhysRegName(ops[0].GetReg()) << ", 0(" << PhysRegName(ops[1].GetReg()) << ")\n"; - } else if (ops.size() == 2 && ops[1].GetKind() == Operand::Kind::Imm) { - // outgoing 存储:偏移 = local_vars + 16 + ops[1].GetImm() + } /*else if (ops.size() == 2 && ops[1].GetKind() == Operand::Kind::Imm) { int offset = ops[1].GetImm(); // 实际偏移需在 AsmPrinter 中加上 local_vars+16,这里简单先直接用 offset(动态修正稍复杂) // 临时方案:直接生成 sw t0, offset(sp),但 offset 应为 local_vars+16=? // 由于 AsmPrinter 中可访问 function.GetLocalVarsSize(),我们计算: int actual_offset = function.GetLocalVarsSize() + 16 + offset; if (actual_offset <= 2047) os << " sd " << PhysRegName(ops[0].GetReg()) << ", " << actual_offset << "(sp)\n"; - else { /* 扩展大偏移 */ } - } else { + else { }*/ + else { int frame_idx = ops[1].GetFrameIndex(); const auto& slot = function.GetFrameSlot(frame_idx); if (slot.size == 8) EmitStackStore64(os, ops[0].GetReg(), slot.offset); @@ -201,7 +200,7 @@ void PrintAsmFunction(const MachineFunction& function, std::ostream& os) { int caller_offset = total_frame + argv_index * 8; // 加载到 T0 if (caller_offset <= 2047) { - os << " ld " << PhysRegName(ops[0].GetReg()) << ", " << caller_offset << "(sp)\n"; + os << " ld " << PhysRegName(ops[0].GetReg()) << ", " << caller_offset << "(s0)\n"; } else { os << " li t4, " << caller_offset << "\n"; os << " add t4, s0, t4\n"; @@ -216,6 +215,24 @@ void PrintAsmFunction(const MachineFunction& function, std::ostream& os) { } break; } + + case Opcode::LoadCallerStackArgFloat: { + int argv_index = ops.at(2).GetImm(); + int dst_slot = ops.at(1).GetFrameIndex(); + int total_frame = function.GetFrameSize(); + int caller_offset = total_frame + argv_index * 8; + // 使用 s0 保证稳定 + if (caller_offset <= 2047) { + os << " flw " << PhysRegName(ops.at(0).GetReg()) << ", " << caller_offset << "(s0)\n"; + } else { + os << " li t4, " << caller_offset << "\n"; + os << " add t4, s0, t4\n"; + os << " flw " << PhysRegName(ops.at(0).GetReg()) << ", 0(t4)\n"; + } + const auto& slot = function.GetFrameSlot(dst_slot); + EmitStackStoreFloat(os, ops.at(0).GetReg(), slot.offset); + break; + } case Opcode::Add: os << " add " << PhysRegName(ops.at(0).GetReg()) << ", " @@ -476,7 +493,7 @@ void PrintAsmFunction(const MachineFunction& function, std::ostream& os) { case Opcode::FPToSI: os << " fcvt.w.s " << PhysRegName(ops[0].GetReg()) << ", " - << PhysRegName(ops[1].GetReg()) << "\n"; + << PhysRegName(ops[1].GetReg()) << ", rtz\n"; break; case Opcode::LoadFloat: @@ -515,73 +532,97 @@ void PrintAsmFunction(const MachineFunction& function, std::ostream& os) { // 输出多个函数的汇编 void PrintAsm(const std::vector>& functions, std::ostream& os) { // ========== 输出全局变量 ========== - - // 输出 .data 段(已初始化的全局变量) + + // .data 段:非常量变量 bool hasData = false; for (const auto& gv : g_globalVars) { - if (!gv.isConst) { - if (!hasData) { - os << ".data\n"; - hasData = true; - } - os << " .global " << gv.name << "\n"; - os << " .type " << gv.name << ", @object\n"; - - if (gv.isArray && gv.arraySize > 1) { - int totalSize = gv.arraySize * 4; - os << " .size " << gv.name << ", " << totalSize << "\n"; - os << gv.name << ":\n"; - - if (!gv.arrayValues.empty()) { - for (int val : gv.arrayValues) { - os << " .word " << val << "\n"; + if (gv.isConst) continue; // 常量到 .rodata + if (!hasData) { + os << ".data\n"; + hasData = true; + } + os << " .global " << gv.name << "\n"; + os << " .type " << gv.name << ", @object\n"; + + if (gv.isArray && gv.arraySize > 1) { + int totalSize = gv.arraySize * 4; + os << " .size " << gv.name << ", " << totalSize << "\n"; + os << gv.name << ":\n"; + if (gv.isFloat) { + if (!gv.arrayValuesF.empty()) { + for (float val : gv.arrayValuesF) { + union { float f; uint32_t i; } u; + u.f = val; + os << " .word " << u.i << "\n"; } } else { - for (int i = 0; i < gv.arraySize; i++) { - os << " .word 0\n"; - } + for (int i = 0; i < gv.arraySize; i++) os << " .word 0\n"; + } + } else { + if (!gv.arrayValues.empty()) { + for (int val : gv.arrayValues) os << " .word " << val << "\n"; + } else { + for (int i = 0; i < gv.arraySize; i++) os << " .word 0\n"; } + } + } else { + os << " .size " << gv.name << ", 4\n"; + os << gv.name << ":\n"; + if (gv.isFloat) { + union { float f; uint32_t i; } u; + u.f = gv.valueF; + os << " .word " << u.i << "\n"; } else { - os << " .size " << gv.name << ", 4\n"; - os << gv.name << ":\n"; os << " .word " << gv.value << "\n"; } } } - // 输出 .rodata 段(只读常量) + // .rodata 段:只读常量 bool hasRodata = false; for (const auto& gv : g_globalVars) { - if (gv.isConst) { - if (!hasRodata) { - os << ".section .rodata\n"; - hasRodata = true; - } - os << " .global " << gv.name << "\n"; - os << " .type " << gv.name << ", @object\n"; - - if (gv.isArray && gv.arraySize > 1) { - int totalSize = gv.arraySize * 4; - os << " .size " << gv.name << ", " << totalSize << "\n"; - os << gv.name << ":\n"; - - if (!gv.arrayValues.empty()) { - for (int val : gv.arrayValues) { - os << " .word " << val << "\n"; + if (!gv.isConst) continue; + if (!hasRodata) { + os << ".section .rodata\n"; + hasRodata = true; + } + os << " .global " << gv.name << "\n"; + os << " .type " << gv.name << ", @object\n"; + + if (gv.isArray && gv.arraySize > 1) { + int totalSize = gv.arraySize * 4; + os << " .size " << gv.name << ", " << totalSize << "\n"; + os << gv.name << ":\n"; + if (gv.isFloat) { + if (!gv.arrayValuesF.empty()) { + for (float val : gv.arrayValuesF) { + union { float f; uint32_t i; } u; + u.f = val; + os << " .word " << u.i << "\n"; } } else { - for (int i = 0; i < gv.arraySize; i++) { - os << " .word 0\n"; - } + for (int i = 0; i < gv.arraySize; i++) os << " .word 0\n"; } } else { - os << " .size " << gv.name << ", 4\n"; - os << gv.name << ":\n"; + if (!gv.arrayValues.empty()) { + for (int val : gv.arrayValues) os << " .word " << val << "\n"; + } else { + for (int i = 0; i < gv.arraySize; i++) os << " .word 0\n"; + } + } + } else { + os << " .size " << gv.name << ", 4\n"; + os << gv.name << ":\n"; + if (gv.isFloat) { + union { float f; uint32_t i; } u; + u.f = gv.valueF; + os << " .word " << u.i << "\n"; + } else { os << " .word " << gv.value << "\n"; } } } - + // ========== 输出代码段 ========== os << ".text\n"; diff --git a/src/mir/Lowering.cpp b/src/mir/Lowering.cpp index 10429f7..0ed57e2 100644 --- a/src/mir/Lowering.cpp +++ b/src/mir/Lowering.cpp @@ -27,6 +27,7 @@ static bool IsFloatReg(PhysReg reg) { using ValueSlotMap = std::unordered_map; static std::unordered_map block_map; + MachineBasicBlock* GetOrCreateBlock(const ir::BasicBlock* ir_block, MachineFunction& function) { auto it = block_map.find(ir_block); @@ -45,14 +46,20 @@ MachineBasicBlock* GetOrCreateBlock(const ir::BasicBlock* ir_block, void EmitValueToReg(const ir::Value* value, PhysReg target, const ValueSlotMap& slots, MachineBasicBlock& block, - bool for_address = false) { + MachineFunction& function, bool for_address = false){ // 处理参数(Argument) if (auto* arg = dynamic_cast(value)) { auto it = slots.find(arg); if (it != slots.end()) { bool src_is_float = value->GetType()->IsFloat32(); bool dst_is_float = IsFloatReg(target); - if (src_is_float && !dst_is_float) { + if (src_is_float == dst_is_float) { + // 同类型 → 直接加载,不转换 + if (src_is_float) + block.Append(Opcode::LoadFloat, {Operand::Reg(target), Operand::FrameIndex(it->second)}); + else + block.Append(Opcode::Load, {Operand::Reg(target), Operand::FrameIndex(it->second)}); + } else if (src_is_float && !dst_is_float) { // 浮点 -> 整数 block.Append(Opcode::LoadFloat, {Operand::Reg(PhysReg::FT0), Operand::FrameIndex(it->second)}); @@ -62,16 +69,7 @@ void EmitValueToReg(const ir::Value* value, PhysReg target, block.Append(Opcode::Load, {Operand::Reg(PhysReg::T0), Operand::FrameIndex(it->second)}); block.Append(Opcode::SIToFP, {Operand::Reg(target), Operand::Reg(PhysReg::T0)}); - } else { - // 同类型直接加载 - if (src_is_float) { - block.Append(Opcode::LoadFloat, - {Operand::Reg(target), Operand::FrameIndex(it->second)}); - } else { - block.Append(Opcode::Load, - {Operand::Reg(target), Operand::FrameIndex(it->second)}); - } - } + } return; } } @@ -84,27 +82,32 @@ void EmitValueToReg(const ir::Value* value, PhysReg target, return; } - // 处理浮点常量 + // 处理浮点常量 if (auto* fconstant = dynamic_cast(value)) { - float val = fconstant->GetValue(); + // 直接使用标准的 double -> float 转换,无需特殊分支 + float fval = static_cast(fconstant->GetValue()); uint32_t bits; - memcpy(&bits, &val, sizeof(val)); - bool target_is_fp = IsFloatReg(target); - if (target_is_fp) { - block.Append(Opcode::MovImm, - {Operand::Reg(PhysReg::T0), Operand::Imm(static_cast(bits))}); - block.Append(Opcode::FMovWX, {Operand::Reg(target), Operand::Reg(PhysReg::T0)}); + std::memcpy(&bits, &fval, sizeof(fval)); + int32_t imm = static_cast(bits); + + if (IsFloatReg(target)) { + // 通过栈槽加载以保证浮点寄存器符合 NaN‑boxing 要求 + int tmp_slot = function.CreateFrameIndex(4); + block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::T4), Operand::Imm(imm)}); + block.Append(Opcode::Store, {Operand::Reg(PhysReg::T4), + Operand::FrameIndex(tmp_slot)}); + block.Append(Opcode::LoadFloat, {Operand::Reg(target), + Operand::FrameIndex(tmp_slot)}); } else { - block.Append(Opcode::MovImm, - {Operand::Reg(target), Operand::Imm(static_cast(bits))}); + block.Append(Opcode::MovImm, {Operand::Reg(target), Operand::Imm(imm)}); } return; } // 处理 GEP 指令 if (auto* gep = dynamic_cast(value)) { - EmitValueToReg(gep->GetBasePtr(), target, slots, block, true); - EmitValueToReg(gep->GetIndex(), PhysReg::T1, slots, block); + EmitValueToReg(gep->GetBasePtr(), target, slots, block,function, true); + EmitValueToReg(gep->GetIndex(), PhysReg::T1, slots, block,function); block.Append(Opcode::Slli, {Operand::Reg(PhysReg::T1), Operand::Reg(PhysReg::T1), Operand::Imm(2)}); @@ -140,7 +143,7 @@ void EmitValueToReg(const ir::Value* value, PhysReg target, return; } - // 处理一般栈槽中的值 + // 处理一般栈槽中的值 auto it = slots.find(value); if (it != slots.end()) { bool src_is_float = value->GetType()->IsFloat32(); @@ -203,25 +206,25 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct case ir::Opcode::Store: { auto& store = static_cast(inst); // 如果指针是 GEP,手动生成地址并 store,避免额外计算 - if (auto* gep = dynamic_cast(store.GetPtr())) { + if (auto* gep = dynamic_cast(store.GetPtr())) { // 判断值的类型是否为浮点 bool val_is_float = store.GetValue()->GetType()->IsFloat32(); if (val_is_float) { // 将浮点值加载到 FT0 - EmitValueToReg(store.GetValue(), PhysReg::FT0, slots, block); + EmitValueToReg(store.GetValue(), PhysReg::FT0, slots, block, function); } else { // 整数值加载到 T2 - EmitValueToReg(store.GetValue(), PhysReg::T2, slots, block); + EmitValueToReg(store.GetValue(), PhysReg::T2, slots, block, function); } // 计算基址 + 索引*4 - EmitValueToReg(gep->GetBasePtr(), PhysReg::T0, slots, block, true); + EmitValueToReg(gep->GetBasePtr(), PhysReg::T0, slots, block, function, true); auto idx_it = slots.find(gep->GetIndex()); if (idx_it != slots.end()) { block.Append(Opcode::Load, {Operand::Reg(PhysReg::T1), Operand::FrameIndex(idx_it->second)}); } else { - EmitValueToReg(gep->GetIndex(), PhysReg::T1, slots, block); + EmitValueToReg(gep->GetIndex(), PhysReg::T1, slots, block, function); } block.Append(Opcode::Slli, {Operand::Reg(PhysReg::T1), Operand::Reg(PhysReg::T1), Operand::Imm(2)}); block.Append(Opcode::Add, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T1)}); @@ -235,15 +238,21 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct return; } if (auto* global = dynamic_cast(store.GetPtr())) { - EmitValueToReg(store.GetValue(), PhysReg::T0, slots, block); + EmitValueToReg(store.GetValue(), PhysReg::T0, slots, block, function); std::string global_name = global->GetName(); block.Append(Opcode::StoreGlobal, {Operand::Reg(PhysReg::T0), Operand::Global(global_name)}); return; } auto dst = slots.find(store.GetPtr()); if (dst != slots.end()) { - EmitValueToReg(store.GetValue(), PhysReg::T0, slots, block); - StoreRegToSlot(PhysReg::T0, dst->second, block); + bool val_is_float = store.GetValue()->GetType()->IsFloat32(); + if (val_is_float) { + EmitValueToReg(store.GetValue(), PhysReg::FT0, slots, block, function); + StoreRegToSlot(PhysReg::FT0, dst->second, block, true); + } else { + EmitValueToReg(store.GetValue(), PhysReg::T0, slots, block, function); + StoreRegToSlot(PhysReg::T0, dst->second, block, false); + } return; } throw std::runtime_error(FormatError("mir", "Store: 无法处理的指针类型")); @@ -253,13 +262,13 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto& load = static_cast(inst); if (auto* gep = dynamic_cast(load.GetPtr())) { // 计算地址到 T0 - EmitValueToReg(gep->GetBasePtr(), PhysReg::T0, slots, block, true); + EmitValueToReg(gep->GetBasePtr(), PhysReg::T0, slots, block, function, true); auto idx_it = slots.find(gep->GetIndex()); if (idx_it != slots.end()) { block.Append(Opcode::Load, {Operand::Reg(PhysReg::T1), Operand::FrameIndex(idx_it->second)}); } else { - EmitValueToReg(gep->GetIndex(), PhysReg::T1, slots, block); + EmitValueToReg(gep->GetIndex(), PhysReg::T1, slots, block, function); } block.Append(Opcode::Slli, {Operand::Reg(PhysReg::T1), Operand::Reg(PhysReg::T1), Operand::Imm(2)}); block.Append(Opcode::Add, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T1)}); @@ -280,7 +289,7 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct return; } if (dynamic_cast(load.GetPtr())) { - EmitValueToReg(load.GetPtr(), PhysReg::T0, slots, block, true); + EmitValueToReg(load.GetPtr(), PhysReg::T0, slots, block, function, true); block.Append(Opcode::LoadIndirect, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T0)}); int dst_slot = function.CreateFrameIndex(4); @@ -344,8 +353,8 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct int dst_slot = function.CreateFrameIndex(4); if (result_is_float) { - EmitValueToReg(bin.GetLhs(), PhysReg::FT0, slots, block); - EmitValueToReg(bin.GetRhs(), PhysReg::FT1, slots, block); + EmitValueToReg(bin.GetLhs(), PhysReg::FT0, slots, block, function); + EmitValueToReg(bin.GetRhs(), PhysReg::FT1, slots, block, function); Opcode op; switch (inst.GetOpcode()) { @@ -360,8 +369,8 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct Operand::Reg(PhysReg::FT1)}); StoreRegToSlot(PhysReg::FT0, dst_slot, block, true); } else { - EmitValueToReg(bin.GetLhs(), PhysReg::T0, slots, block); - EmitValueToReg(bin.GetRhs(), PhysReg::T1, slots, block); + EmitValueToReg(bin.GetLhs(), PhysReg::T0, slots, block, function); + EmitValueToReg(bin.GetRhs(), PhysReg::T1, slots, block, function); Opcode op; switch (inst.GetOpcode()) { @@ -414,23 +423,22 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct bool arg_is_float = call.GetArg(i)->GetType()->IsFloat32(); if (arg_is_float) { PhysReg freg = static_cast(static_cast(PhysReg::FA0) + i); - EmitValueToReg(call.GetArg(i), freg, slots, block); + EmitValueToReg(call.GetArg(i), freg, slots, block, function); } else { PhysReg ireg = static_cast(static_cast(PhysReg::A0) + i); - EmitValueToReg(call.GetArg(i), ireg, slots, block); + EmitValueToReg(call.GetArg(i), ireg, slots, block, function); } } // 栈参数:存入 sp + offset 处 for (int i = regArgs; i < numArgs; i++) { - EmitValueToReg(call.GetArg(i), PhysReg::T0, slots, block); + bool arg_is_float = call.GetArg(i)->GetType()->IsFloat32(); int offset = (i - regArgs) * 8; - // 计算 sp+offset 到 t4 + // 计算栈地址到 t4(sp + offset) if (offset == 0) { - block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::T4), Operand::Imm(0)}); // t4=0 block.Append(Opcode::Add, {Operand::Reg(PhysReg::T4), - Operand::Reg(PhysReg::SP), - Operand::Reg(PhysReg::T4)}); + Operand::Reg(PhysReg::SP), + Operand::Reg(PhysReg::ZERO)}); } else if (offset <= 2047) { block.Append(Opcode::Addi, {Operand::Reg(PhysReg::T4), Operand::Reg(PhysReg::SP), @@ -438,11 +446,21 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct } else { block.Append(Opcode::MovImm, {Operand::Reg(PhysReg::T4), Operand::Imm(offset)}); block.Append(Opcode::Add, {Operand::Reg(PhysReg::T4), - Operand::Reg(PhysReg::SP), - Operand::Reg(PhysReg::T4)}); + Operand::Reg(PhysReg::SP), + Operand::Reg(PhysReg::T4)}); + } + + if (arg_is_float) { + // 浮点参数存入栈:使用现有的 StoreFloat 指令(会生成 fsw) + EmitValueToReg(call.GetArg(i), PhysReg::FT0, slots, block, function); + block.Append(Opcode::StoreFloat, + {Operand::Reg(PhysReg::FT0), Operand::Reg(PhysReg::T4)}); + } else { + // 整数/指针参数存入栈:使用现有的 Store 指令(会生成 sd) + EmitValueToReg(call.GetArg(i), PhysReg::T0, slots, block, function); + block.Append(Opcode::Store, + {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T4)}); } - // Store T0 -> [t4] - block.Append(Opcode::Store, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::T4)}); } std::string func_name = call.GetCalleeName(); @@ -481,8 +499,8 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto& icmp = static_cast(inst); int dst_slot = function.CreateFrameIndex(); - EmitValueToReg(icmp.GetLhs(), PhysReg::T0, slots, block); - EmitValueToReg(icmp.GetRhs(), PhysReg::T1, slots, block); + EmitValueToReg(icmp.GetLhs(), PhysReg::T0, slots, block, function); + EmitValueToReg(icmp.GetRhs(), PhysReg::T1, slots, block, function); ir::ICmpPredicate pred = icmp.GetPredicate(); @@ -547,7 +565,7 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto& zext = static_cast(inst); int dst_slot = function.CreateFrameIndex(4); - EmitValueToReg(zext.GetSrc(), PhysReg::T0, slots, block); + EmitValueToReg(zext.GetSrc(), PhysReg::T0, slots, block, function); StoreRegToSlot(PhysReg::T0, dst_slot, block); slots.emplace(&inst, dst_slot); return; @@ -557,36 +575,51 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto& fcmp = static_cast(inst); int dst_slot = function.CreateFrameIndex(4); - EmitValueToReg(fcmp.GetLhs(), PhysReg::FT0, slots, block); - EmitValueToReg(fcmp.GetRhs(), PhysReg::FT1, slots, block); + EmitValueToReg(fcmp.GetLhs(), PhysReg::FT0, slots, block, function); + EmitValueToReg(fcmp.GetRhs(), PhysReg::FT1, slots, block, function); ir::FCmpPredicate pred = fcmp.GetPredicate(); switch (pred) { case ir::FCmpPredicate::OEQ: - block.Append(Opcode::FEq, {Operand::Reg(PhysReg::FT0), + block.Append(Opcode::FEq, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::FT0), Operand::Reg(PhysReg::FT1)}); break; + case ir::FCmpPredicate::ONE: + block.Append(Opcode::FEq, {Operand::Reg(PhysReg::T0), + Operand::Reg(PhysReg::FT0), + Operand::Reg(PhysReg::FT1)}); + block.Append(Opcode::Xori, {Operand::Reg(PhysReg::T0), + Operand::Reg(PhysReg::T0), + Operand::Imm(1)}); + break; case ir::FCmpPredicate::OLT: - block.Append(Opcode::FLt, {Operand::Reg(PhysReg::FT0), + block.Append(Opcode::FLt, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::FT0), Operand::Reg(PhysReg::FT1)}); break; + case ir::FCmpPredicate::OGT: + block.Append(Opcode::FLt, {Operand::Reg(PhysReg::T0), + Operand::Reg(PhysReg::FT1), + Operand::Reg(PhysReg::FT0)}); + break; case ir::FCmpPredicate::OLE: - block.Append(Opcode::FLe, {Operand::Reg(PhysReg::FT0), + block.Append(Opcode::FLe, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::FT0), Operand::Reg(PhysReg::FT1)}); break; + case ir::FCmpPredicate::OGE: + block.Append(Opcode::FLe, {Operand::Reg(PhysReg::T0), + Operand::Reg(PhysReg::FT1), + Operand::Reg(PhysReg::FT0)}); + break; default: - block.Append(Opcode::FEq, {Operand::Reg(PhysReg::FT0), + block.Append(Opcode::FEq, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::FT0), Operand::Reg(PhysReg::FT1)}); break; } - - block.Append(Opcode::FMov, {Operand::Reg(PhysReg::T0), - Operand::Reg(PhysReg::FT0)}); StoreRegToSlot(PhysReg::T0, dst_slot, block); slots.emplace(&inst, dst_slot); return; @@ -596,13 +629,8 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto& conv = static_cast(inst); int dst_slot = function.CreateFrameIndex(4); - auto src_it = slots.find(conv.GetSrc()); - if (src_it == slots.end()) { - throw std::runtime_error(FormatError("mir", "SIToFP: 找不到源操作数的栈槽")); - } - - block.Append(Opcode::Load, - {Operand::Reg(PhysReg::T0), Operand::FrameIndex(src_it->second)}); + // 直接加载源操作数到 T0,不依赖 slots 中是否存在 + EmitValueToReg(conv.GetSrc(), PhysReg::T0, slots, block, function); block.Append(Opcode::SIToFP, {Operand::Reg(PhysReg::FT0), Operand::Reg(PhysReg::T0)}); StoreRegToSlot(PhysReg::FT0, dst_slot, block, true); @@ -614,13 +642,8 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto& conv = static_cast(inst); int dst_slot = function.CreateFrameIndex(4); - auto src_it = slots.find(conv.GetSrc()); - if (src_it == slots.end()) { - throw std::runtime_error(FormatError("mir", "FPToSI: 找不到源操作数的栈槽")); - } - - block.Append(Opcode::LoadFloat, - {Operand::Reg(PhysReg::FT0), Operand::FrameIndex(src_it->second)}); + // 直接加载源操作数到 FT0,不依赖 slots + EmitValueToReg(conv.GetSrc(), PhysReg::FT0, slots, block, function); block.Append(Opcode::FPToSI, {Operand::Reg(PhysReg::T0), Operand::Reg(PhysReg::FT0)}); StoreRegToSlot(PhysReg::T0, dst_slot, block, false); @@ -641,7 +664,7 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct auto* true_bb = condbr.GetTrueBB(); auto* false_bb = condbr.GetFalseBB(); - EmitValueToReg(condbr.GetCond(), PhysReg::T0, slots, block); + EmitValueToReg(condbr.GetCond(), PhysReg::T0, slots, block, function); MachineBasicBlock* true_block = GetOrCreateBlock(true_bb, function); MachineBasicBlock* false_block = GetOrCreateBlock(false_bb, function); @@ -656,9 +679,9 @@ void LowerInstructionToBlock(const ir::Instruction& inst, MachineFunction& funct if (ret.GetValue()) { auto val = ret.GetValue(); if (val->GetType()->IsFloat32()) { - EmitValueToReg(val, PhysReg::FA0, slots, block); + EmitValueToReg(val, PhysReg::FA0, slots, block, function); } else { - EmitValueToReg(val, PhysReg::A0, slots, block); + EmitValueToReg(val, PhysReg::A0, slots, block, function); } } else { block.Append(Opcode::MovImm, @@ -703,11 +726,19 @@ std::unique_ptr LowerFunctionToMIR(const ir::Function& func) { } else { // 栈参数:从调用者的动态栈帧加载到本地栈槽 // 使用 LoadCallerStackArg 特殊指令,参数索引 = i - 8 - entry->Append(Opcode::LoadCallerStackArg, { - Operand::Reg(PhysReg::T0), // 临时寄存器 - Operand::FrameIndex(slot), // 目标本地栈槽 - Operand::Imm(static_cast(i - 8)) // 栈参数索引 - }); + if (arg->GetType()->IsFloat32()) { + entry->Append(Opcode::LoadCallerStackArgFloat, { + Operand::Reg(PhysReg::FT0), // 临时浮点寄存器 + Operand::FrameIndex(slot), // 目标本地栈槽 + Operand::Imm(static_cast(i - 8)) // 栈参数索引 + }); + } else { + entry->Append(Opcode::LoadCallerStackArg, { + Operand::Reg(PhysReg::T0), + Operand::FrameIndex(slot), + Operand::Imm(static_cast(i - 8)) + }); + } } slots[arg] = slot; diff --git a/src/sem/func.cpp b/src/sem/func.cpp index 3053065..f9c12c3 100644 --- a/src/sem/func.cpp +++ b/src/sem/func.cpp @@ -5,6 +5,58 @@ #include #include "utils/Log.h" +#include // 提供 ldexp + +namespace { + +// 解析十六进制浮点字面量,支持 0xH.Hp±E 格式 +double ParseHexFloat(const std::string& str) { + const char* s = str.c_str(); + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2; + + double significand = 0.0; + bool have_dot = false; + double dot_scale = 1.0 / 16.0; + + while (*s && *s != 'p' && *s != 'P') { + if (*s == '.') { + have_dot = true; + ++s; + continue; + } + int digit = -1; + if (*s >= '0' && *s <= '9') digit = *s - '0'; + else if (*s >= 'a' && *s <= 'f') digit = *s - 'a' + 10; + else if (*s >= 'A' && *s <= 'F') digit = *s - 'A' + 10; + if (digit >= 0) { + if (have_dot) { + significand += digit * dot_scale; + dot_scale /= 16.0; + } else { + significand = significand * 16 + digit; + } + } + ++s; + } + + int exponent = 0; + if (*s == 'p' || *s == 'P') { + ++s; + int sign = 1; + if (*s == '-') { sign = -1; ++s; } + else if (*s == '+') { ++s; } + exponent = 0; + while (*s >= '0' && *s <= '9') { + exponent = exponent * 10 + (*s - '0'); + ++s; + } + exponent *= sign; + } + + return ldexp(significand, exponent); +} + +} // anonymous namespace namespace sem { @@ -156,7 +208,12 @@ ConstValue EvaluatePrimaryExp(SysYParser::PrimaryExpContext& ctx) { val.float_val = static_cast(val.int_val); } else if (float_const) { val.is_int = false; - val.float_val = ToFloat32(std::stod(float_const->getText())); + std::string text = float_const->getText(); + if (text.size() >= 2 && (text[1] == 'x' || text[1] == 'X')) { + val.float_val = ToFloat32(ParseHexFloat(text)); + } else { + val.float_val = ToFloat32(std::stod(text)); + } val.int_val = static_cast(val.float_val); } else { throw std::runtime_error(FormatError("sema", "非法数字字面量"));