Simon Camphausen e47b507562
[mlir][EmitC] Model lvalues as a type in EmitC (#91475)
This adds an `emitc.lvalue` type which models assignable lvlaues in the
type system. Operations modifying memory are restricted to this type
accordingly.

See also the discussion on
[discourse](https://discourse.llvm.org/t/rfc-separate-variables-from-ssa-values-in-emitc/75224/9).
The most notable changes are as follows.

- `emitc.variable` and `emitc.global` ops are restricted to return
`emitc.array` or `emitc.lvalue` types
- Taking the address of a value is restricted to operands with lvalue
type
- Conversion from lvalues into SSA values is done with the new
`emitc.load` op
- The var operand of the `emitc.assign` op is restricted to lvalue type 
- The result of the `emitc.subscript` and `emitc.get_global` ops is a
lvalue type
- The operands and results of the `emitc.member` and
`emitc.member_of_ptr` ops are restricted to lvalue types

---------

Co-authored-by: Matthias Gehre <matthias.gehre@amd.com>
2024-08-20 11:52:16 +02:00

46 lines
2.1 KiB
MLIR

// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT
// RUN: mlir-translate -mlir-to-cpp -declare-variables-at-top %s | FileCheck %s -check-prefix=CPP-DECLTOP
func.func @emitc_variable() {
%c0 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue<i32>
%c1 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue<i32>
%c2 = "emitc.variable"(){value = -1 : i32} : () -> !emitc.lvalue<i32>
%c3 = "emitc.variable"(){value = -1 : si8} : () -> !emitc.lvalue<si8>
%c4 = "emitc.variable"(){value = 255 : ui8} : () -> !emitc.lvalue<ui8>
%c5 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.lvalue<!emitc.ptr<i32>>
%c6 = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.lvalue<!emitc.ptr<i32>>
%c7 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<3x7xi32>
%c8 = "emitc.variable"(){value = #emitc.opaque<"">} : () -> !emitc.array<5x!emitc.ptr<i8>>
return
}
// CPP-DEFAULT: void emitc_variable() {
// CPP-DEFAULT-NEXT: int32_t [[V0:[^ ]*]];
// CPP-DEFAULT-NEXT: int32_t [[V1:[^ ]*]] = 42;
// CPP-DEFAULT-NEXT: int32_t [[V2:[^ ]*]] = -1;
// CPP-DEFAULT-NEXT: int8_t [[V3:[^ ]*]] = -1;
// CPP-DEFAULT-NEXT: uint8_t [[V4:[^ ]*]] = 255;
// CPP-DEFAULT-NEXT: int32_t* [[V5:[^ ]*]];
// CPP-DEFAULT-NEXT: int32_t* [[V6:[^ ]*]] = NULL;
// CPP-DEFAULT-NEXT: int32_t [[V7:[^ ]*]][3][7];
// CPP-DEFAULT-NEXT: int8_t* [[V8:[^ ]*]][5];
// CPP-DECLTOP: void emitc_variable() {
// CPP-DECLTOP-NEXT: int32_t [[V0:[^ ]*]];
// CPP-DECLTOP-NEXT: int32_t [[V1:[^ ]*]];
// CPP-DECLTOP-NEXT: int32_t [[V2:[^ ]*]];
// CPP-DECLTOP-NEXT: int8_t [[V3:[^ ]*]];
// CPP-DECLTOP-NEXT: uint8_t [[V4:[^ ]*]];
// CPP-DECLTOP-NEXT: int32_t* [[V5:[^ ]*]];
// CPP-DECLTOP-NEXT: int32_t* [[V6:[^ ]*]];
// CPP-DECLTOP-NEXT: int32_t [[V7:[^ ]*]][3][7];
// CPP-DECLTOP-NEXT: int8_t* [[V8:[^ ]*]][5];
// CPP-DECLTOP-NEXT: ;
// CPP-DECLTOP-NEXT: [[V1]] = 42;
// CPP-DECLTOP-NEXT: [[V2]] = -1;
// CPP-DECLTOP-NEXT: [[V3]] = -1;
// CPP-DECLTOP-NEXT: [[V4]] = 255;
// CPP-DECLTOP-NEXT: ;
// CPP-DECLTOP-NEXT: [[V6]] = NULL;
// CPP-DECLTOP-NEXT: ;
// CPP-DECLTOP-NEXT: ;