JuliaHubOSS / llvm-cbe

resurrected LLVM "C Backend", with improvements
Other
811 stars 138 forks source link

Add support for the `freeze` instruction #175

Open dpaoliello opened 1 year ago

dpaoliello commented 1 year ago

Looking at LLVM IR for some Rust code, I noticed the freeze instruction that LLVM-CBE doesn't currently support: https://llvm.org/docs/LangRef.html#freeze-instruction

I've been thinking about how we should handle this, but have run into a few issues:

hikari-no-yume commented 1 year ago

Is it actually possible to express this in C at all? I think undefined behaviours in C are global.

dpaoliello commented 1 year ago

Is it actually possible to express this in C at all? I think undefined behaviours in C are global.

I'm not sure.

One option is to avoid undef and poison values altogether, for example we could always initialize variables, thus freeze becomes a no-op.

If I'm reading cppref correctly, there we may be able to safely access it via a char*.

From https://en.cppreference.com/w/c/language/initialization

objects with automatic storage duration are initialized to indeterminate values (which may be trap representations)

From https://en.cppreference.com/w/c/language/object

If an object representation does not represent any value of the object type, it is known as trap representation. Accessing a trap representation in any way other than reading it through an lvalue expression of character type is undefined behavior. The value of a structure or union is never a trap representation even if any particular member is one.

I do have a test for this now, unfortunately it doesn't seem like casting to char* helped...

// Compile with clang -S test.c -emit-llvm -O3
#include <string.h>
#include <stdio.h>

int main(int argc, char** argv) {
    int i;
    int j /* = freeze i */;
    // Insert "freeze" operation here...
    char* tmp = (char*)&i;
    memcpy(&j, tmp, sizeof(int));
    // If j is correctly frozen, then k and j must have the same value.
    int k = j;
    // If j isn't frozen, then printf is called with `i32 undef, i32 undef`
    printf("%d, %d", j, k);
    return 0;
}