riscv-non-isa / riscv-asm-manual

RISC-V Assembly Programmer's Manual
https://jira.riscv.org/browse/RVG-4
Creative Commons Attribution 4.0 International
1.41k stars 235 forks source link

Compile-time rounding-mode specification in [inline] assembly #88

Closed mysoreanoop closed 10 months ago

mysoreanoop commented 1 year ago

Providing a rounding mode alongside a floating point instruction seems to work for me when used in an inline assembly. For example: fadd.s ft0, ft0, ft0, rtz (reference: https://github.com/riscv/riscv-isa-manual/issues/230) It generates the same assembly code.

However, if I instead want to pass the rounding mode as an argument to inline assembly like so:

asm volatile (
                      "fcvt.s.w fa5, %[a];"  // convert int a to float in register fa5
                      "fcvt.s.w fa6, %[b];"
                      "fmul.s fa7, fa5, fa6, %[frm];"
                      "fcvt.w.s %[rf], fa7"
                      : [rf] "=r" (rf)
                      : [a]  "rm" (f[i]) ,
                        [b]  "rm" (f[j]) ,
                        [frm] "s" ("rtz")  // note the "s" constraint
);

There's an error: Error: illegal operands fmul.s fa7,fa5,fa6,.LC4 (also tried "X", "S" instead of "s"; reference: https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html)

Is there a way to send in rounding mode as an argument in inline assembly?

cmuellner commented 10 months ago

Sorry for the late response here.

Inline assembly is provided by the compiler. At least in case of GCC, the rounding modes are not explicitly set there (with only few exceptions). Therefore, there is no way to change the rounding mode of the instruction that the compiler will emit.

If you know the rounding mode at compile time (like in your example), then there is no need to pass it as constraint. Just put it into the asm string: asm volatile ("fadd %0, %1, %2, rup" : "=f" (result) : "f" (f1) , "f" (f2));.

If you need a more dynamic approach (where constraints won't help you anyway), you can put if/else-statement (or a switch-statement) around that:

typedef enum {
    rne,
    rtz,
} rm_t;

float foo1(float f1, float f2, rm_t rm)
{
    float result;
    if (rm == rne) {
        asm volatile (
            "fadd %0, %1, %2, rne"
            : "=f" (result)
            : "f" (f1) , "f" (f2));
    } else if (rm == rtz) {
                asm volatile (
            "fadd %0, %1, %2, rtz"
            : "=f" (result)
            : "f" (f1) , "f" (f2));
    }
    return result;
}

However, you can set the rounding mode as part of the inline assembly string and